diff --git a/.env b/.env deleted file mode 100644 index 153edd43b..000000000 --- a/.env +++ /dev/null @@ -1,4 +0,0 @@ -TOKEN_1=ExampleToken1 -TOKEN_2=ExampleToken2 -TOKEN_3=ExampleToken3 -TOKEN_4=ExampleToken4 diff --git a/.glitch-assets b/.glitch-assets new file mode 100644 index 000000000..04e75a069 --- /dev/null +++ b/.glitch-assets @@ -0,0 +1,275 @@ +{"name":"2023_10_10_0rf_Kleki.png","date":"2023-10-10T18:58:08.611Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2023_10_10_0rf_Kleki.png","type":"image/png","size":30464,"imageWidth":256,"imageHeight":256,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2023_10_10_0rf_Kleki.png","thumbnailWidth":256,"thumbnailHeight":256,"uuid":"UP44Oex8WvGywkCD"} +{"name":"6avWH55.jpg","date":"2023-10-25T12:45:16.390Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/6avWH55.jpg","type":"image/jpeg","size":327303,"imageWidth":2500,"imageHeight":1667,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2F6avWH55.jpg","thumbnailWidth":330,"thumbnailHeight":221,"uuid":"o6pEXEUSnOPqm4bg"} +{"name":"4073e372df1399336a01c51052a1bbd8.jpg","date":"2023-10-25T13:01:09.623Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/4073e372df1399336a01c51052a1bbd8.jpg","type":"image/jpeg","size":48408,"imageWidth":960,"imageHeight":649,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2F4073e372df1399336a01c51052a1bbd8.jpg","thumbnailWidth":330,"thumbnailHeight":224,"uuid":"w9ZO2wxV83aWhelI"} +{"name":"58563194-553c-49ae-95db-441b06bf9bef.image.png","date":"2023-10-25T13:19:20.463Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/58563194-553c-49ae-95db-441b06bf9bef.image.png","type":"image/png","size":76850,"imageWidth":360,"imageHeight":240,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2F58563194-553c-49ae-95db-441b06bf9bef.image.png","thumbnailWidth":330,"thumbnailHeight":220,"uuid":"RsOUyfm1cBYSqbw0"} +{"uuid":"o6pEXEUSnOPqm4bg","deleted":true} +{"name":"girb.jpg","date":"2023-10-25T12:45:16.390Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/girb.jpg","type":"image/jpeg","size":327303,"imageWidth":2500,"imageHeight":1667,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2F6avWH55.jpg","thumbnailWidth":330,"thumbnailHeight":221,"uuid":"o6pEXEUSnOPqm4bg"} +{"uuid":"w9ZO2wxV83aWhelI","deleted":true} +{"name":"othergirb.jpg","date":"2023-10-25T13:01:09.623Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/othergirb.jpg","type":"image/jpeg","size":48408,"imageWidth":960,"imageHeight":649,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2F4073e372df1399336a01c51052a1bbd8.jpg","thumbnailWidth":330,"thumbnailHeight":224,"uuid":"w9ZO2wxV83aWhelI"} +{"name":"131107152744-mona-lisa.jpg","date":"2023-10-26T11:10:16.817Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/131107152744-mona-lisa.jpg","type":"image/jpeg","size":747095,"imageWidth":2000,"imageHeight":3000,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2F131107152744-mona-lisa.jpg","thumbnailWidth":220,"thumbnailHeight":330,"uuid":"YM7ULs8ieFPfkHTh"} +{"name":"2022_06_23_11e_Kleki.png","date":"2023-10-26T11:10:22.958Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2022_06_23_11e_Kleki.png","type":"image/png","size":66360,"imageWidth":1009,"imageHeight":601,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2F2022_06_23_11e_Kleki.png","thumbnailWidth":330,"thumbnailHeight":197,"uuid":"CKrqEXVr9r1fWHQ6"} +{"name":"84812d435b246f4edffe887c5f755008.jpg","date":"2023-10-26T11:10:27.584Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/84812d435b246f4edffe887c5f755008.jpg","type":"image/jpeg","size":111067,"imageWidth":924,"imageHeight":1000,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2F84812d435b246f4edffe887c5f755008.jpg","thumbnailWidth":305,"thumbnailHeight":330,"uuid":"iKniUyyIl8sambKK"} +{"name":"videoplayback.mp4","date":"2023-10-26T11:10:49.863Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/videoplayback.mp4","type":"video/mp4","size":2106277,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fvideoplayback.mp4","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"txSk7RsRJ33ZgL0R"} +{"name":"IMG_0316.webp","date":"2023-10-26T11:20:34.628Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/IMG_0316.webp","type":"image/webp","size":12986,"imageWidth":640,"imageHeight":494,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FIMG_0316.webp","thumbnailWidth":330,"thumbnailHeight":255,"uuid":"ULDBE338jPz5CztZ"} +{"name":"devil vortex.jpg","date":"2023-10-26T11:23:31.448Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/devil%20vortex.jpg","type":"image/jpeg","size":70977,"imageWidth":2048,"imageHeight":1070,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fdevil%20vortex.jpg","thumbnailWidth":330,"thumbnailHeight":173,"uuid":"rwxaYBQQ3Vdh4GOB"} +{"uuid":"CKrqEXVr9r1fWHQ6","deleted":true} +{"name":"lratio","date":"2023-10-26T11:10:22.958Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/lratio","type":"image/png","size":66360,"imageWidth":1009,"imageHeight":601,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2F2022_06_23_11e_Kleki.png","thumbnailWidth":330,"thumbnailHeight":197,"uuid":"CKrqEXVr9r1fWHQ6"} +{"name":"mqdefault.jpg","date":"2023-10-26T15:51:05.241Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/mqdefault.jpg","type":"image/jpeg","size":8165,"imageWidth":320,"imageHeight":180,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/mqdefault.jpg","thumbnailWidth":320,"thumbnailHeight":180,"uuid":"vUoqYUUmAaCJlbFE"} +{"name":"e4b3f8d2-72dd-4995-87ad-633e8c5e5754.image.png","date":"2023-10-26T15:52:48.829Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/e4b3f8d2-72dd-4995-87ad-633e8c5e5754.image.png","type":"image/png","size":667529,"imageWidth":970,"imageHeight":750,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fe4b3f8d2-72dd-4995-87ad-633e8c5e5754.image.png","thumbnailWidth":330,"thumbnailHeight":256,"uuid":"2TdCgTp1qJy5VpQF"} +{"name":"4703606e-9aeb-4893-aad3-b9788cccfc9b.image.png","date":"2023-10-26T15:56:52.346Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/4703606e-9aeb-4893-aad3-b9788cccfc9b.image.png","type":"image/png","size":13711,"imageWidth":295,"imageHeight":247,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/4703606e-9aeb-4893-aad3-b9788cccfc9b.image.png","thumbnailWidth":295,"thumbnailHeight":247,"uuid":"vB57dbf5e3LDGNTc"} +{"name":"9fbac25f-6710-4a95-b963-502275ff8728.image.png","date":"2023-10-26T16:03:48.998Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/9fbac25f-6710-4a95-b963-502275ff8728.image.png","type":"image/png","size":5638,"imageWidth":218,"imageHeight":157,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/9fbac25f-6710-4a95-b963-502275ff8728.image.png","thumbnailWidth":218,"thumbnailHeight":157,"uuid":"AUYt8QpAyhIjzDDo"} +{"uuid":"AUYt8QpAyhIjzDDo","deleted":true} +{"name":"2023_10_26_0ml_Kleki.png","date":"2023-10-26T16:04:27.088Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2023_10_26_0ml_Kleki.png","type":"image/png","size":6063,"imageWidth":218,"imageHeight":157,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2023_10_26_0ml_Kleki.png","thumbnailWidth":218,"thumbnailHeight":157,"uuid":"XrOWUvHhmVrkljWG"} +{"name":"b6b06d98-c722-433b-b100-0fb0d0d0915c.image.png","date":"2023-10-26T16:06:40.232Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/b6b06d98-c722-433b-b100-0fb0d0d0915c.image.png","type":"image/png","size":155677,"imageWidth":480,"imageHeight":480,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fb6b06d98-c722-433b-b100-0fb0d0d0915c.image.png","thumbnailWidth":330,"thumbnailHeight":330,"uuid":"ctTmChYwrALlsYSY"} +{"name":"asda.gif","date":"2023-10-26T16:07:13.205Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/asda.gif","type":"image/gif","size":2414319,"imageWidth":1160,"imageHeight":653,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fasda.gif","thumbnailWidth":330,"thumbnailHeight":186,"uuid":"DrNyvjoahVRfPqfc"} +{"name":"freddy.gif","date":"2023-10-26T16:07:33.397Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/freddy.gif","type":"image/gif","size":3807320,"imageWidth":480,"imageHeight":480,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Ffreddy.gif","thumbnailWidth":330,"thumbnailHeight":330,"uuid":"JZgBnLYoTvZmoiEm"} +{"name":"poop-emoji.jpg","date":"2023-11-27T16:55:26.682Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/poop-emoji.jpg","type":"image/jpeg","size":277135,"imageWidth":1200,"imageHeight":1200,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fpoop-emoji.jpg","thumbnailWidth":330,"thumbnailHeight":330,"uuid":"Cb4D9nc5184NLZWn"} +{"name":"Screen_Shot_2021-06-25_at_8.06.28_PM_1400x.webp","date":"2023-11-27T16:55:33.660Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Screen_Shot_2021-06-25_at_8.06.28_PM_1400x.webp","type":"image/webp","size":34994,"imageWidth":1400,"imageHeight":788,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FScreen_Shot_2021-06-25_at_8.06.28_PM_1400x.webp","thumbnailWidth":330,"thumbnailHeight":186,"uuid":"ZVERuCeCDI11tY8f"} +{"name":"videoplayback (5).mp4","date":"2023-11-30T20:09:06.159Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/videoplayback%20(5).mp4","type":"video/mp4","size":5225498,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fvideoplayback%20(5).mp4","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"x22blklePMGQRwIA"} +{"name":"afg-spaghetti-alla-assassina-1-19ef-superJumbo.jpg","date":"2023-12-01T17:04:48.242Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/afg-spaghetti-alla-assassina-1-19ef-superJumbo.jpg","type":"image/jpeg","size":673888,"imageWidth":2048,"imageHeight":1365,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fafg-spaghetti-alla-assassina-1-19ef-superJumbo.jpg","thumbnailWidth":330,"thumbnailHeight":220,"uuid":"DjbeeYPv58kWZxGT"} +{"name":"Papyrus.webp","date":"2023-12-01T17:04:54.185Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Papyrus.webp","type":"image/webp","size":22528,"imageWidth":400,"imageHeight":400,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FPapyrus.webp","thumbnailWidth":330,"thumbnailHeight":330,"uuid":"1oCUTGTCUHSm6Rht"} +{"name":"videoplayback (6).mp4","date":"2023-12-04T12:01:19.895Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/videoplayback%20(6).mp4","type":"video/mp4","size":107238,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fvideoplayback%20(6).mp4","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"sKgj926hemecxf1z"} +{"name":"nerd-emoji.gif","date":"2023-12-04T12:10:45.734Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/nerd-emoji.gif","type":"image/gif","size":58415,"imageWidth":200,"imageHeight":200,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/nerd-emoji.gif","thumbnailWidth":200,"thumbnailHeight":200,"uuid":"IEWg3jT2scnmIEBa"} +{"name":"IMG_20231204_144411762_LAYER.jpg","date":"2023-12-04T18:20:34.323Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/IMG_20231204_144411762_LAYER.jpg","type":"image/jpeg","size":4291465,"imageWidth":3072,"imageHeight":4096,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FIMG_20231204_144411762_LAYER.jpg","thumbnailWidth":248,"thumbnailHeight":330,"uuid":"kHofB34sB8zK8ghc"} +{"name":"IMG_20231204_144409218_LAYER.jpg","date":"2023-12-04T18:20:37.274Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/IMG_20231204_144409218_LAYER.jpg","type":"image/jpeg","size":4649997,"imageWidth":3072,"imageHeight":4096,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FIMG_20231204_144409218_LAYER.jpg","thumbnailWidth":248,"thumbnailHeight":330,"uuid":"wy3sATUDmtO4UKav"} +{"name":"IMG_20231204_144406913_LAYER.jpg","date":"2023-12-04T18:20:40.278Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/IMG_20231204_144406913_LAYER.jpg","type":"image/jpeg","size":4663414,"imageWidth":3072,"imageHeight":4096,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FIMG_20231204_144406913_LAYER.jpg","thumbnailWidth":248,"thumbnailHeight":330,"uuid":"VVnb7tpycOZ96wIM"} +{"name":"IMG_20231204_144358408_LAYER.jpg","date":"2023-12-04T18:20:43.765Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/IMG_20231204_144358408_LAYER.jpg","type":"image/jpeg","size":4910430,"imageWidth":3072,"imageHeight":4096,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FIMG_20231204_144358408_LAYER.jpg","thumbnailWidth":248,"thumbnailHeight":330,"uuid":"298PzLlhaFIqxxcq"} +{"name":"2023_12_05_0sn_Kleki.png","date":"2023-12-05T20:41:21.532Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2023_12_05_0sn_Kleki.png","type":"image/png","size":9872,"imageWidth":91,"imageHeight":93,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2023_12_05_0sn_Kleki.png","thumbnailWidth":91,"thumbnailHeight":93,"uuid":"lzgyLwxKAAQT4aRa"} +{"name":"2023_12_06_0yp_Kleki.png","date":"2023-12-07T00:24:27.560Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2023_12_06_0yp_Kleki.png","type":"image/png","size":70691,"imageWidth":296,"imageHeight":296,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2023_12_06_0yp_Kleki.png","thumbnailWidth":296,"thumbnailHeight":296,"uuid":"lq8MCR84TekmbueY"} +{"name":"2023_12_06_0yt_Kleki.png","date":"2023-12-07T00:24:47.196Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2023_12_06_0yt_Kleki.png","type":"image/png","size":81775,"imageWidth":296,"imageHeight":296,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2023_12_06_0yt_Kleki.png","thumbnailWidth":296,"thumbnailHeight":296,"uuid":"ggXSa8BNzRjqSBnD"} +{"name":"2023_12_06_0yl_Kleki.png","date":"2023-12-07T00:25:10.293Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2023_12_06_0yl_Kleki.png","type":"image/png","size":84439,"imageWidth":296,"imageHeight":296,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2023_12_06_0yl_Kleki.png","thumbnailWidth":296,"thumbnailHeight":296,"uuid":"YAFhahkJBvHvomAo"} +{"name":"2023_12_06_0yi_Kleki.png","date":"2023-12-07T00:30:14.507Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2023_12_06_0yi_Kleki.png","type":"image/png","size":87010,"imageWidth":296,"imageHeight":296,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2023_12_06_0yi_Kleki.png","thumbnailWidth":296,"thumbnailHeight":296,"uuid":"dvm2XAnEJNmrlaoJ"} +{"name":"2023_12_06_0yh_Kleki.png","date":"2023-12-07T00:30:19.835Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2023_12_06_0yh_Kleki.png","type":"image/png","size":87060,"imageWidth":296,"imageHeight":296,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2023_12_06_0yh_Kleki.png","thumbnailWidth":296,"thumbnailHeight":296,"uuid":"RakITIBsTZAoxn6J"} +{"name":"2023_12_06_0yb_Kleki.png","date":"2023-12-07T00:30:29.284Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2023_12_06_0yb_Kleki.png","type":"image/png","size":75357,"imageWidth":296,"imageHeight":296,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2023_12_06_0yb_Kleki.png","thumbnailWidth":296,"thumbnailHeight":296,"uuid":"EvxT6uRiwx18Z2e8"} +{"name":"2023_12_06_0za_Kleki.png","date":"2023-12-07T00:49:05.704Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2023_12_06_0za_Kleki.png","type":"image/png","size":72696,"imageWidth":296,"imageHeight":296,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2023_12_06_0za_Kleki.png","thumbnailWidth":296,"thumbnailHeight":296,"uuid":"aoroY4SW6zapPfOE"} +{"name":"2023_12_08_0g8_Kleki.png","date":"2023-12-08T13:15:13.341Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2023_12_08_0g8_Kleki.png","type":"image/png","size":142882,"imageWidth":1117,"imageHeight":607,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2F2023_12_08_0g8_Kleki.png","thumbnailWidth":330,"thumbnailHeight":180,"uuid":"iRH2k0fN1Gx4DUk1"} +{"name":"MOSHED-2023-11-2-9-15-39.gif","date":"2023-12-12T12:59:58.261Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/MOSHED-2023-11-2-9-15-39.gif","type":"image/gif","size":9742202,"imageWidth":640,"imageHeight":400,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FMOSHED-2023-11-2-9-15-39.gif","thumbnailWidth":330,"thumbnailHeight":207,"uuid":"52P1expoZSM3Z2bZ"} +{"name":"MOSHED-2023-11-2-9-16-18.jpg","date":"2023-12-12T13:00:04.817Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/MOSHED-2023-11-2-9-16-18.jpg","type":"image/jpeg","size":122406,"imageWidth":1568,"imageHeight":980,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FMOSHED-2023-11-2-9-16-18.jpg","thumbnailWidth":330,"thumbnailHeight":207,"uuid":"VyBWbHyBZeQDkCqK"} +{"name":"MOSHED-2023-11-2-9-16-30.jpg","date":"2023-12-12T13:00:12.253Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/MOSHED-2023-11-2-9-16-30.jpg","type":"image/jpeg","size":194318,"imageWidth":1568,"imageHeight":980,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FMOSHED-2023-11-2-9-16-30.jpg","thumbnailWidth":330,"thumbnailHeight":207,"uuid":"ccSREI092qAxPu6K"} +{"name":"MOSHED-2023-11-2-9-17-44.gif","date":"2023-12-12T13:00:21.674Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/MOSHED-2023-11-2-9-17-44.gif","type":"image/gif","size":8254208,"imageWidth":640,"imageHeight":400,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FMOSHED-2023-11-2-9-17-44.gif","thumbnailWidth":330,"thumbnailHeight":207,"uuid":"vThvLihG3U4Tva8u"} +{"name":"MOSHED-2023-11-2-9-18-42.gif","date":"2023-12-12T13:00:29.800Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/MOSHED-2023-11-2-9-18-42.gif","type":"image/gif","size":22820370,"imageWidth":640,"imageHeight":400,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FMOSHED-2023-11-2-9-18-42.gif","thumbnailWidth":330,"thumbnailHeight":207,"uuid":"Aei1r7CUxV9JTPGZ"} +{"name":"MOSHED-2023-11-2-9-19-19.jpg","date":"2023-12-12T13:00:34.450Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/MOSHED-2023-11-2-9-19-19.jpg","type":"image/jpeg","size":102760,"imageWidth":1568,"imageHeight":980,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FMOSHED-2023-11-2-9-19-19.jpg","thumbnailWidth":330,"thumbnailHeight":207,"uuid":"lp7GBZ7NYag3ZEM5"} +{"name":"MOSHED-2023-11-2-9-22-40.gif","date":"2023-12-12T13:00:45.756Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/MOSHED-2023-11-2-9-22-40.gif","type":"image/gif","size":13789663,"imageWidth":640,"imageHeight":400,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FMOSHED-2023-11-2-9-22-40.gif","thumbnailWidth":330,"thumbnailHeight":207,"uuid":"b3XRVsDg7Qv5QFYZ"} +{"name":"MOSHED-2023-11-2-9-24-47.gif","date":"2023-12-12T13:00:51.248Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/MOSHED-2023-11-2-9-24-47.gif","type":"image/gif","size":6092682,"imageWidth":640,"imageHeight":400,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FMOSHED-2023-11-2-9-24-47.gif","thumbnailWidth":330,"thumbnailHeight":207,"uuid":"9TjxQT7jJYwEwQZb"} +{"uuid":"Aei1r7CUxV9JTPGZ","deleted":true} +{"name":"MOSHED-2023-11-2-9-18-42.gif","date":"2023-12-12T13:07:15.262Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/MOSHED-2023-11-2-9-18-42.gif","type":"image/gif","size":22820370,"imageWidth":640,"imageHeight":400,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FMOSHED-2023-11-2-9-18-42.gif","thumbnailWidth":330,"thumbnailHeight":207,"uuid":"mFh1JnSydzXR12gh"} +{"uuid":"mFh1JnSydzXR12gh","deleted":true} +{"name":"MOSHED-2023-12-12-10-47-6.gif","date":"2023-12-12T14:17:22.498Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/MOSHED-2023-12-12-10-47-6.gif","type":"image/gif","size":11089695,"imageWidth":640,"imageHeight":400,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FMOSHED-2023-12-12-10-47-6.gif","thumbnailWidth":330,"thumbnailHeight":207,"uuid":"kEzXuIpHEELcAuHJ"} +{"name":"MOSHED-2023-12-12-10-46-41.gif","date":"2023-12-12T14:17:26.360Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/MOSHED-2023-12-12-10-46-41.gif","type":"image/gif","size":12491342,"imageWidth":640,"imageHeight":400,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FMOSHED-2023-12-12-10-46-41.gif","thumbnailWidth":330,"thumbnailHeight":207,"uuid":"MjoGdc3z87JYHYl4"} +{"name":"MOSHED-2023-12-12-10-42-0.gif","date":"2023-12-12T14:17:29.599Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/MOSHED-2023-12-12-10-42-0.gif","type":"image/gif","size":8559279,"imageWidth":640,"imageHeight":400,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FMOSHED-2023-12-12-10-42-0.gif","thumbnailWidth":330,"thumbnailHeight":207,"uuid":"orEDVirkk7HGAjwX"} +{"name":"MOSHED-2023-12-12-10-39-41.gif","date":"2023-12-12T14:17:33.878Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/MOSHED-2023-12-12-10-39-41.gif","type":"image/gif","size":6042203,"imageWidth":640,"imageHeight":400,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FMOSHED-2023-12-12-10-39-41.gif","thumbnailWidth":330,"thumbnailHeight":207,"uuid":"soSGGxLRe87PpUyB"} +{"name":"MOSHED-2023-12-12-10-37-55.gif","date":"2023-12-12T14:17:36.549Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/MOSHED-2023-12-12-10-37-55.gif","type":"image/gif","size":1825419,"imageWidth":640,"imageHeight":400,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FMOSHED-2023-12-12-10-37-55.gif","thumbnailWidth":330,"thumbnailHeight":207,"uuid":"suIcEXpXCuqgBnhb"} +{"uuid":"suIcEXpXCuqgBnhb","deleted":true} +{"uuid":"soSGGxLRe87PpUyB","deleted":true} +{"uuid":"orEDVirkk7HGAjwX","deleted":true} +{"uuid":"MjoGdc3z87JYHYl4","deleted":true} +{"uuid":"kEzXuIpHEELcAuHJ","deleted":true} +{"uuid":"9TjxQT7jJYwEwQZb","deleted":true} +{"uuid":"b3XRVsDg7Qv5QFYZ","deleted":true} +{"uuid":"lp7GBZ7NYag3ZEM5","deleted":true} +{"uuid":"vThvLihG3U4Tva8u","deleted":true} +{"uuid":"ccSREI092qAxPu6K","deleted":true} +{"uuid":"VyBWbHyBZeQDkCqK","deleted":true} +{"uuid":"52P1expoZSM3Z2bZ","deleted":true} +{"name":"fb286e65-331c-42ff-b226-ac5bfc7418b7.image.png","date":"2024-01-14T21:10:07.867Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/fb286e65-331c-42ff-b226-ac5bfc7418b7.image.png","type":"image/png","size":2376,"imageWidth":96,"imageHeight":96,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/fb286e65-331c-42ff-b226-ac5bfc7418b7.image.png","thumbnailWidth":96,"thumbnailHeight":96,"uuid":"uuaOAwjEVYE8UjTl"} +{"name":"oioioi.mp3","date":"2024-01-15T02:47:10.033Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/oioioi.mp3","type":"audio/mpeg","size":7221396,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Foioioi.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"TLbSQQprOSopfHoY"} +{"name":"Depredation.mp3","date":"2024-01-15T02:47:46.890Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Depredation.mp3","type":"audio/mpeg","size":8288129,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FDepredation.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"XfFWeHV5t1gcuE4J"} +{"name":"World's End.wav","date":"2024-01-15T02:48:09.038Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/World's%20End.wav","type":"audio/wav","size":33800236,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FWorld's%20End.wav","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"nFvYO1N5f6xH8PgY"} +{"name":"4Miklipi (Dejected) Preview.mp3","date":"2024-01-15T02:50:22.417Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/4Miklipi%20(Dejected)%20Preview.mp3","type":"audio/mpeg","size":4125377,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2F4Miklipi%20(Dejected)%20Preview.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"b0959XaAUwrm5DBm"} +{"name":"nero shitpost.png","date":"2024-01-15T03:46:10.363Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/nero%20shitpost.png","type":"image/png","size":192370,"imageWidth":500,"imageHeight":400,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fnero%20shitpost.png","thumbnailWidth":330,"thumbnailHeight":264,"uuid":"27bMMsSzzePzc4gx"} +{"name":"6fcc71bf-255f-4d26-b13e-e3f9f68fb77a.image.png","date":"2024-01-15T04:04:38.159Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/6fcc71bf-255f-4d26-b13e-e3f9f68fb77a.image.png","type":"image/png","size":151618,"imageWidth":498,"imageHeight":498,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2F6fcc71bf-255f-4d26-b13e-e3f9f68fb77a.image.png","thumbnailWidth":330,"thumbnailHeight":330,"uuid":"BS5SvNlFUKcj0C0u"} +{"name":"look_closely.mp3","date":"2024-01-15T04:09:46.778Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/look_closely.mp3","type":"audio/mpeg","size":20922,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Flook_closely.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"VlbLJHd2YrAkE8oQ"} +{"name":"e304fc26-480b-47b5-8270-949f7df44d92.image.png","date":"2024-01-15T04:58:22.951Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/e304fc26-480b-47b5-8270-949f7df44d92.image.png","type":"image/png","size":85814,"imageWidth":298,"imageHeight":397,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fe304fc26-480b-47b5-8270-949f7df44d92.image.png","thumbnailWidth":248,"thumbnailHeight":330,"uuid":"JndrzAvoYpyDCqAG"} +{"name":"toilet_flush.mp3","date":"2024-01-15T05:28:22.578Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/toilet_flush.mp3","type":"audio/mpeg","size":94293,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Ftoilet_flush.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"8EtOGgdbXaVQRsG2"} +{"name":"y2mate_HOnnyD0.mp3","date":"2024-01-15T05:28:25.126Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/y2mate_HOnnyD0.mp3","type":"audio/mpeg","size":50684,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fy2mate_HOnnyD0.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"gZIE2RUndOaeOkpY"} +{"name":"flowing-water-sound-effect.mp3","date":"2024-01-15T06:24:21.150Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/flowing-water-sound-effect.mp3","type":"audio/mpeg","size":164603,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fflowing-water-sound-effect.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"lFzb954crqkjqSxU"} +{"name":"pew_pew-dknight556-1379997159.mp3","date":"2024-01-15T06:26:15.747Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/pew_pew-dknight556-1379997159.mp3","type":"audio/mpeg","size":7551,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fpew_pew-dknight556-1379997159.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"wbsUbQ176JelACja"} +{"name":"2024_01_15_05q_Kleki.png","date":"2024-01-15T06:57:08.958Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2024_01_15_05q_Kleki.png","type":"image/png","size":20218,"imageWidth":612,"imageHeight":612,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2F2024_01_15_05q_Kleki.png","thumbnailWidth":330,"thumbnailHeight":330,"uuid":"FSqPDlLinpE8Loxx"} +{"name":"chipi-chipi-chapa-chapa.mp3","date":"2024-01-15T07:13:52.837Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/chipi-chipi-chapa-chapa.mp3","type":"audio/mpeg","size":192826,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fchipi-chipi-chapa-chapa.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"yz3SmgjTHe6LnBrF"} +{"name":"neko-arc.mp3","date":"2024-01-15T07:13:55.953Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/neko-arc.mp3","type":"audio/mpeg","size":17901,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fneko-arc.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"u3PHWM6bxDbQa4Z4"} +{"name":"bwomp.mp3","date":"2024-01-15T07:13:59.344Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/bwomp.mp3","type":"audio/mpeg","size":6765,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fbwomp.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"ORPQeX8y3fWoNeC1"} +{"name":"nfl.mp3","date":"2024-01-15T07:14:03.389Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/nfl.mp3","type":"audio/mpeg","size":300347,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fnfl.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"ll5dGpaMX1dkzUAc"} +{"name":"Gear-icon-transparent-background.png","date":"2024-01-18T11:59:38.381Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Gear-icon-transparent-background.png","type":"image/png","size":14537,"imageWidth":512,"imageHeight":512,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FGear-icon-transparent-background.png","thumbnailWidth":330,"thumbnailHeight":330,"uuid":"kK6xzuT7nN8es5J9"} +{"name":"Untitled979_20240120123618.png","date":"2024-01-20T17:38:31.845Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Untitled979_20240120123618.png","type":"image/png","size":14246,"imageWidth":350,"imageHeight":350,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FUntitled979_20240120123618.png","thumbnailWidth":330,"thumbnailHeight":330,"uuid":"izP72RmZ8nLYsSdc"} +{"name":"74ccbc9f-e1fa-4144-8a05-bebbd593fba3.image.png","date":"2024-01-20T17:39:19.444Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/74ccbc9f-e1fa-4144-8a05-bebbd593fba3.image.png","type":"image/png","size":17060,"imageWidth":215,"imageHeight":196,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/74ccbc9f-e1fa-4144-8a05-bebbd593fba3.image.png","thumbnailWidth":215,"thumbnailHeight":196,"uuid":"bJt3vCO1iQJAcPkv"} +{"name":"videoplayback.mp3","date":"2024-01-21T03:17:37.028Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/videoplayback.mp3","type":"audio/mpeg","size":3451436,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fvideoplayback.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"hFAccqiGuKtlcJVr"} +{"name":"jake-chudnow-edited_y1t8j5q.mp3","date":"2024-01-23T13:54:17.534Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/jake-chudnow-edited_y1t8j5q.mp3","type":"audio/mpeg","size":340823,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fjake-chudnow-edited_y1t8j5q.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"KsmNUXrjFBTR9nnt"} +{"name":"MemeFeedBot_5.mp4","date":"2024-01-30T20:25:51.474Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/MemeFeedBot_5.mp4","type":"video/mp4","size":1311719,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FMemeFeedBot_5.mp4","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"reUPECkwcraGwOc3"} +{"name":"4 2.wav","date":"2024-01-31T15:49:21.860Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/4%202.wav","type":"audio/wav","size":248118,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2F4%202.wav","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"1E7gld9pLGXWDUC8"} +{"name":"Screen recording 2024-01-23 9.38.41 AM.webm","date":"2024-02-02T01:45:08.442Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Screen%20recording%202024-01-23%209.38.41%20AM.webm","type":"video/webm","size":1616860,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FScreen%20recording%202024-01-23%209.38.41%20AM.webm","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"Lp97bNs9HjhFIlKp"} +{"name":"2024_02_01_112_Kleki.png","date":"2024-02-02T01:45:11.256Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2024_02_01_112_Kleki.png","type":"image/png","size":84804,"imageWidth":256,"imageHeight":256,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2024_02_01_112_Kleki.png","thumbnailWidth":256,"thumbnailHeight":256,"uuid":"QZfJ4aPwLpj3gxD9"} +{"name":"2024_02_01_10z_Kleki.png","date":"2024-02-02T01:45:15.168Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2024_02_01_10z_Kleki.png","type":"image/png","size":84316,"imageWidth":256,"imageHeight":256,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2024_02_01_10z_Kleki.png","thumbnailWidth":256,"thumbnailHeight":256,"uuid":"nDK0YapB9Y94CjO7"} +{"name":"2024_02_09_11n_Kleki.png","date":"2024-02-10T02:06:04.886Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2024_02_09_11n_Kleki.png","type":"image/png","size":53374,"imageWidth":218,"imageHeight":143,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2024_02_09_11n_Kleki.png","thumbnailWidth":218,"thumbnailHeight":143,"uuid":"KkGODJKzVOA9trS5"} +{"name":"2024_02_15_0qs_Kleki.png","date":"2024-02-15T19:34:53.434Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2024_02_15_0qs_Kleki.png","type":"image/png","size":2051,"imageWidth":100,"imageHeight":100,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2024_02_15_0qs_Kleki.png","thumbnailWidth":100,"thumbnailHeight":100,"uuid":"b7U68EwE9UUNAsv8"} +{"uuid":"b7U68EwE9UUNAsv8","deleted":true} +{"name":"Trophy.png","date":"2024-02-15T19:34:53.434Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Trophy.png","type":"image/png","size":2051,"imageWidth":100,"imageHeight":100,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2024_02_15_0qs_Kleki.png","thumbnailWidth":100,"thumbnailHeight":100,"uuid":"b7U68EwE9UUNAsv8"} +{"name":"download.mp3","date":"2024-02-18T01:07:44.295Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/download.mp3","type":"audio/mpeg","size":9263777,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fdownload.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"cCo9wkdNbXgR9VRm"} +{"name":"download (1).mp3","date":"2024-02-18T01:07:55.743Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/download%20(1).mp3","type":"audio/mpeg","size":6227366,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fdownload%20(1).mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"GUN6DCqlRr6SCsv0"} +{"name":"Untitled Project (22).jpg","date":"2024-02-19T15:27:04.097Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Untitled%20Project%20(22).jpg","type":"image/jpeg","size":34686,"imageWidth":159,"imageHeight":159,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Untitled%20Project%20(22).jpg","thumbnailWidth":159,"thumbnailHeight":159,"uuid":"QzQilm4F3P6jalgR"} +{"uuid":"x22blklePMGQRwIA","deleted":true} +{"name":"videoplayback (5).mp4","date":"2024-02-21T15:51:31.894Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/videoplayback%20(5).mp4","type":"video/mp4","size":2213386,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fvideoplayback%20(5).mp4","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"q6L0WZWbnI2dyDzS"} +{"name":"arrow.png","date":"2024-02-21T17:00:37.425Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/arrow.png","type":"image/png","size":20446,"imageWidth":500,"imageHeight":500,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Farrow.png","thumbnailWidth":330,"thumbnailHeight":330,"uuid":"ZUGJVJXduGCYUybX"} +{"name":"arrow2.png","date":"2024-02-21T17:00:40.066Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/arrow2.png","type":"image/png","size":20272,"imageWidth":500,"imageHeight":500,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Farrow2.png","thumbnailWidth":330,"thumbnailHeight":330,"uuid":"vTxD8Cdq5AZzpZHG"} +{"name":"2024_01_29_0rx_Kleki.png","date":"2024-02-21T17:30:37.147Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2024_01_29_0rx_Kleki.png","type":"image/png","size":44308,"imageWidth":512,"imageHeight":362,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2F2024_01_29_0rx_Kleki.png","thumbnailWidth":330,"thumbnailHeight":234,"uuid":"RyxRk17SDpdmFzRs"} +{"uuid":"RyxRk17SDpdmFzRs","deleted":true} +{"name":"2024_01_29_0ry_Kleki.png","date":"2024-02-21T17:30:52.978Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2024_01_29_0ry_Kleki.png","type":"image/png","size":78166,"imageWidth":612,"imageHeight":612,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2F2024_01_29_0ry_Kleki.png","thumbnailWidth":330,"thumbnailHeight":330,"uuid":"02ssJF2Tzrmn3sTQ"} +{"uuid":"02ssJF2Tzrmn3sTQ","deleted":true} +{"name":"2024_01_29_0rs_Kleki.png","date":"2024-02-21T17:31:06.919Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2024_01_29_0rs_Kleki.png","type":"image/png","size":49959,"imageWidth":612,"imageHeight":612,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2F2024_01_29_0rs_Kleki.png","thumbnailWidth":330,"thumbnailHeight":330,"uuid":"HqLijl5c1PuEAXz6"} +{"uuid":"HqLijl5c1PuEAXz6","deleted":true} +{"name":"2024_01_29_0ry_Kleki.png","date":"2024-02-21T17:31:20.813Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2024_01_29_0ry_Kleki.png","type":"image/png","size":78166,"imageWidth":612,"imageHeight":612,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2F2024_01_29_0ry_Kleki.png","thumbnailWidth":330,"thumbnailHeight":330,"uuid":"teEHfjowTA5oXZNX"} +{"uuid":"ULDBE338jPz5CztZ","deleted":true} +{"name":"onetransparentsingulardamnfuckingpixel.png","date":"2024-02-22T02:16:19.353Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/onetransparentsingulardamnfuckingpixel.png","type":"image/png","size":81,"imageWidth":1,"imageHeight":1,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/onetransparentsingulardamnfuckingpixel.png","thumbnailWidth":1,"thumbnailHeight":1,"uuid":"ckPJEBh7eEJWdxnK"} +{"name":"primal.webp","date":"2024-02-22T11:52:43.032Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/primal.webp","type":"image/webp","size":56824,"imageWidth":350,"imageHeight":350,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fprimal.webp","thumbnailWidth":330,"thumbnailHeight":330,"uuid":"cfHcvjVbbDfZh8xc"} +{"name":"image.webp","date":"2024-02-22T11:52:45.689Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/image.webp","type":"image/webp","size":59336,"imageWidth":281,"imageHeight":350,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fimage.webp","thumbnailWidth":265,"thumbnailHeight":330,"uuid":"9yXl5YIjYKceliFg"} +{"uuid":"ctTmChYwrALlsYSY","deleted":true} +{"name":"locked.png","date":"2024-02-22T11:55:29.342Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/locked.png","type":"image/png","size":18202,"imageWidth":612,"imageHeight":612,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Flocked.png","thumbnailWidth":330,"thumbnailHeight":330,"uuid":"n8yNyvfqwb7DnXAi"} +{"name":"tv.png","date":"2024-02-22T15:17:55.011Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/tv.png","type":"image/png","size":106896,"imageWidth":600,"imageHeight":600,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Ftv.png","thumbnailWidth":330,"thumbnailHeight":330,"uuid":"IZOWYASNX0WOguf8"} +{"name":"MOSHED-2023-12-14-17-8-14.gif","date":"2024-02-22T16:22:04.966Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/MOSHED-2023-12-14-17-8-14.gif","type":"image/gif","size":710884,"imageWidth":182,"imageHeight":182,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/MOSHED-2023-12-14-17-8-14.gif","thumbnailWidth":182,"thumbnailHeight":182,"uuid":"zoDYKbRylm4uPSua"} +{"name":"skype.png","date":"2024-02-22T16:23:57.464Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/skype.png","type":"image/png","size":135963,"imageWidth":2400,"imageHeight":2435,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fskype.png","thumbnailWidth":326,"thumbnailHeight":330,"uuid":"H8TxN9mqnMgaTfLw"} +{"name":"2e2ccc30-5baf-41a2-aceb-c5456a1cc6dc.image.png","date":"2024-02-22T16:25:46.196Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2e2ccc30-5baf-41a2-aceb-c5456a1cc6dc.image.png","type":"image/png","size":163198,"imageWidth":1200,"imageHeight":1200,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2F2e2ccc30-5baf-41a2-aceb-c5456a1cc6dc.image.png","thumbnailWidth":330,"thumbnailHeight":330,"uuid":"BETXanMl4Oa3nyk2"} +{"uuid":"9yXl5YIjYKceliFg","deleted":true} +{"uuid":"H8TxN9mqnMgaTfLw","deleted":true} +{"name":"skype.png","date":"2024-02-22T17:39:54.494Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/skype.png","type":"image/png","size":37427,"imageWidth":612,"imageHeight":612,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fskype.png","thumbnailWidth":330,"thumbnailHeight":330,"uuid":"f8Ge23pxSgxIHP3y"} +{"name":"image.webp","date":"2024-02-22T17:39:56.560Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/image.webp","type":"image/webp","size":76573,"imageWidth":300,"imageHeight":300,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/image.webp","thumbnailWidth":300,"thumbnailHeight":300,"uuid":"T4mvFRGVmo7ZSS3r"} +{"name":"locked2.png","date":"2024-02-23T18:43:14.287Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/locked2.png","type":"image/png","size":17278,"imageWidth":612,"imageHeight":612,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Flocked2.png","thumbnailWidth":330,"thumbnailHeight":330,"uuid":"M9o7ylMUafge5ugm"} +{"name":"select.png","date":"2024-02-23T19:54:31.992Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/select.png","type":"image/png","size":8705,"imageWidth":382,"imageHeight":200,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fselect.png","thumbnailWidth":330,"thumbnailHeight":173,"uuid":"VUgg69AS6qvPYYm2"} +{"name":"locked!.png","date":"2024-02-23T19:54:35.601Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/locked!.png","type":"image/png","size":9307,"imageWidth":382,"imageHeight":200,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Flocked!.png","thumbnailWidth":330,"thumbnailHeight":173,"uuid":"9TbrgbxQ4qWp7wo8"} +{"name":"selected.png","date":"2024-02-23T19:57:48.075Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/selected.png","type":"image/png","size":10342,"imageWidth":382,"imageHeight":200,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fselected.png","thumbnailWidth":330,"thumbnailHeight":173,"uuid":"FOpbj7lZQ46siJhg"} +{"name":"Coca_Cola_Espuma.mp4","date":"2024-02-25T21:05:14.047Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Coca_Cola_Espuma.mp4","type":"video/mp4","size":104064,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FCoca_Cola_Espuma.mp4","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"FGE2VR7615Lfujp8"} +{"name":"channels4_profile.jpg","date":"2024-03-01T20:16:47.088Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/channels4_profile.jpg","type":"image/jpeg","size":99589,"imageWidth":900,"imageHeight":900,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fchannels4_profile.jpg","thumbnailWidth":330,"thumbnailHeight":330,"uuid":"jd7joNLFJLt9pfED"} +{"name":"2024_03_02_0yw_Kleki.png","date":"2024-03-03T00:26:41.538Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2024_03_02_0yw_Kleki.png","type":"image/png","size":2141,"imageWidth":128,"imageHeight":128,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2024_03_02_0yw_Kleki.png","thumbnailWidth":128,"thumbnailHeight":128,"uuid":"th3bRPzSTorKXKDi"} +{"name":"2024_03_02_0yw_Kleki (1).png","date":"2024-03-03T00:26:52.528Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2024_03_02_0yw_Kleki%20(1).png","type":"image/png","size":7139,"imageWidth":128,"imageHeight":128,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2024_03_02_0yw_Kleki%20(1).png","thumbnailWidth":128,"thumbnailHeight":128,"uuid":"p9YoKuARaRk3B841"} +{"uuid":"txSk7RsRJ33ZgL0R","deleted":true} +{"name":"videoplayback.mp4","date":"2024-03-03T01:45:53.601Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/videoplayback.mp4","type":"video/mp4","size":2796319,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fvideoplayback.mp4","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"NKyN5jkpsVkhg3Yl"} +{"uuid":"q6L0WZWbnI2dyDzS","deleted":true} +{"name":"undertakers-bell_2UwFCIe.mp3","date":"2024-03-12T18:42:39.839Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/undertakers-bell_2UwFCIe.mp3","type":"audio/mpeg","size":68055,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fundertakers-bell_2UwFCIe.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"u6xFAcMANHBQhPTB"} +{"name":"aaaaaaaa-online-audio-converter_r9waVUO.mp3","date":"2024-03-12T19:17:49.219Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/aaaaaaaa-online-audio-converter_r9waVUO.mp3","type":"audio/mpeg","size":17807,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Faaaaaaaa-online-audio-converter_r9waVUO.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"aNcuRqu2nQzZStT2"} +{"name":"metal-pipe-clang.mp3","date":"2024-03-12T19:17:53.637Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/metal-pipe-clang.mp3","type":"audio/mpeg","size":45694,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fmetal-pipe-clang.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"ro1Gfn5NPJDSpUUK"} +{"name":"vine-boom.mp3","date":"2024-03-12T22:02:49.499Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/vine-boom.mp3","type":"audio/mpeg","size":21230,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fvine-boom.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"ebMorJE4l2U0t6ec"} +{"name":"tmp_7901-951678082.mp3","date":"2024-03-12T22:02:54.624Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/tmp_7901-951678082.mp3","type":"audio/mpeg","size":16425,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Ftmp_7901-951678082.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"ApoIUl7SyuyEaopN"} +{"name":"emotional-damage-meme.mp3","date":"2024-03-12T22:02:59.660Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/emotional-damage-meme.mp3","type":"audio/mpeg","size":54262,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Femotional-damage-meme.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"UNGgdWN3md0VrWpz"} +{"name":"discord-notification.mp3","date":"2024-03-12T22:03:03.356Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/discord-notification.mp3","type":"audio/mpeg","size":8301,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fdiscord-notification.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"NCiDWuamdHpEV71a"} +{"name":"wrong-answer-sound-effect.mp3","date":"2024-03-12T22:03:15.813Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/wrong-answer-sound-effect.mp3","type":"audio/mpeg","size":19479,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fwrong-answer-sound-effect.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"cvaZ88hmjymDoYyl"} +{"name":"clash-royale-hog-rider.mp3","date":"2024-03-12T22:03:19.656Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/clash-royale-hog-rider.mp3","type":"audio/mpeg","size":70145,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fclash-royale-hog-rider.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"58kvJm1P0eAgy2zu"} +{"name":"goofy-ahh-car-horn-sound-effect.mp3","date":"2024-03-12T22:03:24.188Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/goofy-ahh-car-horn-sound-effect.mp3","type":"audio/mpeg","size":49456,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fgoofy-ahh-car-horn-sound-effect.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"sqlTlpMYSaoC5Ibw"} +{"name":"tf_nemesis.mp3","date":"2024-03-12T22:03:29.502Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/tf_nemesis.mp3","type":"audio/mpeg","size":73813,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Ftf_nemesis.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"pQcX3TfMLczzdXm0"} +{"name":"chinese-rap-song.mp3","date":"2024-03-12T22:03:35.151Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/chinese-rap-song.mp3","type":"audio/mpeg","size":160451,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fchinese-rap-song.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"UG4BHOkrbtySjMoI"} +{"name":"fire-in-the-hole-geometry-dash.mp3","date":"2024-03-12T22:03:40.367Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/fire-in-the-hole-geometry-dash.mp3","type":"audio/mpeg","size":31680,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Ffire-in-the-hole-geometry-dash.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"RxWARK12ebQVuh9e"} +{"name":"water-on-the-hill.mp3","date":"2024-03-12T22:03:47.326Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/water-on-the-hill.mp3","type":"audio/mpeg","size":13100,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fwater-on-the-hill.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"6lJLNPCsgJCtbgrd"} +{"name":"taco-bell-bong-sfx.mp3","date":"2024-03-12T22:03:52.201Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/taco-bell-bong-sfx.mp3","type":"audio/mpeg","size":31599,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Ftaco-bell-bong-sfx.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"wdvpWAE7Px1X3Z6R"} +{"name":"dun_dun_1.mp3","date":"2024-03-14T15:54:39.063Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/dun_dun_1.mp3","type":"audio/mpeg","size":21607,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fdun_dun_1.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"RukfNSPWQfBw87v2"} +{"name":"holy-moly-emoji.mp3","date":"2024-03-14T15:54:42.780Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/holy-moly-emoji.mp3","type":"audio/mpeg","size":22567,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fholy-moly-emoji.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"B3qwwfOmo4IqDjky"} +{"name":"spongebob-boowomp.mp3","date":"2024-03-14T15:54:49.245Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/spongebob-boowomp.mp3","type":"audio/mpeg","size":23751,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fspongebob-boowomp.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"WKAEtNX56P5Yjl6G"} +{"name":"bad-to-the-bone-meme.mp3","date":"2024-03-14T15:54:54.343Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/bad-to-the-bone-meme.mp3","type":"audio/mpeg","size":41346,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fbad-to-the-bone-meme.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"GE5BxezBXE6OeL3d"} +{"name":"feet-gd.mp3","date":"2024-03-14T15:54:59.794Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/feet-gd.mp3","type":"audio/mpeg","size":8352,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Ffeet-gd.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"8mtGRsAwmu5czOoy"} +{"name":"5c6d635f-a352-4145-9002-2d0a4e16824d.image.png","date":"2024-03-20T22:15:57.366Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/5c6d635f-a352-4145-9002-2d0a4e16824d.image.png","type":"image/png","size":66868,"imageWidth":1536,"imageHeight":951,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2F5c6d635f-a352-4145-9002-2d0a4e16824d.image.png","thumbnailWidth":330,"thumbnailHeight":205,"uuid":"XP09HX2tGTiXNXFs"} +{"name":"2024_03_26_0zp_Kleki.png","date":"2024-03-26T23:55:49.798Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2024_03_26_0zp_Kleki.png","type":"image/png","size":8852,"imageWidth":128,"imageHeight":128,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2024_03_26_0zp_Kleki.png","thumbnailWidth":128,"thumbnailHeight":128,"uuid":"xFkrHKnI6qOjWIB7"} +{"name":"image_2024-04-11_161031965.ico","date":"2024-04-11T18:41:32.273Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/image_2024-04-11_161031965.ico","type":"image/x-icon","size":225726,"imageWidth":256,"imageHeight":256,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/image_2024-04-11_161031965.ico","thumbnailWidth":256,"thumbnailHeight":256,"uuid":"b73O6MpXAdhV1Rur"} +{"uuid":"XfFWeHV5t1gcuE4J","deleted":true} +{"name":"Action Agenda - Killa DFX Edit.mp3","date":"2024-04-17T11:10:44.240Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Action%20Agenda%20-%20Killa%20DFX%20Edit.mp3","type":"audio/mpeg","size":7596960,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FAction%20Agenda%20-%20Killa%20DFX%20Edit.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"goq6Nz3Otdd2T6CZ"} +{"uuid":"RsOUyfm1cBYSqbw0","deleted":true} +{"name":"Apotheosis.wav","date":"2024-04-17T11:13:48.783Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Apotheosis.wav","type":"audio/wav","size":33796140,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FApotheosis.wav","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"sdKc4c16V8kOoffG"} +{"name":"Depredation.wav","date":"2024-04-17T11:51:30.584Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Depredation.wav","type":"audio/wav","size":39784492,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FDepredation.wav","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"vMjHBJ94XqKWFz9b"} +{"name":"2024_04_17_0gh_Kleki.png","date":"2024-04-17T12:23:56.170Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2024_04_17_0gh_Kleki.png","type":"image/png","size":2144,"imageWidth":128,"imageHeight":128,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2024_04_17_0gh_Kleki.png","thumbnailWidth":128,"thumbnailHeight":128,"uuid":"dAHNcl4YUXtrnYNr"} +{"uuid":"sdKc4c16V8kOoffG","deleted":true} +{"uuid":"vMjHBJ94XqKWFz9b","deleted":true} +{"name":"8mb.video-tQi-0UoaHVvl.mp4","date":"2024-04-18T22:14:20.996Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/8mb.video-tQi-0UoaHVvl.mp4","type":"video/mp4","size":18092799,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2F8mb.video-tQi-0UoaHVvl.mp4","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"qbGOtBvcJcjg37V9"} +{"uuid":"qbGOtBvcJcjg37V9","deleted":true} +{"name":"Screenshot_2024-04-12_at_2.52.02_PM.png","date":"2024-04-19T10:54:45.626Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Screenshot_2024-04-12_at_2.52.02_PM.png","type":"image/png","size":72691,"imageWidth":272,"imageHeight":366,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FScreenshot_2024-04-12_at_2.52.02_PM.png","thumbnailWidth":246,"thumbnailHeight":330,"uuid":"UmCvpyaMKwvJtjI9"} +{"name":"videoplayback (4).mp4","date":"2024-04-19T10:56:39.084Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/videoplayback%20(4).mp4","type":"video/mp4","size":258165,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fvideoplayback%20(4).mp4","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"DGrL98ImDItr7mJG"} +{"name":"Depredation V2.mp3","date":"2024-04-19T11:12:12.474Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Depredation%20V2.mp3","type":"audio/mpeg","size":8288129,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FDepredation%20V2.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"6LtgWCgUdzzqE3hr"} +{"name":"Apotheosis (1).mp3","date":"2024-04-19T11:16:59.376Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Apotheosis%20(1).mp3","type":"audio/mpeg","size":7040129,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FApotheosis%20(1).mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"ku50xwnoZ8ABjNcJ"} +{"name":"2024_04_22_0ep_Kleki.png","date":"2024-04-22T11:40:03.892Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2024_04_22_0ep_Kleki.png","type":"image/png","size":2169,"imageWidth":128,"imageHeight":128,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2024_04_22_0ep_Kleki.png","thumbnailWidth":128,"thumbnailHeight":128,"uuid":"KtLhCRh5D7z40ufq"} +{"uuid":"KtLhCRh5D7z40ufq","deleted":true} +{"name":"2024_04_22_0fb_Kleki.png","date":"2024-04-22T11:43:54.204Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2024_04_22_0fb_Kleki.png","type":"image/png","size":2165,"imageWidth":128,"imageHeight":128,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2024_04_22_0fb_Kleki.png","thumbnailWidth":128,"thumbnailHeight":128,"uuid":"Zq5aBpo0JAKsFPSd"} +{"name":"Voicy_Slap Battles Killstreak Kill.mp3","date":"2024-04-25T11:47:23.190Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Voicy_Slap%20Battles%20Killstreak%20Kill.mp3","type":"audio/mpeg","size":45171,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FVoicy_Slap%20Battles%20Killstreak%20Kill.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"YE7Wbxb7eY4uN03N"} +{"name":"1165825970528325682.webp","date":"2024-04-26T18:39:24.280Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/1165825970528325682.webp","type":"image/webp","size":1098,"imageWidth":45,"imageHeight":48,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/1165825970528325682.webp","thumbnailWidth":45,"thumbnailHeight":48,"uuid":"bAX0kJLTMphe3F8v"} +{"name":"1165934432608321546.webp","date":"2024-04-26T18:39:28.932Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/1165934432608321546.webp","type":"image/webp","size":968,"imageWidth":48,"imageHeight":48,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/1165934432608321546.webp","thumbnailWidth":48,"thumbnailHeight":48,"uuid":"Ci3JnJpEDmg4VF1c"} +{"name":"1165934167280848969.webp","date":"2024-04-26T18:39:33.284Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/1165934167280848969.webp","type":"image/webp","size":1582,"imageWidth":48,"imageHeight":48,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/1165934167280848969.webp","thumbnailWidth":48,"thumbnailHeight":48,"uuid":"HTqsPOJz4I9rlBGh"} +{"name":"1165826077843796018.webp","date":"2024-04-26T18:39:38.841Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/1165826077843796018.webp","type":"image/webp","size":950,"imageWidth":48,"imageHeight":48,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/1165826077843796018.webp","thumbnailWidth":48,"thumbnailHeight":48,"uuid":"eV1sBWslSmqgAf1m"} +{"name":"1165825970528325682l.webp","date":"2024-04-26T18:40:07.621Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/1165825970528325682l.webp","type":"image/webp","size":864,"imageWidth":48,"imageHeight":48,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/1165825970528325682l.webp","thumbnailWidth":48,"thumbnailHeight":48,"uuid":"neN7tKpXt8DS0TpV"} +{"uuid":"nFvYO1N5f6xH8PgY","deleted":true} +{"uuid":"b0959XaAUwrm5DBm","deleted":true} +{"name":"Dejected.mp3","date":"2024-01-15T02:50:22.417Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Dejected.mp3","type":"audio/mpeg","size":4125377,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2F4Miklipi%20(Dejected)%20Preview.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"b0959XaAUwrm5DBm"} +{"uuid":"ku50xwnoZ8ABjNcJ","deleted":true} +{"name":"Apotheosis.mp3","date":"2024-04-19T11:16:59.376Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Apotheosis.mp3","type":"audio/mpeg","size":7040129,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FApotheosis%20(1).mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"ku50xwnoZ8ABjNcJ"} +{"uuid":"cCo9wkdNbXgR9VRm","deleted":true} +{"name":"longing.mp3","date":"2024-02-18T01:07:44.295Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/longing.mp3","type":"audio/mpeg","size":9263777,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fdownload.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"cCo9wkdNbXgR9VRm"} +{"uuid":"GUN6DCqlRr6SCsv0","deleted":true} +{"name":"resurgam.mp3","date":"2024-02-18T01:07:55.743Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/resurgam.mp3","type":"audio/mpeg","size":6227366,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fdownload%20(1).mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"GUN6DCqlRr6SCsv0"} +{"uuid":"hFAccqiGuKtlcJVr","deleted":true} +{"name":"anybody.mp3","date":"2024-01-21T03:17:37.028Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/anybody.mp3","type":"audio/mpeg","size":3451436,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fvideoplayback.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"hFAccqiGuKtlcJVr"} +{"name":"World's End.wav","date":"2024-04-29T13:56:37.026Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/World's%20End.wav","type":"audio/wav","size":33800236,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FWorld's%20End.wav","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"ifIYobcrMaJ5CVvw"} +{"uuid":"ifIYobcrMaJ5CVvw","deleted":true} +{"name":"World's End but mp4.mp3","date":"2024-04-29T13:58:52.177Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/World's%20End%20but%20mp4.mp3","type":"audio/mpeg","size":7041141,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FWorld's%20End%20but%20mp4.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"OzD5VXdumCGeEqDb"} +{"uuid":"OzD5VXdumCGeEqDb","deleted":true} +{"name":"WorldsEnd.mp3","date":"2024-04-29T13:58:52.177Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/WorldsEnd.mp3","type":"audio/mpeg","size":7041141,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FWorld's%20End%20but%20mp4.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"OzD5VXdumCGeEqDb"} +{"name":"(Audio) 2024-04-22 15-59-27.m4a","date":"2024-04-29T17:56:37.185Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/(Audio)%202024-04-22%2015-59-27.m4a","type":"audio/x-m4a","size":469042,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2F(Audio)%202024-04-22%2015-59-27.m4a","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"BL7o4FYSsr2Xtdab"} +{"uuid":"BL7o4FYSsr2Xtdab","deleted":true} +{"name":"ultimate laughter.mp4","date":"2024-04-29T17:57:21.289Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/ultimate%20laughter.mp4","type":"video/mp4","size":12731065,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fultimate%20laughter.mp4","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"qKxRKzwie2uwOD1P"} +{"name":"demol1sh.mp3","date":"2024-04-29T18:15:57.787Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/demol1sh.mp3","type":"audio/mpeg","size":4167680,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fdemol1sh.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"J2BTiSehE6If7Hxe"} +{"name":"routin3s.mp3","date":"2024-04-29T18:18:00.054Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/routin3s.mp3","type":"audio/mpeg","size":3073485,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Froutin3s.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"n1p45IKty7rhEB3C"} +{"name":"souven1r.mp3","date":"2024-04-29T18:18:04.036Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/souven1r.mp3","type":"audio/mpeg","size":3815868,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fsouven1r.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"gT7k6nINNGIZi3N3"} +{"name":"jitt3rs.mp3","date":"2024-04-29T18:18:04.287Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/jitt3rs.mp3","type":"audio/mpeg","size":4775267,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fjitt3rs.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"Be3hu6iiO23cqEY0"} +{"name":"2ouvenir.mp3","date":"2024-04-29T18:18:20.719Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2ouvenir.mp3","type":"audio/mpeg","size":4318545,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2F2ouvenir.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"1XBSkO00yeI1Yi2Y"} +{"name":"d3molish.mp3","date":"2024-04-29T18:18:26.958Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/d3molish.mp3","type":"audio/mpeg","size":3902041,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fd3molish.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"zW0KIBTt4lgumW6g"} +{"name":"demoli2h.mp3","date":"2024-04-29T18:18:34.759Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/demoli2h.mp3","type":"audio/mpeg","size":3995734,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fdemoli2h.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"lVqeyaHXOOHA3aZa"} +{"uuid":"n1p45IKty7rhEB3C","deleted":true} +{"name":"routin3s.mp3","date":"2024-04-29T18:20:50.230Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/routin3s.mp3","type":"audio/mpeg","size":3073485,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Froutin3s.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"TFRBBNfrVJUyspgF"} +{"name":"routine2.mp3","date":"2024-04-29T18:21:29.291Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/routine2.mp3","type":"audio/mpeg","size":3457701,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Froutine2.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"YFI91wH7W4ImAspG"} +{"uuid":"Lp97bNs9HjhFIlKp","deleted":true} +{"uuid":"1E7gld9pLGXWDUC8","deleted":true} +{"name":"IMG_20240528_183451141.jpg","date":"2024-05-28T21:05:24.675Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/IMG_20240528_183451141.jpg","type":"image/jpeg","size":1297815,"imageWidth":1842,"imageHeight":4096,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FIMG_20240528_183451141.jpg","thumbnailWidth":149,"thumbnailHeight":330,"uuid":"DOggN020wevkaQxc"} +{"name":"583124__bruhman29__ambient-piano-glitch-loop.mp3","date":"2024-07-03T23:46:28.796Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/583124__bruhman29__ambient-piano-glitch-loop.mp3","type":"audio/mpeg","size":722880,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2F583124__bruhman29__ambient-piano-glitch-loop.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"KYCEs4Okhu8gU0Rw"} +{"name":"spider_2.png","date":"2024-08-02T21:15:19.003Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/spider_2.png","type":"image/png","size":14419,"imageWidth":158,"imageHeight":127,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/spider_2.png","thumbnailWidth":158,"thumbnailHeight":127,"uuid":"dr215LMSNrjEayVI"} +{"name":"IMG_1942.png","date":"2024-08-11T01:56:28.613Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/IMG_1942.png","type":"image/png","size":349865,"imageWidth":903,"imageHeight":869,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FIMG_1942.png","thumbnailWidth":330,"thumbnailHeight":318,"uuid":"IE8b2wO2CuoFPxKz"} +{"name":"52459e59-5ff9-4646-9949-a2a1461c7202.image.png","date":"2024-08-23T00:43:21.016Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/52459e59-5ff9-4646-9949-a2a1461c7202.image.png","type":"image/png","size":32907,"imageWidth":602,"imageHeight":598,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2F52459e59-5ff9-4646-9949-a2a1461c7202.image.png","thumbnailWidth":330,"thumbnailHeight":328,"uuid":"7n3Mf5ySFZaYGt9y"} +{"name":"eb38cb57-74b4-4965-b9b5-f4b83bd80de3.image.png","date":"2024-09-15T03:32:23.116Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/eb38cb57-74b4-4965-b9b5-f4b83bd80de3.image.png","type":"image/png","size":343944,"imageWidth":634,"imageHeight":616,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Feb38cb57-74b4-4965-b9b5-f4b83bd80de3.image.png","thumbnailWidth":330,"thumbnailHeight":321,"uuid":"5gMgdFgGHHpnYjJs"} +{"name":"SuperSaw.wav","date":"2024-09-29T21:04:14.959Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/SuperSaw.wav","type":"audio/wav","size":4214828,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FSuperSaw.wav","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"PKzCxQwewiAF7Gs0"} +{"uuid":"PKzCxQwewiAF7Gs0","deleted":true} +{"name":"Nero.wav","date":"2024-09-29T21:07:08.814Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Nero.wav","type":"audio/wav","size":29626412,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FNero.wav","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"F2PbIeRc9lFIJmeh"} +{"name":"Atomic.wav","date":"2024-09-29T21:07:28.951Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Atomic.wav","type":"audio/wav","size":49156140,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FAtomic.wav","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"6bY9oHn78ci4iecI"} +{"uuid":"YFI91wH7W4ImAspG","deleted":true} +{"name":"routine2.mp3","date":"2024-09-29T21:23:28.378Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/routine2.mp3","type":"audio/mpeg","size":3457701,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Froutine2.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"Zsc0tzfZ9WbJruiV"} +{"uuid":"Zsc0tzfZ9WbJruiV","deleted":true} +{"uuid":"TFRBBNfrVJUyspgF","deleted":true} +{"uuid":"lVqeyaHXOOHA3aZa","deleted":true} +{"uuid":"zW0KIBTt4lgumW6g","deleted":true} +{"uuid":"1XBSkO00yeI1Yi2Y","deleted":true} +{"uuid":"Be3hu6iiO23cqEY0","deleted":true} +{"uuid":"gT7k6nINNGIZi3N3","deleted":true} +{"uuid":"J2BTiSehE6If7Hxe","deleted":true} +{"name":"Failed Connection.mp3","date":"2024-09-29T21:28:24.666Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Failed%20Connection.mp3","type":"audio/mpeg","size":8843969,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FFailed%20Connection.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"LAtmB7m49HCAls6f"} +{"name":"Acension (Apotheosis 2).wav","date":"2024-10-21T12:52:46.145Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Acension%20(Apotheosis%202).wav","type":"audio/wav","size":30978092,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FAcension%20(Apotheosis%202).wav","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"9slDjUspOoEUXAlt"} +{"name":"Nadir (Apotheosis 3).wav","date":"2024-10-21T12:52:50.342Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Nadir%20(Apotheosis%203).wav","type":"audio/wav","size":33538092,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FNadir%20(Apotheosis%203).wav","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"K21MpQlwwaIrOtvb"} +{"name":"Methemphetaphacktomine.wav","date":"2024-10-21T12:52:53.719Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Methemphetaphacktomine.wav","type":"audio/wav","size":35811372,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FMethemphetaphacktomine.wav","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"m3VznFUfVCNRCqkm"} +{"name":"Polychromatism.wav","date":"2024-10-21T12:52:57.274Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Polychromatism.wav","type":"audio/wav","size":35762220,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FPolychromatism.wav","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"TMDLz8dUptnSYX70"} +{"name":"untitled.wav","date":"2024-12-07T23:27:09.212Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/untitled.wav","type":"audio/wav","size":382666,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Funtitled.wav","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"i8XyLCBQNVS9ekCd"} +{"name":"open.wav","date":"2024-12-07T23:27:19.155Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/open.wav","type":"audio/wav","size":208940,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fopen.wav","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"Q3pKhBCulXVUEcTg"} +{"name":"close.wav","date":"2024-12-07T23:27:24.438Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/close.wav","type":"audio/wav","size":192556,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fclose.wav","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"B7z9HLLBtg9ZUDxa"} +{"name":"click.wav","date":"2024-12-08T01:25:43.102Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/click.wav","type":"audio/wav","size":65580,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fclick.wav","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"jsuQL8QqGsmt5sdo"} +{"name":"hover.wav","date":"2024-12-08T01:25:44.155Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/hover.wav","type":"audio/wav","size":49196,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fhover.wav","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"5kUX1PsGm18svZGJ"} +{"name":"441307__aptbr__glitched-piano.wav","date":"2024-12-08T01:39:40.735Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/441307__aptbr__glitched-piano.wav","type":"audio/wav","size":13578284,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2F441307__aptbr__glitched-piano.wav","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"voDkVj4LNaOeuV5N"} +{"name":"84f6ebcc-bf57-42e0-8e5f-85de3dfea363.image.png","date":"2024-12-08T02:37:33.065Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/84f6ebcc-bf57-42e0-8e5f-85de3dfea363.image.png","type":"image/png","size":67048,"imageWidth":1976,"imageHeight":113,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2F84f6ebcc-bf57-42e0-8e5f-85de3dfea363.image.png","thumbnailWidth":330,"thumbnailHeight":19,"uuid":"Qy3JRwgw0f4Ni6g7"} +{"uuid":"Qy3JRwgw0f4Ni6g7","deleted":true} +{"name":"2024_12_07_12i_Kleki.png","date":"2024-12-08T02:37:46.333Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2024_12_07_12i_Kleki.png","type":"image/png","size":208820,"imageWidth":1800,"imageHeight":300,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2F2024_12_07_12i_Kleki.png","thumbnailWidth":330,"thumbnailHeight":55,"uuid":"J2MhNe7jtKFr0qko"} +{"name":"123123.wav","date":"2024-12-14T14:48:06.345Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/123123.wav","type":"audio/wav","size":326690,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2F123123.wav","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"507in5wEQolRBako"} +{"name":"Wednesday, Friday (1).wav","date":"2025-01-15T21:59:59.984Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Wednesday%2C%20Friday%20(1).wav","type":"audio/wav","size":30724140,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FWednesday%2C%20Friday%20(1).wav","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"D2CJZv4jtDlBS3Iq"} +{"name":"Heresy.wav","date":"2025-01-15T22:15:37.244Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Heresy.wav","type":"audio/wav","size":31236140,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FHeresy.wav","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"xXMQVZpDac8bWpYX"} +{"name":"Reconstructed.wav","date":"2025-01-15T22:17:04.454Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Reconstructed.wav","type":"audio/wav","size":33796140,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FReconstructed.wav","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"pXbPNfcnn18rVlF5"} +{"name":"06f19349-48de-46ec-9877-6ea585848961.image.png","date":"2025-02-08T19:41:52.157Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/06f19349-48de-46ec-9877-6ea585848961.image.png","type":"image/png","size":180026,"imageWidth":512,"imageHeight":512,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2F06f19349-48de-46ec-9877-6ea585848961.image.png","thumbnailWidth":330,"thumbnailHeight":330,"uuid":"EloWZczA1qI50ZEl"} +{"name":"Touch the Diddy.mp3","date":"2025-03-21T20:02:03.413Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Touch%20the%20Diddy.mp3","type":"audio/mpeg","size":658319,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FTouch%20the%20Diddy.mp3","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"fDhaJLhOBLmkgDIR"} +{"name":"e1aa2990-5b79-4e6b-b81d-411440f5df7e.image.png","date":"2025-04-30T21:31:27.745Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/e1aa2990-5b79-4e6b-b81d-411440f5df7e.image.png","type":"image/png","size":719025,"imageWidth":645,"imageHeight":460,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fe1aa2990-5b79-4e6b-b81d-411440f5df7e.image.png","thumbnailWidth":330,"thumbnailHeight":236,"uuid":"7kN7jYXmaLNnUqgX"} +{"name":"d52124ef-c203-4a8e-aeef-279d97931cf0.image.png","date":"2025-04-30T21:32:16.528Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/d52124ef-c203-4a8e-aeef-279d97931cf0.image.png","type":"image/png","size":779166,"imageWidth":828,"imageHeight":831,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fd52124ef-c203-4a8e-aeef-279d97931cf0.image.png","thumbnailWidth":329,"thumbnailHeight":330,"uuid":"JaSFmVApie8SMINn"} +{"name":"c9d5bfb7-5d6e-4165-a769-f28b8503ba99.image.png","date":"2025-04-30T21:34:31.797Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/c9d5bfb7-5d6e-4165-a769-f28b8503ba99.image.png","type":"image/png","size":389888,"imageWidth":606,"imageHeight":432,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fc9d5bfb7-5d6e-4165-a769-f28b8503ba99.image.png","thumbnailWidth":330,"thumbnailHeight":236,"uuid":"xnm9dsorODy1Iorg"} +{"name":"d9ff0c74-0202-469a-b614-e91c290e2ee6.image.png","date":"2025-04-30T21:36:37.970Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/d9ff0c74-0202-469a-b614-e91c290e2ee6.image.png","type":"image/png","size":236026,"imageWidth":612,"imageHeight":612,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fd9ff0c74-0202-469a-b614-e91c290e2ee6.image.png","thumbnailWidth":330,"thumbnailHeight":330,"uuid":"Drk1peEBoDOAaMZM"} +{"name":"bleKXO-ad3W-OuOT.mp4","date":"2025-04-30T21:39:25.620Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/bleKXO-ad3W-OuOT.mp4","type":"video/mp4","size":2444928,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FbleKXO-ad3W-OuOT.mp4","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"GNonG59eQmNqQnUW"} +{"name":"creature_of_steel.mp4.mp4","date":"2025-04-30T21:41:52.412Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/creature_of_steel.mp4.mp4","type":"video/mp4","size":1203981,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fcreature_of_steel.mp4.mp4","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"q40C8H0R0jkXZ2VF"} +{"name":"04fda090-a3d9-47f1-ba34-76d37bbaca6a.image.png","date":"2025-04-30T21:45:52.738Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/04fda090-a3d9-47f1-ba34-76d37bbaca6a.image.png","type":"image/png","size":666682,"imageWidth":750,"imageHeight":508,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2F04fda090-a3d9-47f1-ba34-76d37bbaca6a.image.png","thumbnailWidth":330,"thumbnailHeight":224,"uuid":"lFB9sOuBtKEa9eoN"} +{"name":"c35cdf3d-4d0c-48e6-b226-cf4d38a30adf.image.png","date":"2025-04-30T21:46:32.068Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/c35cdf3d-4d0c-48e6-b226-cf4d38a30adf.image.png","type":"image/png","size":284274,"imageWidth":828,"imageHeight":794,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fc35cdf3d-4d0c-48e6-b226-cf4d38a30adf.image.png","thumbnailWidth":330,"thumbnailHeight":317,"uuid":"NTN69skUBtiNuLdh"} +{"name":"eEKak-MBdeQGYORG.mp4","date":"2025-04-30T21:50:22.570Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/eEKak-MBdeQGYORG.mp4","type":"video/mp4","size":593267,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2FeEKak-MBdeQGYORG.mp4","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"jy4YrZZgOEJQ1w3Y"} +{"name":"lil_sis.mp4","date":"2025-04-30T21:56:01.145Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/lil_sis.mp4","type":"video/mp4","size":268471,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Flil_sis.mp4","thumbnailWidth":210,"thumbnailHeight":210,"uuid":"s6YYdhm2a6O8A1aP"} +{"name":"78ef256e-6586-43e1-9028-b0d3e8e829f6.image.png","date":"2025-04-30T21:56:55.645Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/78ef256e-6586-43e1-9028-b0d3e8e829f6.image.png","type":"image/png","size":5139345,"imageWidth":2880,"imageHeight":1800,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2F78ef256e-6586-43e1-9028-b0d3e8e829f6.image.png","thumbnailWidth":330,"thumbnailHeight":207,"uuid":"1LTYT8YpDR2YN6JL"} +{"name":"adacb81f-a679-413e-8499-6005e1cc4b05.image.png","date":"2025-04-30T21:59:45.838Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/adacb81f-a679-413e-8499-6005e1cc4b05.image.png","type":"image/png","size":100807,"imageWidth":162,"imageHeight":230,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/adacb81f-a679-413e-8499-6005e1cc4b05.image.png","thumbnailWidth":162,"thumbnailHeight":230,"uuid":"NJEBu3CqFufkB37c"} +{"name":"43e3e1ea-297c-435c-8198-04760b9427f7.image.png","date":"2025-04-30T22:03:01.478Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/43e3e1ea-297c-435c-8198-04760b9427f7.image.png","type":"image/png","size":665522,"imageWidth":720,"imageHeight":946,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2F43e3e1ea-297c-435c-8198-04760b9427f7.image.png","thumbnailWidth":252,"thumbnailHeight":330,"uuid":"5wmKnV6rum0h1RL6"} +{"name":"nero-logo-text.png","date":"2025-05-08T22:09:22.513Z","url":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/nero-logo-text.png","type":"image/png","size":251897,"imageWidth":1920,"imageHeight":1080,"thumbnail":"https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/thumbnails%2Fnero-logo-text.png","thumbnailWidth":330,"thumbnailHeight":186,"uuid":"5IM9a5dDHFvQ4Qqa"} diff --git a/CHAT.txt b/CHAT.txt new file mode 100644 index 000000000..8da6eedfd --- /dev/null +++ b/CHAT.txt @@ -0,0 +1 @@ +leaked chat documente eith the develpoters of neroio the sequel \ No newline at end of file diff --git a/LICENSE b/LICENSE index 791d0c458..3c577b03e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,13 +1,24 @@ - DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE - Version 2, December 2004 +This is free and unencumbered software released into the public domain. -Copyright (C) 2004 Sam Hocevar +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. -Everyone is permitted to copy and distribute verbatim or modified -copies of this license document, and changing it is allowed as long -as the name is changed. +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. - DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. -0. You just DO WHAT THE FUCK YOU WANT TO. +For more information, please refer to \ No newline at end of file diff --git a/README.md b/README.md index fa25247ae..b992c6b79 100644 --- a/README.md +++ b/README.md @@ -1,48 +1,22 @@ -# Open Source Arras +# Nero.io 2 -Logo +Logo -![GitHub Release](https://img.shields.io/github/v/release/Taureon/aps-plus-plus) -![Discord](https://img.shields.io/discord/1004907608018264094) -![GitHub repo size](https://img.shields.io/github/repo-size/Taureon/aps-plus-plus) +![GitHub Release](https://img.shields.io/github/v/release/DELTAFYREX/neroio) +![Discord](https://img.shields.io/discord/1073429163823869952) +![GitHub repo size](https://img.shields.io/github/repo-size/DELTAFYREX/neroio) -**Open Source Arras is beta software.** This build is **not** representative of the final product. Expect bugs and missing features. +## Important Notice -Major updates may introduce breaking changes that alter how certain things work. It is **your responsibility** to keep your private server up-to-date and functioning. +**Nero.io is under constant development** This build is **not** a final product. -## Setup Guide (Localhost) +Bugs are likely common so expect the unexpected -This guide covers setting up your server on your own hardware and only supports PCs running up-to-date versions of Windows/macOS/Linux. +## Looking for other developers -You'll first need to install [Node.js](https://nodejs.org). It doesn't matter if you pick the LTS or Latest version, they'll both work fine. +Nero is a ~~two~~ three man project currently and any help would be appreciated greatly -Once `Node.js` is installed, open Terminal and run the command `npm i ws`. This will install the WebSocket library that Open Source Arras uses. - -After installing `ws`, [download the source code of the latest release of Open Source Arras](https://github.com/Taureon/aps-plus-plus/releases). Extract it once it's downloaded and open either `run.bat` (if you're on Windows) or `run.sh` (if you're not). If there aren't any errors, your server will start up. Go to `localhost:26301` in your favourite web browser (keep the terminal window open, closing it will shut down the server) to play. - -[If you need a more detailed guide, click here for a step by step list.](https://github.com/Taureon/aps-plus-plus/wiki/Frequently-Asked-Questions#how-do-i-set-up-my-server) - -If you want to stay up to date, fork this template, download a git client, and sync the fork whenever there's a major update. - -## Setup Guide (Webhost) - -Don't have a supported device or don't want to mess around with localhost? Get a webhost to do the dirty work for you. - -Create a new project and choose to import one from GitHub. When prompted for the URL of the repository, type in `https://github.com/Taureon/aps-plus-plus.git`. - -Navigate to `server/config.js` and replace `localhost:26301` with the URL for your project. (For Glitch users, it's `your-project.glitch.me` (replace `your-project` with the actual name of your project, it should be above settings)). - -**For Glitch specifically, go to `package.json` and replace `"node": "18.x"` with `"node": "16.x"` and change your port to something more generic like 3000 or 8080.** - -After doing that, your server should be ready! - -## Useful Tools -- [Create a custom shape](https://arras.io/ext/custom-shape) -- [Create a custom tank](https://zyrafaq.com/arras-tank-builder) -- [Official Addon list](https://github.com/Taureon/aps-plus-plus-addons) -- [Unofficial Server list](https://zyrafaq.com/arras-server-list/) +Join the discord server if your interested in helping out ## Other Links -- [Our Discord server](https://discord.gg/kvCAZfUCjy) - -*p.s. if something goes terribly wrong it's not our fault* +- [Our Discord server](https://discord.gg/GmhACsX9aF) \ No newline at end of file diff --git a/changelog preview b/changelog preview new file mode 100644 index 000000000..ba4c8af40 --- /dev/null +++ b/changelog preview @@ -0,0 +1,709 @@ +
+

Update 3.5

+ [2025] +
    +
  • Added 3 new tracks
  • +
  • slightly improved server loading
  • +
  • added water with physics
  • +
  • added minishot
  • +
  • added the minishot branches
  • +
  • added new 75 kill achivement
  • +
  • minos prime skin
  • +
  • nerfed firecracker
  • +
  • added new ffa map
  • +
  • addded the rest of the tier 3 upgrade variants for minishot to the rest of the tier 2 branches
  • +
  • added mini mortar variations of the t2 tanks
  • +
  • made assblasters back thruster bullets transparent
  • +
  • added submachine gun branch to machine gun
  • +
  • fixed date since creation counter turning to a year ahead when its not supposed to
  • +
  • added missing tanks to unavailable developer
  • +
  • added missing stat names to tanks
  • +
  • fixed turret danger values
  • +
  • fixed a bug where recoil wouldnt exist if upgrading from beyonet
  • +
  • removed scope from twiper
  • +
  • added flashfire
  • +
  • buffed firecrackers reload time
  • +
  • buffed shape health
  • +
  • added shadow
  • +
  • fixed Hypothermia not actually shooting ice traps
  • +
  • renamed acidilizer and icilizer to arsenic and devils breath
  • +
  • allowed you to set your tank to any entity via debug/wiki menu in sandbox
  • +
  • fixed the rocks not reflecting bullets in sandbox server
  • +
  • added numbers for health bar
  • +
  • buffed swarm tank damage by a multiplier of 2
  • +
  • nerfed flail damage from 3 to 1.95
  • +
  • buffed whirlwind damage from 1.875 to 4
  • +
  • buffed revolutionist turrets reload from 0.45 to 0.9
  • +
  • made jump smashers bullets half opacity
  • +
  • bayonet reload nerfed from 1 to 1.3
  • +
  • fixed cloner not cloning
  • +
  • nerfed probe cloning reload
  • +
  • buffed cloner branch cloning speed
  • +

    Ay, Anguish on that beat ho'

    +
+
+
+

Update 3.4

+ [2024] +
    +
  • buffed backshield
  • +
  • added slasher and attacker
  • +
  • readded trapception
  • +
  • added homing auto basic to desmos branch
  • +
  • made homing auto-2 upgrade from auto-3
  • +
  • removed auto-2 (except homing auto-2)
  • +
  • fixed upgrading issus
  • +
  • fixed kivaaritehdas
  • +
  • fixed trollface emoji
  • +
  • added sandbox mode
  • +
  • updated sound effects
  • +
  • fixed favicon not appearing on neroio.xyz
  • +
  • balanced rainmaker
  • +
  • fixed wall spawning shift key
  • +
  • added developer basic to testbed
  • +
  • removed mini defender
  • +
  • added ice Trapper branch
  • +
  • nerfed destroyer
  • +
  • nerfed repeater branch
  • +
  • added Kevin and Speed Triple
  • +
  • fixed visual bug with speedtriple
  • +
  • patched crash exploit
  • +

    RANDOM BULLSHIT, GO AGAIN!

    +
+
+
+

Update 3.3

+ [2024] +
    +
  • Added new server
  • +
  • changed menu layout
  • +
  • updated gamemodes
  • +
  • small fixes im too lazy to write
  • +
  • changed server box
  • +
  • small minion bugfixes
  • +
  • forgot to remove mace
  • +
  • dreads update
  • +
  • got rid of trilancer branch
  • +
  • dreadv1 changes
  • +
  • undertow update
  • +
  • removed a bunch of songs from ost
  • +
  • removed european server
  • +
  • updated credits
  • +
  • buffed albequerqe
  • +
  • fixed a bug where cloner hybrid did not show up when upgrading from cloner (dunno how i missed that)
  • +
  • removed ranch, marksman and cocci
  • +
  • fixed a bug where autocloner and cloner hybrid having instant clone respawn time
  • +
  • added visualizer to Nero brella
  • +
  • removed sidewinder
  • +
  • removed ceptions
  • +
  • nerfed auras (-100 aura points)
  • +
  • buffed surges emp attack
  • +
  • added choker
  • +
  • added X-Pathogen
  • +
  • added wyrm
  • +
  • added noble branch
  • +
  • added more descriptions
  • +
  • added gatling gun
  • +
  • removed more ceptions
  • +
  • removed aura branch from tier 1
  • +
  • removed auto branch from tier 1
  • +
  • removed hybrid branch from tier 1
  • +
  • removed flankinception branch
  • +
  • added more machceptioner upgrades
  • +
  • added 4 new ost tracks
  • +
  • fixed debug menu
  • +
  • makes shapes killed on run in debug menu reset on death
  • +
  • fixed solario bossfight
  • +
  • fixed bug where recoil doesnt work when upgrading from lancer tree
  • +
  • added charger
  • +
  • revolutionist now upgrades from whirlwind
  • +
  • saturn now upgrades from revolutionist
  • +
  • added formal dehyde and frostbite
  • +
  • buffed smashers
  • +
  • buffed skaters movement speed
  • +
  • gave pion the hadron ability and changed ring color to red
  • +
  • changed bayonet to tier 3
  • +
  • added icegun, fencer arisaka, wakazashi and fireblanket
  • +
  • removed mirror backshield
  • +
  • fixed death sounds
  • +
  • added wark branch
  • +
  • fixed auto2brid not having its main autocannon
  • +
  • fixed bug where scowerer and swivel2brid did not upgrade from its intended branches
  • +
  • fixed grazerbrid not having its autocannon
  • +
  • fixed the skype achievement
  • +
  • updated loading screen tooltips
  • +
  • fixed wark upgrades
  • +
  • nerfed solarios health from 8000 to 5500
  • +
  • nerfed solarios spin speed
  • +
  • disabled regen during solarios laser attack
  • +

    Big ass update :blehh:

    +
+
+
+

Update 3.2

+ [2024] +
    +
  • Fixed Undertow
  • +
  • Added Surge
  • +
  • Moved Music Checkbox
  • +
  • Bugfixes
  • +
  • Added Katana
  • +
  • Addded Risk Gamemode
  • +
  • Changed look of Revolutionist branch
  • +
  • Skin Issue Fix
  • +
  • Added Mini Defender
  • +
  • Integrated Lancer into Main & Added More Lancer Things
  • +
  • buffed kiva
  • +
  • menu tweaks
  • +
  • Added new servers and domain
  • +
  • Necromancer Rebalance + Gun Rework
  • +
  • Added more killstreak messages and an extra bonus at 100 kills :)
  • +
  • small server side optoimizations
  • +
  • added mobile controls :D (now you can play on the go)
  • +
  • added versitile switching from between pc and mobile controls in the menu
  • +
  • super huge bugfixes and balancing
  • +
  • fixed surge and added lancer range stat
  • +
  • fixed game crashing bug (i put two square brackets)
  • +
  • added respawn cooldown and tips n stuff
  • +
  • added /menu command
  • +
  • added custom keybinds
  • +
  • fixed bug where toggables do not work
  • +
  • fixed maze wall size bug
  • +
  • fixed death sound bug
  • +
  • fixed missing upgrades
  • +
  • added propel branch
  • +
  • added new extra tanks
  • +
  • added jouster branch
  • +
  • fixed mockups bug
  • +
  • balance changes and sidewinder branch rework
  • +
  • optimizations
  • +
  • record and screenshot
  • +
  • updated options ui
  • +
  • added extra gui and ui customization
  • +
  • added keybinds and mobile crosshair
  • +
  • nerfed cloner clone spawn time and added cockatiel
  • +
  • balanced propel stuff
  • +
  • added new server
  • +
  • boss stuff
  • +
  • tokay event + skin
  • +
  • finished solario boss
  • +
  • updated checkboxes
  • +
  • nerfed auras
  • +

    RANDOM BULLSHIT, GO!

    +
+
+
+

Update 3.1

+ [2024] +
    +
  • Fixed date since counter
  • +
  • Added BackShield & Mirror Shield
  • +
  • Fixed Tag Gamemode
  • +
  • Removed Stats Temporarily
  • +
  • Changed Bot Leveling
  • +
  • Nerfs & Buffs
  • +
  • Reorganized Entities
  • +
  • Added New Color System
  • +
  • Fixed Color System
  • +
  • New DFX Maze Map
  • +
  • Added Apotheosis V2 & Depredation Remastered V2 By Deltafyrex and Killa By Action Agenda (DFX Edit) To OST
  • +
  • Fixed Siege
  • +
  • Fixed Movement System
  • +
  • Fixed Death Sounds
  • +
  • Revamped Menu Popups
  • +
  • Added TwinSniper Branch And More to Acid And Chiller Branch
  • +
  • Fixed Music Bug, And Added Aura Basic, Jump Smasher And Whirlwind To The Main game
  • +
  • Fixed Shields
  • +
  • Moved Aura From Tier 3 To Tier 2 And Added Aura Branch
  • +
  • Added Flail & Buffed Auras
  • +
  • Added Firecracker, Douverie & Auto-2 Branch
  • +
  • Added Brella (upgrades from backshield) And Lancer Branch
  • +
  • Added More Options For Quality Of Life Features
  • +
  • Added New Achievements & Skins
  • +
  • Fixed Player Skin Bug
  • +
  • Fixed Color System Again And Added Glow + Nerfs/Buffs And other Bug Fixes
  • +

    Update 3.11 [2024]

    +
  • Fixed Desmos + 8 New OST Tracks
  • +
  • Added Music Selector And Fixed Music Bugs
  • +
  • Added In Game Audio Visualizer
  • +
  • Fixed Server Selector
  • +
  • Added A Beta Cocci
  • +
  • Small Menu & Ui Updates
  • +
  • Fixed Desmos AI Bug & Undertow
  • +
  • Nerfed Some Things
  • +

    Holay Molay

    +
+
+
+

Update 3.0

+ [2024] +
    +
  • Added Clubbin
  • +
  • Testing Achievements
  • +
  • Added Reset Achievements Button
  • +
  • Added Start Achievement
  • +
  • Added and Fixed Achievement Details
  • +
  • Added Disconnect, Lag, And Killstreak Achievement
  • +
  • Removed Kill Achievement cuz it dont work
  • +
  • Added New Special Achievement Type
  • +
  • Added Special Piss.io Achievement And Funny Skype Achievement
  • +
  • Re-Added And Fixed 5 Killstreak Achievement Again
  • +
  • Added Server to Client Functions
  • +
  • Added 10 Killstreak Achievement
  • +
  • Changed Debug Menu
  • +
  • Added Kill Amount In Debug
  • +
  • Added Audio Visualizer in the title screen
  • +
  • Fixed Embed Not Working Properly
  • +
  • Fixed Bug Where Audio Visualizer Appears In Game
  • +
  • Added Token And Discord Achievement
  • +
  • Added Achievements Tab
  • +
  • Removed Ach Testing
  • +
  • Added Credits Button
  • +
  • fixed credits interfering with changelog
  • +
  • added credits-changelog animation transition
  • +
  • moved credits button (its 1:08 am im soooooo tired)
  • +
  • Fixed Game Breaking Bug
  • +
  • Added Contagion Branch To Subduer & Trapper
  • +
  • Added Longing And Resurgam By Amaryllis To The OST
  • +
  • added credits ach
  • +
  • Added 2 New Branches For Desmos
  • +
  • Testing Skins
  • +
  • Added Beta Skin Menu
  • +
  • Fixed Skin Bug
  • +
  • Fixed Crashing On Respawn
  • +
  • Added More Detail To Skin Menu
  • +
  • Added Cat Code and Chickensandwhichman Skin
  • +
  • Added Daily Tanks
  • +
  • Added Plenty New Skins, New Achievements And Made Achievements Unlockable
  • +
  • Added Skater & Hitman
  • +
  • Added New "Duality" Map
  • +

    Update 2.93 [2024]

    +
  • David Goggins Event
  • +
  • Updated Menu
  • +
  • Added Marksman Branch To Sniper And Car Branch To
  • +
  • Added Trollface Emote (add --troll to the end of a chat message)
  • +
  • Added Waterfall, Acid, Cooler, Rainmaker And New Options Layout
  • +
  • Added Notes Tab + Live Counter
  • +
  • Added More Customization, Graphics, Helecopter And Fixed Music Bug
  • +
  • Added Reverie Branch And Injector
  • +
  • Added Debugger Menu
  • +
  • You Can Now Color Messages With §
  • +

    Niners fucking lost Again Bruh...Fuck Taylor Swift

    +
+
+
+

Update 2.9

+ [2024] +
    +
  • Added Motor
  • +
  • Added Kivaaharatedas (i did not spell that right)
  • +
  • Added Equilibrium, Revobrid, Subverter
  • +
  • shrapnel testing
  • +
  • removed unfinished aimbot/boosting testing
  • +
  • Added Basic Hybrid Tier 3 branch
  • +
  • Bug Fixed Colors
  • +
  • Added Tanks of my friends and tank soundboard support
  • +
  • Added the rest of the Basic Hybrid branch (tier 4)
  • +
  • Fixed changelog not appearing
  • +
  • Added beta music support including 5 songs
  • +
  • changed start button look to not shade out and actually work like a button
  • +
  • fixed debug key (again)
  • +
  • fixed screen tearing
  • +
  • worked bullet spawn position
  • +
  • Better organized dev menu and changed the way utilities looks
  • +
  • Added music recognition in the debug key to see the song name & artist
  • +
  • Added new song (Anybody can find Love (except You) by hkmori
  • +
  • fixed debug not recognizing a song and not updating after a song is finished
  • +
  • Testing wall colors/effects
  • +
  • Added Shield Turrets
  • +
  • Added new tiles (dance floor+black)
  • +
  • added new "banquet" map
  • +
  • Finished Revolutionist Branch
  • +
  • Added Inception & Albuquerque
  • +
  • im a fucking moron
  • +
  • Added Machceptioner & Tailgator
  • +
  • Added Interceptor, Twinceptioner, Inceptionist branch, hybrid/auto ver of inception branch
  • +
  • Added Desmos/Inception/Bascrid Ception
  • +
  • fixed the ceptionist turrets/autobullet turrets
  • +
  • nerfed shit
  • +
  • fixed some upgrades not appearing
  • +
  • no players (dead game and nobody plays is sadly)
  • +
  • so it turns out i forgot to give twinceptionist the right bullets so i fixed that :/
  • +
  • fixed flankcept branch turrets
  • +

    Update 2.91 [2024]

    +
  • Added the subduer branch
  • +
  • Fixed The Rest of the menu buttons and fixed sound effects
  • +
  • Added flankduer
  • +
  • Added Binary branch, Pathogen branch, mitochondrion branch, Subduer-Hybrid branch and Auto-Subduer Branch
  • +
  • fixed missing upgrades
  • +

    Hey! vsauce, Michael here. the game is stable and non buggy...or is it?

    +
+
+
+

Update 2.8

+ [2023] +
    +
  • Tank Adding Wave Two (ex. hadron, dictator, railgun + more)
  • +
  • Debug Key Bug Fix (how ironic)
  • +
  • Fixed Rng Images Bugging Out
  • +
  • Testing Whirlwind Branch
  • +
  • Fixed Maze Gamemode
  • +
  • Added Tooltips (beta)
  • +
  • Added Status Effects (beta+devevent)
  • +
  • Added Addon Support
  • +
  • Fixed button Shadows
  • +
  • Upgraded APS++ Updating Speed
  • +
  • New Mouse Controller
  • +
  • Keybind Fix
  • +
  • Enter can cancel a chat message being sent
  • +
  • CoNgReGaTiOn JuMpScArEs
  • +
  • Images on Tanks/Sound Effects For Tanks (dev)
  • +
  • Blackhole (dont ask just roll with it)
  • +
  • P A P Y R U S
  • +
  • Fixed Some Lag Holding Down Server Speed
  • +
  • 109.43.21.5.14
  • +
  • Added Desmos Branch
  • +
  • Theres Prob More But I Forgor
  • +

    wahhh... (i forgor why im crying)

    +
+
+
+

Update 2.7

+ [2023] +
    +
  • Debuffed Many Tanks
  • +
  • Migrated to new host
  • +
  • Removed all Nero Exclusive Tanks From The Game (for now anyway, dont worry)
  • +
  • Added "revolutionist" to testbed"
  • +
  • Massive Testbed overhaul
  • +
  • Added a funny randomly generated image on the start screen
  • +
  • Readded Sounds, design and other previous widgets
  • +
  • Hired new devs
  • +
  • did some tweaks to bots
  • +
  • got rid of the "nero" theme and the server list
  • +
  • added easter eggs
  • +
  • added random funny image
  • +

    Update 2.71 [2023]

    +
  • Tank Adding Wave One (ex. auto branch, revolutionist, cloner + more)
  • +
  • plenty of new dev features
  • +
  • added gamemode polls (once theres enough people)
  • +

    There are Easter Eggs All Over The Main Menu, You Might Find Something...

    +
+
+
+

Update 2.6

+ [2023] +
    +
  • replaced smashers origional upgrade path with the "armoury" tree -added lancer and smasher upgrades to armoury tree
  • +
  • added "Sword", "Injector" and "Fencer" to lancer upgrades
  • +
  • buffed drone tanks, twin tanks & tank health
  • +
  • added "Dictator" -added "Tripwire"
  • +
  • added "Barricade", "Twister", "Cyclone" and "Architect" -added "Tri-Trapper" tree -added "auto tritrapper", "auto armour" and "autolancer"
  • +
  • added "eagle" and "bulwark"
  • +
  • updated debug menu
  • +
  • removed hivemind from basic
  • +
  • added cloner upgrade
  • +
  • added hivemind and "splitter" to cloner upgrade
  • +
  • added "auto cloner", "auto flamethrower", "flamethrower hybrid" and "lancer hybrid"
  • +
  • updated colorscheme and other color related things
  • +
  • updated teams on 2tdm after 3 team bug -added all new Rock Maze gamemode
  • +

    Ryerson Loves Burger King

    +
+
+
+

Update 2.5

+ [2023] +
    +
  • added new tanks into beta for further testing
  • +
  • hired new devs
  • +
  • neroio discord is up
  • +
  • added new mascallenus tank and section
  • +
  • hired new beta testers
  • +
  • added new easter eggs
  • +
  • tested 2nd server opening
  • +
  • added "Scanner" and "hadoken"
  • +
  • nerfed Hahaugobrr
  • +
  • promoted lucas medieros to co-owner of the game
  • +
  • demoted a few staff
  • +
  • added 2TDM game mode
  • +
  • woomy event is back! now with free access to testbed
  • +
  • added "flankdrive", "twindrive" and "machinedrive"
  • +
  • fixed trapper look
  • +
  • added "infantry", "musket", "Traprid", "Auto Traprid", "Snigrav", "AsWdragafora", "Assasolak", "Builifacate", "Rifagiulus", "Auto Snigrav"
  • +
  • added "flamethrower", "Baker", "Wildfire" and "Equinox"
  • +
  • new nero.io default theme instead of using arras's
  • +
  • added insane af tanks to testbed
  • +
  • added "lancer"
  • +

    Open Na Noor

    +
+
+
+

Update 2.4

+ [2023] +
    +
  • added 2 new admin commands
  • +
  • added homing auto Basic
  • +
  • added bosses tab to AIT
  • +
  • bwomp AA $$ €€
  • +
  • added easter egg name colors
  • +
  • added the tanks "mercury", "venus", "earth", "mars", "jupiter", "saturn", "uranus", and "neptune"
  • +
  • added a new boss
  • +
  • added more natural spawning bosses
  • +
  • added "SpawnTrap"
  • +
  • updated bot names
  • +
  • ended woomy event
  • +

    Oh great red Text of the Changelog, What is your Wisdom?

    +
+
+
+

Update 2.3

+ [2023] +
    +
  • added "maleficator", "stalker", "landmine", "jumpsmash", "speedbent", "heavy3", and re-added "twindrive", "interceptioner", the "drive" subtree to autobasic, plus increased map size
  • +
  • fixed and debuffed jumpsmash
  • +
  • debuffed speedbent
  • +
  • added a public changelog (the one your looking at now)
  • +
  • added the red text
  • +
  • updated sounds and styles
  • +
  • added the "corrupted" button
  • +

    So Hows Ur Day?

    + +
+
+
+

Update 2.2

+ [2023] +
    +
  • added more tanks into beta
  • +
  • added sounds and updated client backround
  • +
  • Decoration finished
  • +
  • started decoration on migration host
  • +
  • added chat feature
  • +
  • migration big fixes
  • +
  • WE DID IT! MIGRATION COMPLETE!
  • +
  • during migration found multiple small bugs that was fixed
  • +
  • 2nd failed migrating attempt, starting yet another
  • +
  • fixed crashing bug
  • +
  • 2nd attempt at migrating
  • +
  • added random bot and skill classes
  • +
  • made bots more op
  • +
  • fixed a bot bug
  • +
  • downgraded bots
  • +
  • added tank visualizers
  • +
  • buffed bots a tiny bit more
  • +
  • fixed visualizer bug
  • +
  • added "rifle"
  • +
  • fixed "lilfact" upgrade path
  • +
  • added auto "lilfact"
  • +
  • renamed "lilfact" to "spawner"
  • +
  • added secret tanks for update 2.3
  • +
  • minor crash bug fixes
  • +
  • removed "rifle" and "autospawner" from beta
  • +
  • fixed smasher bug
  • +
  • failed "lancer" class attempt
  • +
  • secret tank updates
  • +
  • major bug fixes
  • +
  • rainbow color old client fix
  • +
  • last patches before big update
  • +
  • fixed tiny bug
  • +

    I Know Where You Live

    +
+
+
+

Update 2.1

+ [2022] +
    +
  • fixed the 2 game crashing bugs
  • +
  • tried to migrate to another server host but yet failed due to unknown reasons
  • +
  • added "speedbent" to beta
  • +
  • updated messages
  • +

    tbh im sad the 49ers missed the super bowl :/

    +
+
+
+

Update 2.0

+ [2021] +
    +
  • brought the ception tree into beta tanks
  • +
  • figured out that the "ceptions" arent really ceptions
  • +
  • forgot to add the actual way to access it LOL, also added a REAL machine ceptionist as a test
  • +
  • removed ceptionist and drive tanks as they are too overpowered
  • +
  • added lazer guns
  • +
  • stole code from someone elses server
  • +
  • added beta shock and burn
  • +
  • added some secret really stupid tanks
  • +
  • fixed a tank
  • +
  • removed revolutionist for being too buggy
  • +
  • added new auto class branch
  • +
  • added hivemind
  • +
  • bug fixes
  • +
  • major bug that caused no tanks to be added or bugs fixed causing confusion
  • +
  • crashing bug made game unplayable for large amount of time (like a whole 9 months)
  • +

    Whats Up Guys Quandale Dingle Here

    +
+
+
+

Update 1.9

+ [2021] +
    +
  • testing in progress
  • +
  • approved multiple tanks into the game
  • +
  • did some stupidity and added random stuff and figured out that there is indeed, 12882 lines of code in this project
  • +
  • added some dumb tanks like "mInIfLyInGfAsTeRtHiNgY"
  • +
  • added some cool colored objects on the "AsWdWsA" branch
  • +
  • added a secret tank
  • +
  • messed with some things like homing bullets
  • +
  • removed the homing stuff due to bugs
  • +
  • tried to recreate the "revolutionist" tank from woomy arras
  • +
  • more tests
  • +
  • added auto bullets
  • +
  • added drive tanks into beta testing phase
  • +
  • moved where the secret tank is
  • +
  • debuffed "single"
  • +
  • added "Cascal", "Gunto", "Catalyst", And "Cescav" to beta tanks
  • +
  • added a beta version of the drive tree into the game after some testing
  • +

    What A Dumb Fucking Game!

    +
+
+
+

Update 1.8

+ [2021] +
    +
  • completed and put the poison function into the game
  • +
  • completed and put the freeze function into the game
  • +
  • created a seprate freeze and poison bullets
  • +
  • added a stun function
  • +
  • added a healing and speed function
  • +
  • added a stun, healing and speed bullet shooting tanks
  • +
  • added the "AsWdWsA" branch
  • +
  • fixed poison cannon
  • +
  • renamed the bullets to respected name
  • +
  • renamed the cannons to a respected name
  • +
  • created a page 2 for the mascallenus
  • +
  • put multitanks into testbed
  • +
  • put multitanks into testbed
  • +
  • organized the tanks
  • +
  • removed public testbed
  • +

    :skull:

    +
+
+
+

Update 1.7

+ [2020] +
    +
  • added an admin logger
  • +
  • changed the AI color to pink
  • +
  • changed AI to have twin upgrade instead of basic
  • +
  • expanded the map
  • +
  • changed the colors of the spawning player to be random instead of always red or blue
  • +
  • added the tanks "oof" and "oof2" to mascallenus
  • +
  • added the tank "minibee" to testbed
  • +
  • added the tank "hexa trapper" into the game
  • +
  • added the tank "Paint Brush" into the crayon tree
  • +
  • added the tank "brutalizer"
  • +
  • added "sidewinder"
  • +

    Share with your friends!

    +
+
+
+

Update 1.6

+ [2020] +
    +
  • added the tank "tower mech"
  • +
  • added the "AIT" category into testbed
  • +
  • added a way to get back to a basic tank after becoming testbed
  • +
  • added the tank "crayon"
  • +
  • added the two tanks "marker" and "pastel"
  • +
  • added the tank "pen"
  • +
  • added a kill button to testbed
  • +
  • added the tank "highlighter"
  • +
  • added a way to immediatly upgrade into a basic trapper
  • +
  • invited some friends to help code my game
  • +

    Yo shout out to Lucas Medeiros

    +
+
+
+

Update 1.5

+ [2020] +
    +
  • removed jesus donut
  • +
  • removed DeltaCannon
  • +
  • fixed some bugs with AI's
  • +
  • fixed some bugs with crashers and bosses
  • +
  • added a bunch of testbed tanks into the real thing
  • +
  • removed fairsquare
  • +
  • added flame killa to testbed
  • +
  • removed access to the recently added tanks from testbed to save space
  • +
  • added Boxer to testbed
  • +
  • removed every testbed tank
  • +
  • added categories to test bed like "beta" and "mascallenus"
  • +

    come down today and try some corn, or we will sacrifice your newborn

    +
+
+
+

Update 1.4

+ [2020] +
    +
  • added Lottery to testbed
  • +
  • added hellblazer and Rocketer to testbed
  • +
  • added Nautilus to testbed
  • +
  • added jesus donut to testbed
  • +
  • experimented with bullet effects
  • +
  • added SleamShot
  • +
  • added TrapHard into testbed
  • +

    LMFAO WHAT A BOZO

    +
+
+
+

Update 1.3

+ [2020] +
    +
  • added master
  • +
  • added lilfact
  • +
  • fixed bug with bots
  • +
  • fixed bug with lilfact
  • +
  • ADDED PUBLIC TESTBED
  • +
  • fixed some bugs
  • +
  • fixed testbed problems
  • +
  • fixed testbed key errors regarding platform
  • +
  • added helltank to testbed
  • +
  • added DeltaCannon to testbed
  • +

    DrUgS aRe BaD fOr YoU1!1!

    +
+
+
+

Update 1.2

+ [2020] +
    +
  • server shutdown due to server problems
  • +
  • fixed problem
  • +
  • fixed some more bugs
  • +
  • fixed bug with the upgrades
  • +
  • added 3 pre-made extra tanks (hive shooter, auto assassin, auto cruiser)
  • +
  • added Unlocked
  • +
  • added more ways to get hive shooter
  • +
  • added more ways to get unlocked
  • +
  • added bots
  • +
  • fixed bad bug with Unlocked
  • +

    tbh play a better game than this

    +
+
+
+

Update 1.1

+ [2019] +
    +
  • added revix
  • +
  • added DeltaGunner
  • +

    OH BABY A TRIPLE

    +
+
+
+

Update 1.0

+ [2019] +
    +
  • just opened server
  • +
  • testing new tanks
  • +

    Bwomp

    +
+
+You've Reached The End ?̵̛̤̱̯͕̠̘̬̦̟̼̏͆̍̋̀̃͋͑̈́̂̎̉͒́̇̋͗̆͗̿́́̃́͗̉̈́̓̓͒̑̌͊̎͗̕̚̕͜͠͠͝͠͠?̵̧̢̨͉̹̥̩͕͙̦̞̹͙̣̱̪̫͚͚̋͐̒͐̈́͠?̶̡̢͈̮͉͕̩̣̘͚̳̳̺̹̜̺̹͙̼̤̼̱̣̭̪̘̖̊̅̽̃̎͋̽̇͂͆̽̃̇̏͒͋͗̾̀̉̐͘͜͠?̷̧̧̨̡̛̛̪̠̝̖̪̖͓̝̖̣͖͚̖̗̼̬̯̦̹̯͖̮̥͚͓̙͇̥̼͍̠̟̙̫̫̞̆̔́̊̆̓̿́̑̇̅̄̀̑̄̇̆̀̓͐̾̄̽̒̃͝͝ͅ?̶̢̧̢̢̧̧̛̣̳̮̝̳̞̞̙̟͓̝̬̤͎̂͛͆̓͑̌͌̂̽ \ No newline at end of file diff --git a/features.md b/features.md index 0ffa3a086..cbd7d12bc 100644 --- a/features.md +++ b/features.md @@ -174,7 +174,7 @@ It includes all features up to the latest release version. * Definitions Management * Split up into numerous other files, all located in `server/modules/definitions`. * Entity definitions are in `/groups`. - * "Facilitators" (makeAuto, combineStats, etc.), constants and gun values are in their own files. + * "Facilitators" (makeHybrid, combineStats, etc.), constants and gun values are in their own files. * As a requirement, you can now put `"strings"` as references instead of `Class.entity` references. * Added definition flattening, which would improve performance a bit by applying `PARENT`'s definitions directly to the definition. * Definition flattening also checks for entities that do not exist. @@ -275,4 +275,4 @@ It includes all features up to the latest release version. * Dominator Game Mode. * Doesn't kick for invalid tokens, instead just does not give any perms. * Level Bar now shows max level if you have exactly enough score to reach that level. -* Large `SHAPE`s now work. +* Large `SHAPE`s now work. \ No newline at end of file diff --git a/install.sh b/install.sh old mode 100755 new mode 100644 index b4847ba0a..ceab25054 --- a/install.sh +++ b/install.sh @@ -15,4 +15,4 @@ else else echo "Error occurred during installation." fi -fi +fi \ No newline at end of file diff --git a/neroplayer/script.js b/neroplayer/script.js new file mode 100644 index 000000000..f947ac1ff --- /dev/null +++ b/neroplayer/script.js @@ -0,0 +1,86 @@ +window.onload = function() { + + //Music functions: + //decide the music + var music2 = new Audio(); + const pmusic = ["https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/oioioi.mp3?v=1705286830033", "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/4Miklipi%20(Dejected)%20Preview.mp3?v=1705287022417", "https://cdn.glitch.me/5fc7dcb6-aada-495b-828e-66901a470a29/World's%20End.wav?v=1705286889038", "https://cdn.glitch.global/f80d3eec-1e99-4b8c-b120-79a55addacf9/Meloncholy.mp3?v=1675465750213","https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Depredation.mp3?v=1705286866890", "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/videoplayback.mp3?v=1705807057028"]; + var randmusic = pmusic[~~(Math.random() * pmusic.length)]; + music2.src = (randmusic); + //load the play functions for itasdasf meow + function PlayMusic() { + music2.load(); + music2.play(); +} + +//actually play the audio when the checkbox is clicked on (checked) and stop it when unchecked +/* document.getElementById("optSound").onclick = () => { + if (document.getElementById("optSound").checked === true) { + global.music2.play() + global.music2.addEventListener('ended', function() {this.currentTime = 0; global.music2.src = pmusic[~~(Math.random() * pmusic.length)]; this.play();}, false); + } else if (document.getElementById("optSound").checked === false) { + global.music2.pause() + global.music2.songname = "Not Playing"; + } + return; };*/ + + var checkbox = document.getElementById("optSound"); + var audio = document.getElementById("audio"); + +checkbox.onclick = function() { + audio.src = randmusic; + audio.load(); + audio.play(); + var context = new AudioContext(); + var src = context.createMediaElementSource(audio); + var analyser = context.createAnalyser(); + + var canvas = document.getElementById("canvas"); + canvas.width = window.innerWidth; + canvas.height = window.innerHeight; + var ctx = canvas.getContext("2d"); + + src.connect(analyser); + analyser.connect(context.destination); + + analyser.fftSize = 256; + + var bufferLength = analyser.frequencyBinCount; + console.log(bufferLength); + + var dataArray = new Uint8Array(bufferLength); + + var WIDTH = canvas.width; + var HEIGHT = canvas.height; + + var barWidth = (WIDTH / bufferLength) * 2.5; + var barHeight; + var x = 0; + + function renderFrame() { + requestAnimationFrame(renderFrame); + + x = 0; + + analyser.getByteFrequencyData(dataArray); + + ctx.fillStyle = "#000"; + ctx.fillRect(0, 0, WIDTH, HEIGHT); + + for (var i = 0; i < bufferLength; i++) { + barHeight = dataArray[i]; + + var r = barHeight + (25 * (i/bufferLength)); + var g = 250 * (i/bufferLength); + var b = 50; + + ctx.fillStyle = "rgb(" + r + "," + g + "," + b + ")"; + ctx.fillRect(x, HEIGHT - barHeight, barWidth, barHeight); + + x += barWidth + 1; + } + } + + audio.play(); + renderFrame(); + }; +}; \ No newline at end of file diff --git a/neroplayer/stylesheet.css b/neroplayer/stylesheet.css new file mode 100644 index 000000000..c6218fa18 --- /dev/null +++ b/neroplayer/stylesheet.css @@ -0,0 +1,14 @@ +#canvas { + position: fixed; + left: 0; + top: 0; + width: 100%; + height: 100%; +} + +audio { + position: fixed; + left: 10px; + bottom: 10px; + width: calc(100% - 20px); +} \ No newline at end of file diff --git a/neroplayer/visual.html b/neroplayer/visual.html new file mode 100644 index 000000000..90658cec2 --- /dev/null +++ b/neroplayer/visual.html @@ -0,0 +1,166 @@ + + + + + Audio Visualizer + + +
+ + +
+
+ + + + + + + + + \ No newline at end of file diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 907707baa..000000000 --- a/package-lock.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "name": "arras", - "version": "1.0.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "arras", - "version": "1.0.0", - "license": "GPL-3.0", - "dependencies": { - "ws": "^8.13.0" - }, - "engines": { - "node": "16.x" - } - }, - "node_modules/ws": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", - "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - } - }, - "dependencies": { - "ws": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", - "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", - "requires": {} - } - } -} diff --git a/package.json b/package.json index 68119883e..3217ba878 100644 --- a/package.json +++ b/package.json @@ -6,15 +6,16 @@ "startOptimized": "node --optimize-for-size --no-lazy --gc_interval=120 server/index", "restartOnSaveOptimized": "node --optimize-for-size --no-lazy --gc_interval=120 --watch server/index", "start": "node server/index", + "startClient": "node public/index", "restartOnSave": "node --watch server/index", "host": "node standaloneClient/index", "build": "node standaloneClient/build minify" }, "dependencies": { - "ws": "^8.13.0" + "ws": "^8.18.1" }, "engines": { - "node": "18.x" + "node": "16.x" }, "license": "GPL-3.0" -} +} \ No newline at end of file diff --git a/public/app.js b/public/app.js index af49506b8..d2bb5bfe8 100644 --- a/public/app.js +++ b/public/app.js @@ -6,7 +6,9 @@ import { settings } from "./lib/settings.js"; import { Canvas } from "./lib/canvas.js"; import { color } from "./lib/color.js"; import { gameDraw } from "./lib/gameDraw.js"; +import { tankdescs } from "./lib/tankdesc.js"; import * as socketStuff from "./lib/socketInit.js"; + (async function (util, global, settings, Canvas, color, gameDraw, socketStuff) { let { socketInit, gui, leaderboard, minimap, moveCompensation, lag, getNow } = socketStuff; @@ -19,7 +21,790 @@ let { socketInit, gui, leaderboard, minimap, moveCompensation, lag, getNow } = s // document.getElementById("patchNotes").innerHTML += `
${changelog[0][0].slice(1).trim()}: ${changelog[0].slice(1).join(":") || "Update lol"}
    ${changelog.slice(1).map((line) => `
  • ${line.slice(1).trim()}
  • `).join("")}

`; // } // }); + var playbuttonsound = new Audio(); + playbuttonsound.src = + "https://cdn.glitch.global/f80d3eec-1e99-4b8c-b120-79a55addacf9/op1.wav?v=1675463613542"; + function PlaySound69() { + playbuttonsound.play(); + } + var clicked = false; + + var slap = new Audio(); + slap.src = + "https://cdn.glitch.global/f80d3eec-1e99-4b8c-b120-79a55addacf9/(Audio)%20videoplayback.m4a?v=1675999054321"; + function PlaySound68() { + slap.play(); + } + + var vsau = new Audio(); + vsau.src = "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/jake-chudnow-edited_y1t8j5q.mp3?v=1706018057534" + function PlaySound99() { + vsau.play(); + } + + var clicksound = new Audio(); + clicksound.src = + "https://cloud-cube.s3.amazonaws.com/m660o440l0wv/public/sysse_ok.ogg"; + function PlaySound210() { + clicksound.play(); + } + + var trapperclosely = new Audio(); + trapperclosely.src = ("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/look_closely.mp3?v=1705291786778"); + function PlaySoundtrap() { + trapperclosely.play(); + } + + var waterflush = new Audio(); + waterflush.src = ("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/toilet_flush.mp3?v=1705296502578"); + function PlaySoundwater() { + waterflush.play(); + } + + var undadewatuh = new Audio(); + undadewatuh.src = ("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/y2mate_HOnnyD0.mp3?v=1705296505126"); + function PlaySoundwatuh() { + undadewatuh.play(); + } + + var piss = new Audio(); + piss.src = ("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/flowing-water-sound-effect.mp3?v=1705299861150"); + function PlaySoundpiss() { + piss.play(); + } + + var pew = new Audio(); + pew.src = ("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/pew_pew-dknight556-1379997159.mp3?v=1705299975747"); + function PlaySoundpew() { + pew.play(); + } + var chipi = new Audio(); + chipi.src = ("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/chipi-chipi-chapa-chapa.mp3?v=1705302832837"); + function PlaySoundchipi() { + chipi.play(); + } + var neko = new Audio(); + neko.src = ("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/neko-arc.mp3?v=1705302835953"); + function PlaySoundneko() { + neko.play(); + } + var bwomp = new Audio(); + bwomp.src = ("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/bwomp.mp3?v=1705302839344"); + function PlaySoundbwomp() { + bwomp.play(); + } + var nfl = new Audio(); + nfl.src = ("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/nfl.mp3?v=1705302843389"); + function PlaySoundnfl() { + nfl.play(); + } +var open = new Audio(); +open.src = ("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/close.wav?v=1733614044438"); +function PlaySoundOpen() { + open.play(); +} +var close = new Audio(); +close.src = ("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/open.wav?v=1733614039155"); +function PlaySoundClose() { + close.play(); +} + function doSomething() { + if (clicked) { + var optionclicksound = new Audio(); + optionclicksound.src = + "https://cloud-cube.s3.amazonaws.com/m660o440l0wv/public/cancel.wav"; + optionclicksound.load(); + optionclicksound.play(); + } else { + clicksound.load(); + clicksound.play(); + } + clicked = !clicked; + } + + var smallaudio2 = new Audio(); + smallaudio2.src = + "https://cloud-cube.s3.amazonaws.com/m660o440l0wv/public/error.ogg"; + function PlaySound211() { + smallaudio2.play(); + } + + var smallaudio3 = new Audio( + "https://cloud-cube.s3.amazonaws.com/m660o440l0wv/public/socket.wav" + ); + smallaudio3.loop = false; + function PlaySound212() { + smallaudio3.loop = false; + smallaudio3.play(); + } +var killvariablenamething = true; +let metalpipe = new Audio(); +metalpipe.loop = false; +var randomdeathsound = ["https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/metal-pipe-clang.mp3?v=1710271073637", "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/undertakers-bell_2UwFCIe.mp3?v=1710268959839", "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/aaaaaaaa-online-audio-converter_r9waVUO.mp3?v=1710271069219", "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/vine-boom.mp3?v=1710280969499", "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/tmp_7901-951678082.mp3?v=1710280974624", + "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/emotional-damage-meme.mp3?v=1710280979660", "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/discord-notification.mp3?v=1710280983356", "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/wrong-answer-sound-effect.mp3?v=1710280995813", "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/clash-royale-hog-rider.mp3?v=1710280999656", "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/goofy-ahh-car-horn-sound-effect.mp3?v=1710281004188", + "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/tf_nemesis.mp3?v=1710281009502", "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/chinese-rap-song.mp3?v=1710281015151", "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/fire-in-the-hole-geometry-dash.mp3?v=1710281020367", "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/water-on-the-hill.mp3?v=1710281027326", "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/taco-bell-bong-sfx.mp3?v=1710281032201", + "https://cdn.glitch.global/68f0db33-c86d-4aa5-9a35-a6750a92eae7/download.mp3?v=1699142486910", "https://cdn.glitch.global/68f0db33-c86d-4aa5-9a35-a6750a92eae7/spongebob-fail.mp3?v=1699146799125", "https://cdn.glitch.global/68f0db33-c86d-4aa5-9a35-a6750a92eae7/62640b13-df2b-47d8-a06e-fb63b7fbb06e.mp3?v=1699272890577", "https://cdn.glitch.global/68f0db33-c86d-4aa5-9a35-a6750a92eae7/f93f6d33-9dab-4e9d-aebb-917fe2d22982.mp3?v=1700153956047", "https://cdn.glitch.global/68f0db33-c86d-4aa5-9a35-a6750a92eae7/c647ea60-edf9-4bde-a0af-c49353593c7f.mp3?v=1700153959194", + "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/feet-gd.mp3?v=1710431699794", "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/bad-to-the-bone-meme.mp3?v=1710431694343", "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/spongebob-boowomp.mp3?v=1710431689245", "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/holy-moly-emoji.mp3?v=1710431682780", "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/dun_dun_1.mp3?v=1710431679063"]; +function PlaySound420() { + if (global.killsoundready) { + killvariablenamething = true; + getksound(); + } +} +function getksound() { + if (global.killsoundready) { + if (killvariablenamething) { + metalpipe.src = randomdeathsound[Math.floor(Math.random() * randomdeathsound.length)]; + metalpipe.play(); + global.killsoundready = false; + } + } +} + var grubhub = new Audio(); +grubhub.src = ("https://cdn.glitch.global/68f0db33-c86d-4aa5-9a35-a6750a92eae7/d318bd1e-5162-4fae-a757-5c350b16ccc9.mp3?v=1700153738394"); +function PlaySound169() { + grubhub.play(); +} + var smallaudio5 = new Audio(); + smallaudio5.src = + "https://cloud-cube.s3.amazonaws.com/m660o440l0wv/public/poka.wav"; + function PlaySound214() { + smallaudio5.play(); + } + var smallaudio6 = new Audio(); + smallaudio6.src = + "https://cloud-cube.s3.amazonaws.com/m660o440l0wv/public/finish.wav"; + function PlaySound215() { + smallaudio6.play(); + } + var camerasound = new Audio(); + camerasound.src = + "https://cloud-cube.s3.amazonaws.com/m660o440l0wv/public/camera.wav"; + function PlaySound213() { + camerasound.play(); + } +var checkList = document.getElementById('list1'); +checkList.getElementsByClassName('anchor')[0].onclick = function(evt) { + if (checkList.classList.contains('visible')) + checkList.classList.remove('visible'); + else + checkList.classList.add('visible'); +} + +var pmusic = new Array(); +pmusic.push("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/oioioi.mp3?v=1705286830033"); +pmusic.push("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Dejected.mp3?v=1705287022417"); +pmusic.push("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/WorldsEnd.mp3?v=1714399132177"); +pmusic.push("https://cdn.glitch.me/5fc7dcb6-aada-495b-828e-66901a470a29/Nero.wav?v=1727644028814"); +//if (localStorage.getItem("anybody" + 'Checked')) pmusic.push("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/anybody.mp3?v=1705807057028"); +//if (localStorage.getItem("resurgam" + 'Checked')) pmusic.push("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/resurgam.mp3?v=1708218475743"); +//if (localStorage.getItem("longing" + 'Checked')) pmusic.push("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/longing.mp3?v=1708218464295"); +pmusic.push("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Apotheosis.mp3?v=1713525419376"); +pmusic.push("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Action%20Agenda%20-%20Killa%20DFX%20Edit.mp3?v=1713352244240"); +pmusic.push("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Failed%20Connection.mp3?v=1727645304666"); +//if (localStorage.getItem("demol1sh" + 'Checked')) pmusic.push("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/demol1sh.mp3?v=1714414557787"); +//if (localStorage.getItem("demoli2h" + 'Checked')) pmusic.push("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/demoli2h.mp3?v=1714414714759"); +//if (localStorage.getItem("d3molish" + 'Checked')) pmusic.push("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/d3molish.mp3?v=1714414706958"); +//if (localStorage.getItem("souven1r" + 'Checked')) pmusic.push("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/souven1r.mp3?v=1714414684036"); +//if (localStorage.getItem("2ouvenir" + 'Checked')) pmusic.push("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2ouvenir.mp3?v=1714414700719"); +//if (localStorage.getItem("routine2" + 'Checked')) pmusic.push("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/routine2.mp3?v=1714414889291"); +//if (localStorage.getItem("routin3s" + 'Checked')) pmusic.push("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/routin3s.mp3?v=1714414850230"); +//if (localStorage.getItem("jitt3rs" + 'Checked')) pmusic.push("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/jitt3rs.mp3?v=1714414684287"); +pmusic.push("https://cdn.glitch.me/5fc7dcb6-aada-495b-828e-66901a470a29/Atomic.wav?v=1727644048951"); +pmusic.push("https://cdn.glitch.me/5fc7dcb6-aada-495b-828e-66901a470a29/Acension%20(Apotheosis%202).wav?v=1729515166145"); +pmusic.push("https://cdn.glitch.me/5fc7dcb6-aada-495b-828e-66901a470a29/Nadir%20(Apotheosis%203).wav?v=1729515170342"); +pmusic.push("https://cdn.glitch.me/5fc7dcb6-aada-495b-828e-66901a470a29/Methemphetaphacktomine.wav?v=1729515173719"); +pmusic.push("https://cdn.glitch.me/5fc7dcb6-aada-495b-828e-66901a470a29/Polychromatism.wav?v=1729515177274"); +pmusic.push("https://cdn.glitch.me/5fc7dcb6-aada-495b-828e-66901a470a29/Wednesday%2C%20Friday%20(1).wav?v=1736978399984"); +pmusic.push("https://cdn.glitch.me/5fc7dcb6-aada-495b-828e-66901a470a29/Heresy.wav?v=1736979337244"); +pmusic.push("https://cdn.glitch.me/5fc7dcb6-aada-495b-828e-66901a470a29/Reconstructed.wav?v=1736979424454"); + +//Music functions: + //decide the music + global.music2 = document.getElementById("audio"); + var randmusic = pmusic[~~(Math.random() * pmusic.length)]; + global.music2.src = (randmusic); + //load the play functions for itasdasf meow + function PlayMusic() { + global.music2.load(); + global.music2.play(); +} + let musicvolume = 0; + var analyser; + +//actually play the audio when the checkbox is clicked on (checked) and stop it when unchecked + $("#optSound").on("click", function() { + if (document.getElementById("optSound").checked === true) { + songrecog() + global.music2.play() + //if (global.ISTHEGODAMNFUCKINGGAMEON !== "yeah") { + document.getElementById("content").style.opacity = 0.5 + //audio.src = randmusic; + //audio.load(); + //audio.play(); + var musiccontext = new AudioContext(); + var musicsrc = musiccontext.createMediaElementSource(global.music2); + // var filter = musiccontext.createBiquadFilter(); + // musicsrc.connect(filter); + // filter.connect(musiccontext.destination); + var analyser = musiccontext.createAnalyser(); +// global.blackhole ? filter.type = "lowpass" : filter.type = "allpass"; + + let musiccanvas = document.getElementById("canvas"); + musiccanvas.width = window.innerWidth * 1.3; + musiccanvas.height = window.innerHeight; + var ctx3 = musiccanvas.getContext("2d"); + ctx3.clearRect(0, 0, WIDTHOFBAR, global.screenHeight); + + musicsrc.connect(analyser); + analyser.connect(musiccontext.destination); + + analyser.fftSize = 1024; + + var bufferLength = analyser.frequencyBinCount; + console.log(bufferLength); + + var WIDTHOFBAR = musiccanvas.width; + var HEIGHTOFBAR = musiccanvas.height; + + var dataArray = new Uint8Array(bufferLength); + + var musicbarWidth = (WIDTHOFBAR / bufferLength); + var musicbarHeight; + var barstuffx = 0; + + function renderFrame() { + + if (global.gameStart) { + analyser.fftSize = 32; + musiccanvas.width = window.innerWidth; + WIDTHOFBAR = musiccanvas.width; + musicbarWidth = (WIDTHOFBAR / bufferLength); + musiccanvas.height = window.innerHeight; + bufferLength = analyser.frequencyBinCount; + document.getElementById("canvas").style.border = "solid 7px #000000" + } + + let deviscale = window.devicePixelRatio + + requestAnimationFrame(renderFrame); + barstuffx = 0; + + analyser.getByteFrequencyData(dataArray); + + ctx3.fillStyle = "rgba(0,0,0,0.12)"; + ctx3.fillRect(0, 0, WIDTHOFBAR, global.screenHeight); + + for (var i = 0; i < bufferLength; i++) { + musicbarHeight = dataArray[i] * 2; + musicvolume = musicbarHeight; + + var b = musicbarHeight + (18 * (i/bufferLength)); + var r = 250 * (i/bufferLength); + var g = 50; + + ctx3.fillStyle = "rgb(" + r + "," + g + "," + b + ")"; + ctx3.fillRect(barstuffx, global.screenHeight - musicbarHeight * deviscale, musicbarWidth, musicbarHeight); + + barstuffx += musicbarWidth; + } + } + //audio.play(); + renderFrame(); + //} + global.music2.addEventListener('ended', function() {this.currentTime = 0; global.music2.src = pmusic[~~(Math.random() * pmusic.length)]; this.play(); songrecog();}, false); + } else if (document.getElementById("optSound").checked === false) { + document.getElementById("content").style.opacity = 0 + global.music2.pause() + global.music2.songname = "Not Playing"; + } + return; }); + + let counterthing = document.querySelector(".displaytest"); + let skinnamedisplay = document.querySelector(".displayskinname"); + let myImg = document.querySelector("#skinpreview"); + let lock = document.querySelector("#lockedskin"); + let selectimage = document.querySelector("#selectskin"); + + $("#rightarrowbutton").on("click", function() { + if (global.skinpage === 18) { + global.skinpage = 0; + } else { + global.skinpage += 1; + }; + changeskinpreview(); + }); + $("#leftarrowbutton").on("click", function() { + if (global.skinpage === 0) { + global.skinpage = 18; + } else { + global.skinpage -= 1; + }; + changeskinpreview(); + }); + + $("#selectskin").on("click", function() { + if (global.lockedornot === 0) { + global.skin = global.selectedskin; + selectimage.src = "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/selected.png?v=1708718268075"; + } else { + selectimage.src = "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/locked!.png?v=1708718075601"; + } + }) + + + function checkifachieve(ach, lockcolor) { + if (global.selectedskin !== "") { + if (localStorage.getItem(ach) === "YOUDIDIT:D!!!") { + global.lockedornot = 0; + lock.style.display = 'none'; + myImg.style.filter = 'brightness(1)'; + updateskinselectbutton(); + } else { + global.lockedornot = 1; + selectimage.src = "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/locked!.png?v=1708718075601"; + lock.style.display = 'inline-block'; + myImg.style.filter = 'brightness(0.5)'; + if (lockcolor === "white") { + lock.style.filter = 'invert(1)'; + } else if (lockcolor === "grey") { + lock.style.filter = 'invert(0.7)'; + } else if (lockcolor === "dgrey") { + lock.style.filter = 'invert(0.3)'; + } else { + lock.style.filter = 'invert(0)'; + } + } + } else { + lock.style.display = 'none'; + if (global.skin === global.selectedskin) { + selectimage.src = "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/selected.png?v=1708718268075"; + } else { + global.skin === global.selectedskin + selectimage.src = "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/select.png?v=1708718071992"; + }; + } +} + + function updateskinselectbutton() { + if (global.lockedornot === 0) { + if (global.skin === global.selectedskin) { + selectimage.src = "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/selected.png?v=1708718268075"; + } else { + selectimage.src = "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/select.png?v=1708718071992"; + } + } else { + selectimage.src = "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/locked!.png?v=1708718075601"; + } + } + + function changeskinpreview() { + if (global.skinpage === 0) { + counterthing.textContent = "◉ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○"; + global.selectedskin = ""; + skinnamedisplay.textContent = "Default"; + checkifachieve("", ""); + myImg.src = "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/onetransparentsingulardamnfuckingpixel.png?v=1708568179353"; + } + if (global.skinpage === 1) { + counterthing.textContent = "○ ◉ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○"; + global.selectedskin = "bsignalskin"; + skinnamedisplay.textContent = "Broken Signal"; + checkifachieve("disconnectachievement", "black"); + myImg.src = "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/tv.png?v=1708615075011" + } + if (global.skinpage === 2) { + counterthing.textContent = "○ ○ ◉ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○"; + global.selectedskin = "tankcharmskin"; + skinnamedisplay.textContent = "Tank Charm"; + checkifachieve("25killsachievement", "dgrey"); + myImg.src = "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2024_01_29_0ry_Kleki.png?v=1708536680813"; + } + if (global.skinpage === 3) { + counterthing.textContent = "○ ○ ○ ◉ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○"; + global.selectedskin = "dfxskin"; + skinnamedisplay.textContent = "Deltafyrex"; + checkifachieve("50killsachievement", "grey"); + myImg.src = "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/MOSHED-2023-12-14-17-8-14.gif?v=1708618924966"; + } + if (global.skinpage === 4) { + counterthing.textContent = "○ ○ ○ ○ ◉ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○"; + global.selectedskin = "primalskin"; + skinnamedisplay.textContent = "Ultimate Primal"; + checkifachieve("100killsachievement", "white"); + myImg.src = "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/primal.webp?v=1708602763032"; + } + if (global.skinpage === 5) { + counterthing.textContent = "○ ○ ○ ○ ○ ◉ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○"; + global.selectedskin = "kangarooskin"; + skinnamedisplay.textContent = "Kangaroo"; + checkifachieve("killachievement", "black"); + myImg.src = "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/image.webp?v=1708623596560"; + } + if (global.skinpage === 6) { + counterthing.textContent = "○ ○ ○ ○ ○ ○ ◉ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○"; + global.selectedskin = "cswmskin"; + skinnamedisplay.textContent = "ChickenSandwhichMan"; + checkifachieve("killachievement2", "grey"); + myImg.src = "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Untitled%20Project%20(22).jpg?v=1708356424097" + } + if (global.skinpage === 7) { + counterthing.textContent = "○ ○ ○ ○ ○ ○ ○ ◉ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○"; + global.selectedskin = "cogskin"; + skinnamedisplay.textContent = "Cogwheel"; + checkifachieve("lagachievement", "black"); + myImg.src = "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Gear-icon-transparent-background.png?v=1705579178381"; + } + if (global.skinpage === 8) { + counterthing.textContent = "○ ○ ○ ○ ○ ○ ○ ○ ◉ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○"; + global.selectedskin = "eggskin"; + skinnamedisplay.textContent = "Eggbert"; + checkifachieve("100shapesachievement", "black"); + myImg.src = "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/1165825970528325682l.webp?v=1714156807621"; + } + if (global.skinpage === 9) { + counterthing.textContent = "○ ○ ○ ○ ○ ○ ○ ○ ○ ◉ ○ ○ ○ ○ ○ ○ ○ ○ ○"; + global.selectedskin = "squareskin"; + skinnamedisplay.textContent = "Squarey"; + checkifachieve("250shapesachievement", "dgrey"); + myImg.src = "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/1165934167280848969.webp?v=1714156773284"; + } + if (global.skinpage === 10) { + counterthing.textContent = "○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ◉ ○ ○ ○ ○ ○ ○ ○ ○"; + global.selectedskin = "triangleskin"; + skinnamedisplay.textContent = "Triangleton"; + checkifachieve("500shapesachievement", "dgrey"); + myImg.src = "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/1165934432608321546.webp?v=1714156768932"; + } + if (global.skinpage === 11) { + counterthing.textContent = "○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ◉ ○ ○ ○ ○ ○ ○ ○"; + global.selectedskin = "pentagonskin"; + skinnamedisplay.textContent = "Pentogan"; + checkifachieve("750shapesachievement", "white"); + myImg.src = "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/1165825970528325682.webp?v=1714156764280"; + } + if (global.skinpage === 12) { + counterthing.textContent = "○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ◉ ○ ○ ○ ○ ○ ○"; + global.selectedskin = "gemskin"; + skinnamedisplay.textContent = "Gemy"; + checkifachieve("1000shapesachievement", "grey"); + myImg.src = "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/1165826077843796018.webp?v=1714156778841"; + } + if (global.skinpage === 13) { + counterthing.textContent = "○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ◉ ○ ○ ○ ○ ○"; + global.selectedskin = "coinskin"; + skinnamedisplay.textContent = "Coined"; + checkifachieve("tokenachievement", "black"); + myImg.src = "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2e2ccc30-5baf-41a2-aceb-c5456a1cc6dc.image.png?v=1708619146196"; + } + if (global.skinpage === 14) { + counterthing.textContent = "○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ◉ ○ ○ ○ ○"; + global.selectedskin = "discordskin"; + skinnamedisplay.textContent = "Sex Update"; + checkifachieve("Getbacktowoooak", "dgrey"); + myImg.src = "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2023_12_06_0yl_Kleki.png?v=1701908710293"; + } + if (global.skinpage === 15) { + counterthing.textContent = "○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ◉ ○ ○ ○"; + global.selectedskin = "deltaDecoskin"; + skinnamedisplay.textContent = "Cat-Code"; + checkifachieve("creditsachievement", "grey"); + myImg.src = "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2024_01_15_05q_Kleki.png?v=1705301828958"; + } + if (global.skinpage === 16) { + counterthing.textContent = "○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ◉ ○ ○"; + global.selectedskin = "incomskin"; + skinnamedisplay.textContent = "Very Much Incommodiousness"; + checkifachieve("pissio", "grey"); + myImg.style.filter = 'blur(10px)'; + myImg.src = "https://cdn.glitch.global/68f0db33-c86d-4aa5-9a35-a6750a92eae7/1200px-Icon-round-Question_mark.svg.png?v=1699273933044"; + } + if (global.skinpage === 17) { + counterthing.textContent = "○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ◉ ○"; + global.selectedskin = "tokayskin"; + skinnamedisplay.textContent = "Swaggity Waggity"; + checkifachieve("bossachivement", "white"); + myImg.src = "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/spider_2.png?v=1722633319003"; + } + if (global.skinpage === 18) { + counterthing.textContent = "○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ◉"; + global.selectedskin = "minosskin"; + skinnamedisplay.textContent = "THY END IS NOW!"; + checkifachieve("75killsachievement", "dgrey"); + myImg.src = "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/06f19349-48de-46ec-9877-6ea585848961.image.png?v=1739043712157"; + } + }; + let tanktype = "unfinished", + tankdesc = "unfinished", + tanktier = "???", + tankweap = "???", + tankabil = "???", + tankweak = "unfinished", + tankupto = ["Tier 2: ???", "Tier 3: ???", "Tier 4: ???", "Misc: ???"], + tankupfr = "unfinished", + tankorgn = "???", + tankupad = "???"; + +let trollface = null; + +function songrecog() { +//song names for display in the debug menu (may move it to a different place later) +if (global.music2.src === "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/oioioi.mp3?v=1705286830033") { + global.music2.songname = "OI OI OI --- Action Agenda"; +} +if (global.music2.src === "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Dejected.mp3?v=1705287022417") { + global.music2.songname = "Dejected --- Deltafyrex"; +} +if (global.music2.src === "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/WorldsEnd.mp3?v=1714399132177") { + global.music2.songname = "World's End --- Deltafyrex"; +} +if (global.music2.src === "https://cdn.glitch.global/f80d3eec-1e99-4b8c-b120-79a55addacf9/Meloncholy.mp3?v=1675465750213") { + global.music2.songname = "Melancholy --- Deltafyrex"; +} +if (global.music2.src === "https://cdn.glitch.me/5fc7dcb6-aada-495b-828e-66901a470a29/Nero.wav?v=1727644028814") { + global.music2.songname = "Nero --- Deltafyrex"; +} +if (global.music2.src === "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/anybody.mp3?v=1705807057028") { + global.music2.songname = "Anybody can find Love (except You.) --- hkmori" +} +if (global.music2.src === "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/resurgam.mp3?v=1708218475743") { + global.music2.songname = "Resurgam --- Amaryllis" +} +if (global.music2.src === "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/longing.mp3?v=1708218464295") { + global.music2.songname = "Longing --- Amaryllis" +} +if (global.music2.src === "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Action%20Agenda%20-%20Killa%20DFX%20Edit.mp3?v=1713352244240") { + global.music2.songname = "Killa --- Action Agenda (DFX EDIT)" +} +if (global.music2.src === "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Apotheosis.mp3?v=1713525419376") { + global.music2.songname = "Apotheosis V2 --- Deltafyrex" +} +if (global.music2.src === "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/demol1sh.mp3?v=1714414557787") { + global.music2.songname = "Demol1sh --- Nintendo" +} +if (global.music2.src === "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/demoli2h.mp3?v=1714414714759") { + global.music2.songname = "Demoli2h --- Nintendo" +} +if (global.music2.src === "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/d3molish.mp3?v=1714414706958") { + global.music2.songname = "D3molish --- Nintendo" +} +if (global.music2.src === "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/souven1r.mp3?v=1714414684036") { + global.music2.songname = "Souven1r --- Nintendo" +} +if (global.music2.src === "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2ouvenir.mp3?v=1714414700719") { + global.music2.songname = "2ouvenir --- Nintendo" +} +if (global.music2.src === "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/routine2.mp3?v=1714414889291") { + global.music2.songname = "Routine2 --- Nintendo" +} +if (global.music2.src === "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/routin3s.mp3?v=1714414850230") { + global.music2.songname = "Routin3s --- Nintendo" +} +if (global.music2.src === "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/jitt3rs.mp3?v=1714414684287") { + global.music2.songname = "Jitt3rs --- Nintendo" +} +if (global.music2.src === "https://cdn.glitch.me/5fc7dcb6-aada-495b-828e-66901a470a29/Atomic.wav?v=1727644048951") { + global.music2.songname = "Atomic --- Deltafyrex" +} +if (global.music2.src === "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Failed%20Connection.mp3?v=1727645304666") { + global.music2.songname = "Failed Connection --- Deltafyrex" +} +if (global.music2.src === "https://cdn.glitch.me/5fc7dcb6-aada-495b-828e-66901a470a29/Acension%20(Apotheosis%202).wav?v=1729515166145") { + global.music2.songname = "Ascension --- Deltafyrex" +} +if (global.music2.src === "https://cdn.glitch.me/5fc7dcb6-aada-495b-828e-66901a470a29/Nadir%20(Apotheosis%203).wav?v=1729515170342") { + global.music2.songname = "Nadir --- Deltafyrex" +} +if (global.music2.src === "https://cdn.glitch.me/5fc7dcb6-aada-495b-828e-66901a470a29/Methemphetaphacktomine.wav?v=1729515173719") { + global.music2.songname = "Phacktomine --- Deltafyrex" +} +if (global.music2.src === "https://cdn.glitch.me/5fc7dcb6-aada-495b-828e-66901a470a29/Polychromatism.wav?v=1729515177274") { + global.music2.songname = "Polychromatism --- Deltafyrex" +} +if (global.music2.src === "https://cdn.glitch.me/5fc7dcb6-aada-495b-828e-66901a470a29/Wednesday%2C%20Friday%20(1).wav?v=1736978399984") { + global.music2.songname = "Wednesday, Friday --- Deltafyrex" +} +if (global.music2.src === "https://cdn.glitch.me/5fc7dcb6-aada-495b-828e-66901a470a29/Heresy.wav?v=1736979337244") { + global.music2.songname = "Heresy --- Deltafyrex" +} +if (global.music2.src === "https://cdn.glitch.me/5fc7dcb6-aada-495b-828e-66901a470a29/Reconstructed.wav?v=1736979424454") { + global.music2.songname = "Reconstructed --- Deltafyrex" +} +} +function lagachloop() { + if (global.metrics.rendertime <= 45 && global.metrics.rendertime >= 15) { + util.submitAchievementToLocalStorage("lagachievement"); + } + if (global.savedkillcount >= 100) { + util.submitAchievementToLocalStorage("100killsachievement"); + } + if (global.savedkillcount >= 75) { + util.submitAchievementToLocalStorage("75killsachievement"); + } + if (global.savedkillcount >= 50) { + util.submitAchievementToLocalStorage("50killsachievement"); + } + if (global.savedkillcount >= 25) { + util.submitAchievementToLocalStorage("25killsachievement"); + } + if (global.savedshapecount >= 100) { + util.submitAchievementToLocalStorage("100shapesachievement"); + } + if (global.savedshapecount >= 250) { + util.submitAchievementToLocalStorage("250shapesachievement"); + } + if (global.savedshapecount >= 500) { + util.submitAchievementToLocalStorage("500shapesachievement"); + } + if (global.savedshapecount >= 750) { + util.submitAchievementToLocalStorage("750shapesachievement"); + } + if (global.savedshapecount >= 1000) { + util.submitAchievementToLocalStorage("1000shapesachievement"); + } +} +/*if (localStorage.getItem("killachievement") !== "YOUDIDIT:D!!!") { + if (global.achievements.kills >= 4) { + util.submitAchievementToLocalStorage("killachievement"); + } +}*/ +if (global.ISTHEGODAMNFUCKINGGAMEON !== "yeah") { +if (localStorage.getItem("startachievement") !== "YOUDIDIT:D!!!") { +localStorage.setItem("savedkills", 0); +} +} +function resetAllAchievements() { + var zeroyeah = 0; + util.resetAchievementFromLocalStorage("killachievement"); +} + let nIntervId; + if (!nIntervId) { + nIntervId = setInterval(gettimesince, 1000); + } + function gettimesince() { + const date = new Date() + var sec = 0; + var min = 0; + var hour = 0; + var day = 0; + var month = 0; + var year = 0; + var nerosec = ''; + var neromin = ''; + var nerohour = ''; + var neroday = ''; + var neromonth = ''; + var daysinm = 0; + if (date.getMonth() == 8 || 10 || 3 || 5) { + daysinm = 30 + } else { + if (date.getMonth() == 1) { + if (date.getFullYear() == 2024 || 2028 || 2032 || 2036 || 2040 || 2044 || 2048 || 2042) { + daysinm = 29 + } else { + daysinm = 28 + } + } else { + daysinm = 31 + } + } + if (date.getSeconds() + 28 > 59) { + sec = (date.getSeconds() + 60) - 92 + } else { + sec = (date.getSeconds() + 60) - 32 + }; + if (date.getMinutes() < 45) { + if (date.getSeconds() > 31) { + min = (date.getMinutes() + 60) - 44 + } else { + min = (date.getMinutes() + 60) - 45 + } + } else { + if (date.getSeconds() > 31) { + min = (date.getMinutes() + 60) - 104 + } else { + min = (date.getMinutes() + 60) - 105 + } + } + if (date.getHours() < 11) { + if (date.getMinutes() > 44) { + hour = ((date.getHours() + 24) - 10) + } else { + hour = ((date.getHours() + 24) - 11) + } + } else { + if (date.getMinutes() > 44) { + hour = ((date.getHours() + 24) - 34) + } else { + hour = ((date.getHours() + 24) - 35) + } + } + if (date.getDate() < 24) { + if (date.getHours() > 10) { + day = (date.getDate() + daysinm) - 23 + } else { + day = (date.getDate() + daysinm) - 24 + } + } else { + if (date.getHours() > 10) { + day = (date.getDate() + daysinm) - (23 + daysinm) + } else { + day = (date.getDate() + daysinm) - (24 + daysinm) + } + }; + if (date.getMonth() < 4) { + if (date.getDate() > 23) { + if (date.getMonth() == 3) { + month = (date.getMonth() + 11) - 14 + } else { + month = (date.getMonth() + 11) - 2 + } + } else { + month = (date.getMonth() + 11) - 3 + } + } else { + if (date.getDate() > 23) { + month = (date.getMonth() + 11) - 14 + } else { + month = (date.getMonth() + 11) - 15 + } + }; + if (date.getMonth() > 2 & date.getDate() > 23) { + year = ' | Years: ' + (date.getFullYear() - 2019) + } else { + year = ' | Years: ' + (date.getFullYear() - 2020) + } + if (sec !== 0) { + nerosec = ', Seconds: ' + sec + } else { + nerosec = '' + } + if (min !== 0) { + neromin = ', Minutes: ' + min + } else { + neromin = '' + } + if (hour !== 0) { + nerohour = ', Hours: ' + hour + } else { + nerohour = '' + } + if (day !== 0) { + neroday = ', Days: ' + day + } else { + neroday = '' + } + if (month !== 0) { + neromonth = ', Months: ' + month + } else { + neromonth = '' + } + //const currentdate = ' / Current Year: ' + date.getFullYear() + ' / Current Month: ' + date.getMonth() + ' / Current Day: ' + date.getDate() + ' / Current Hour: ' + date.getHours() + ' / Current Minute: ' + date.getMinutes() + ' / Current Second: ' + date.getSeconds() + ' /' + const nerodate = year + ' ' + neromonth + ' ' + neroday + ' ' + nerohour + ' ' + neromin + ' ' + nerosec + ' |' + $(document.getElementById("updatetime")).html("

" + nerodate + "

"); + //$(document.getElementById("updatetime2")).html("

" + currentdate + "

"); + } fetch("changelog.html", { cache: "no-cache" }) .then(async ChangelogsHTMLFile => { let patchNotes = document.querySelector("#patchNotes"); @@ -39,6 +824,25 @@ fetch("changelog.html", { cache: "no-cache" }) } }); +fetch("credits.html", { cache: "no-cache" }) +.then(async CreditsHTMLFile => { + let patchNotes = document.querySelector("#credits"); + try { + let parser = new DOMParser(), + RawHTMLString = await CreditsHTMLFile.text(), + ParsedHTML = parser.parseFromString(RawHTMLString, "text/html"), + titles = ParsedHTML.documentElement.getElementsByTagName('h1'); + for (const title of titles) { + title.classList.add('title'); + } + + patchNotes.innerHTML += ParsedHTML.documentElement.innerHTML; + } catch (error) { + patchNotes.innerHTML = `

An error occured while trying to fetch 'credits.html'

${error}

`; + console.error(error); + } +}); + class Animation { constructor(start, to, smoothness = 0.05) { this.start = start; @@ -71,12 +875,20 @@ class Animation { return Math.abs(this.to - this.value) < val; } } -let animations = window.animations = { - connecting: new Animation(1, 0), - disconnected: new Animation(1, 0), - deathScreen: new Animation(1, 0), - error: new Animation(1, 0), -}; +let controls = document.getElementById("controlSettings"), + resetButton = document.getElementById("resetControls"), + moreControls = document.getElementById("moreControls"), + moreControlsLength = null, + selectedElement = null, + controlsArray = [], + defaultKeybinds = {}, + keybinds = {}, + animations = window.animations = { + connecting: new Animation(1, 0), + disconnected: new Animation(1, 0), + deathScreen: new Animation(1, 0), + error: new Animation(1, 0), + }; // Mockup functions // Prepare stuff @@ -112,8 +924,15 @@ global.canUpgrade = false; global.canSkill = false; global.message = ""; global.time = 0; +global.enableSlideAnimation = false; +global.mspt = "?"; +global.serverName = "neroio2.glitch.me"; +// Tips setup :D +let tips = global.tips[Math.floor(Math.random() * global.tips.length)]; +global.tips = tips[Math.floor(Math.random() * tips.length)]; // Window setup <3 global.mobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent); +global.mobile && document.body.classList.add("mobile"); var serverName = "Connected"; var provider = "Unknown"; function getMockups() { @@ -121,96 +940,373 @@ function getMockups() { util.pullJSON("mockups").then(data => { global.mockups = data; console.log('Mockups loading complete.'); + console.log("%cWhy are you here Lmfao", "color: #FFFFFF; font-size: 45px; background: #333333; text-shadow: #FFF 0px 0px 5px, #FFF 0px 0px 10px, #FFF 0px 0px 15px, #FF2D95 0px 0px 20px, #FF2D95 0px 0px 30px, #FF2D95 0px 0px 40px, #FF2D95 0px 0px 50px, #FF2D95 0px 0px 75px;"); Resolve(); }); }); } +function getKeybinds() { + let kb = localStorage.getItem("keybinds"); + keybinds = typeof kb === "string" && kb.startsWith("{") ? JSON.parse(kb) : {}; +} +function setKeybinds() { + localStorage.setItem("keybinds", JSON.stringify(keybinds)); +} +function unselectElement() { + if (window.getSelection) { + window.getSelection().removeAllRanges(); + } + selectedElement.element.parentNode.parentNode.classList.remove("editing"); + selectedElement = null; +} +function selectElement(element) { + selectedElement = element; + selectedElement.element.parentNode.parentNode.classList.add("editing"); + if (selectedElement.keyCode !== -1 && window.getSelection) { + let selection = window.getSelection(); + selection.removeAllRanges(); + let range = document.createRange(); + range.selectNodeContents(selectedElement.element); + selection.addRange(range); + } +} +function setKeybind(key, keyCode) { + selectedElement.element.parentNode.parentNode.classList.remove("editing"); + resetButton.classList.add("active"); + if (keyCode !== selectedElement.keyCode) { + let otherElement = controlsArray.find(c => c.keyCode === keyCode); + if (keyCode !== -1 && otherElement) { + otherElement.keyName = selectedElement.keyName; + otherElement.element.innerText = selectedElement.keyName; + otherElement.keyCode = selectedElement.keyCode; + global[otherElement.keyId] = selectedElement.keyCode; + keybinds[otherElement.keyId] = [selectedElement.keyName, selectedElement.keyCode]; + } + } + selectedElement.keyName = key; + selectedElement.element.innerText = key; + selectedElement.keyCode = keyCode; + global[selectedElement.keyId] = keyCode; + keybinds[selectedElement.keyId] = [key, keyCode]; + setKeybinds(); +} +function getElements(kb, storeInDefault) { + for (let row of controls.rows) { + for (let cell of row.cells) { + let element = cell.firstChild.firstChild; + if (!element) continue; + let key = element.dataset.key; + if (storeInDefault) defaultKeybinds[key] = [element.innerText, global[key]]; + if (kb[key]) { + element.innerText = kb[key][0]; + global[key] = kb[key][1]; + resetButton.classList.add("active"); + } + let obj = { + element, + keyId: key, + keyName: element.innerText, + keyCode: global[key] + }; + controlsArray.push(obj); + } + } +} window.onload = async () => { - window.serverAdd = (await (await fetch("/serverData.json")).json()).ip; - if (Array.isArray(window.serverAdd)) { - window.isMultiserver = true; - const servers = window.serverAdd; - let serverSelector = document.getElementById("serverSelector"), - tbody = document.createElement("tbody"); - serverSelector.style.display = "block"; - document.getElementById("startMenuSlidingContent").removeChild(document.getElementById("serverName")); - serverSelector.classList.add("serverSelector"); - serverSelector.classList.add("shadowscroll"); - serverSelector.appendChild(tbody); - let myServer = { + let servers = await (await fetch("/browserData.json")).json(), + serverSelector = document.getElementById("serverSelector"), + tbody = document.createElement("tbody"), + myServer = { classList: { contains: () => false, }, - }; - for (let server of servers) { - try { - const tr = document.createElement("tr"); - const td = document.createElement("td"); - td.textContent = `${server.gameMode} | ${server.players} Players`; - td.onclick = () => { - if (myServer.classList.contains("selected")) { - myServer.classList.remove("selected"); - } - tr.classList.add("selected"); - myServer = tr; - window.serverAdd = server.ip; - getMockups(); - }; - tr.appendChild(td); - tbody.appendChild(tr); + }, + ping = 0; + + serverSelector.style.display = "block"; + document.getElementById("serverName").remove(); + serverSelector.classList.add("serverSelector"); + serverSelector.classList.add("shadowscroll"); + serverSelector.appendChild(tbody); + + for (let server of servers) { + let protocol = server[2] ? "https:" : "http:", + location = server[1], + ip = server[0], + minPing, + time; + + if (Array.isArray(server)) { + if (!server.length) continue; + time = Date.now(); + server = await (await fetch(`${protocol}//${ip}/serverData.json`)).json(); + minPing = Date.now() - time; + } else { + console.log(server); + throw new Error("Invalid server browser data"); + } + if (typeof server != "object") { + console.log(server); + throw new Error("Invalid server data"); + } + try { + let tdPlayers = document.createElement("td"), + tdMode = document.createElement("td"), + tdIp = document.createElement("td"), + tr = document.createElement("tr"); + tdMode.textContent = "Loading"; + + tdPlayers.textContent = `${server.players} Players`; + tdPlayers.classList.add("tdLeft"); + tdMode.textContent = server.gameMode; + tdMode.classList.add("tdCenter"); + tdIp.textContent = location == "" ? ip : location; + tdIp.classList.add("tdLeft"); + tr.appendChild(tdIp); + tr.appendChild(tdMode); + tr.appendChild(tdPlayers); + tr.onclick = () => { + if (myServer.classList.contains("selected")) { + myServer.classList.remove("selected"); + } + tr.classList.add("selected"); + myServer = tr; + window.connectionAdd = protocol; + window.serverAdd = ip; + getMockups(); + }; + tbody.appendChild(tr); + if (!ping || ping > minPing) { + ping = minPing; myServer = tr; - } catch (e) { - console.log(e); + serverSelector.scrollTop = tr.offsetTop; } + } catch (e) { + console.log(e); } - if (Array.from(myServer.children)[0].onclick) { - Array.from(myServer.children)[0].onclick(); - } - } else { - getMockups(); - util.pullJSON("gamemodeData").then((json) => { - document.getElementById("serverName").innerHTML = `

${json.gameMode} | ${json.players} Players

`; - }); } + if (myServer.onclick) { + myServer.onclick(); + } + + // Save forms + util.retrieveFromLocalStorage("playerNameInput"); + // Save forms util.retrieveFromLocalStorage("playerNameInput"); util.retrieveFromLocalStorage("playerKeyInput"); util.retrieveFromLocalStorage("optScreenshotMode"); util.retrieveFromLocalStorage("optPredictive"); util.retrieveFromLocalStorage("optFancy"); + util.retrieveFromLocalStorage("optLowResolution"); util.retrieveFromLocalStorage("coloredHealthbars"); util.retrieveFromLocalStorage("centerTank"); util.retrieveFromLocalStorage("optColors"); util.retrieveFromLocalStorage("optCustom"); util.retrieveFromLocalStorage("optNoPointy"); util.retrieveFromLocalStorage("optBorders"); + util.retrieveFromLocalStorage("optNoGrid"); util.retrieveFromLocalStorage("seperatedHealthbars"); util.retrieveFromLocalStorage("autoLevelUp"); + util.retrieveFromLocalStorage("optResolution"); + util.retrieveFromLocalStorage("optMobile"); + // GUI + util.retrieveFromLocalStorage("optRenderGui"); + util.retrieveFromLocalStorage("optRenderLeaderboard"); + util.retrieveFromLocalStorage("optRenderNames"); + util.retrieveFromLocalStorage("optRenderHealth"); + util.retrieveFromLocalStorage("optRenderScores"); + util.retrieveFromLocalStorage("optReducedInfo"); + util.retrieveFromLocalStorage("showCrosshair"); + util.retrieveFromLocalStorage("showJoystick"); + + util.retrieveFromLocalStorage("seperatedHealthbars"); + util.retrieveFromLocalStorage("optOgIcon"); + util.retrieveFromLocalStorage("disableDeathSounds"); + util.retrieveFromLocalStorage("optNoEmojis"); + util.retrieveFromLocalStorage("autoLevelUp"); + /*util.retrieveFromLocalStorageCheckDefault("oioioi"); + util.retrieveFromLocalStorageCheckDefault("dejected"); + util.retrieveFromLocalStorageCheckDefault("worldsend"); + util.retrieveFromLocalStorageCheckDefault("nerosong"); + util.retrieveFromLocalStorage("anybody"); + util.retrieveFromLocalStorageCheckDefault("resurgam"); + util.retrieveFromLocalStorageCheckDefault("longing"); + util.retrieveFromLocalStorageCheckDefault("apotheosis"); + util.retrieveFromLocalStorageCheckDefault("killa"); + util.retrieveFromLocalStorageCheckDefault("failedconnection"); + util.retrieveFromLocalStorageCheckDefault("demol1sh"); + util.retrieveFromLocalStorageCheckDefault("demoli2h"); + util.retrieveFromLocalStorage("d3molish"); + util.retrieveFromLocalStorageCheckDefault("souven1r"); + util.retrieveFromLocalStorageCheckDefault("2ouvenir"); + util.retrieveFromLocalStorage("routine2"); + util.retrieveFromLocalStorage("routin3s"); + util.retrieveFromLocalStorage("jitt3rs"); + util.retrieveFromLocalStorageCheckDefault("atomic"); + util.retrieveFromLocalStorageCheckDefault("ascension"); + util.retrieveFromLocalStorageCheckDefault("nadir"); + util.retrieveFromLocalStorage("phacktomine"); + util.retrieveFromLocalStorageCheckDefault("polychromatism");*/ // Set default theme if (document.getElementById("optColors").value === "") { - document.getElementById("optColors").value = "normal"; + document.getElementById("optColors").value = "nero"; + + // Also do auto check for GUI stuff. + document.getElementById("optRenderGui").checked = true; + document.getElementById("optRenderLeaderboard").checked = true; + document.getElementById("optRenderNames").checked = true; + document.getElementById("optRenderHealth").checked = true; + document.getElementById("optRenderScores").checked = true; + document.getElementById("optFancy").checked = true; + if (global.mobile) document.getElementById("showCrosshair").checked = true, document.getElementById("showJoystick").checked = true; } if (document.getElementById("optBorders").value === "") { - document.getElementById("optBorders").value = "normal"; - } + document.getElementById("optBorders").value = "nero"; + } + if (document.getElementById("optResolution").value === "") { + document.getElementById("optResolution").value = "normal"; + } + + // Mobile Selection stuff. + if (document.getElementById("optMobile").value === "") { + document.getElementById("optMobile").value = "mobile"; + } + + // Achievement Shit + document.getElementById("resetachievementsbutton").onclick = () => resetAllAchievements(); + // Keybinds stuff + getKeybinds(); + getElements(keybinds, true); + document.addEventListener("click", event => { + if (!global.gameStart) { + if (selectedElement) { + unselectElement(); + } else { + let element = controlsArray.find(({ element }) => element === event.target); + if (element) selectElement(element); + } + } + }); + resetButton.addEventListener("click", () => { + keybinds = {}; + setKeybinds(); + controlsArray = []; + getElements(defaultKeybinds); + resetButton.classList.add("spin"); + setTimeout(() => { + resetButton.classList.remove("active"); + resetButton.classList.remove("spin"); + }, 400); + }); + moreControls.addEventListener("click", () => { + if (moreControlsLength) { + for (var b = 0; b < moreControlsLength.length; b++) moreControlsLength[b].classList.add("hidden"); + moreControlsLength = null; + moreControls.classList.remove("x"); + } else { + moreControlsLength = document.querySelectorAll("#controlSettings tr.hidden"); + for (b = 0; b < moreControlsLength.length; b++) moreControlsLength[b].classList.remove("hidden"); + moreControls.classList.add("x"); + } + }); // Game start stuff document.getElementById("startButton").onclick = () => startGame(); document.onkeydown = (e) => { - var key = e.which || e.keyCode; - if (key === global.KEY_ENTER && (global.dead || !global.gameLoading)) { - startGame(); + if (!(global.gameStart || e.shiftKey || e.ctrlKey || e.altKey)) { + let key = e.which || e.keyCode; + if (selectedElement) { + if (1 !== e.key.length || /[0-9]/.test(e.key) || 3 === e.location) { + if (!("Backspace" !== e.key && "Delete" !== e.key)) { + setKeybind("", -1); + } + } else { + setKeybind(e.key.toUpperCase(), e.keyCode); + } + } else if (key === global.KEY_ENTER) { + startGame(); + } } }; window.addEventListener("resize", resizeEvent); resizeEvent(); }; +var callofduty = ""; +// Sliding between options menu. +function toggleOptionsMenu() { + let clicked = false, + a = document.getElementById("startMenuSlidingTrigger"), // Trigger ID + c = document.getElementById("optionArrow"), // Arrow + h = document.getElementById("viewOptionText"), // Text (view options) + u = document.getElementsByClassName("sliderHolder")[0], // Sliding. + y = document.getElementsByClassName("slider"), // For animations things. + toggle = () => { + c.style.transform = c.style.webkitTransform = clicked // Rotate the arrow. + ? "translate(2px, -2px) rotate(45deg)" + : "rotate(-45deg)"; + h.innerText = clicked ? "close options" : "view options"; // Change the text. + clicked ? (u.classList.add("slided"), PlaySoundClose()) : (u.classList.remove("slided"), PlaySoundOpen()) // Slide it up. + y[0].style.opacity = clicked ? 0 : 1; // Fade it away. + y[2].style.opacity = clicked ? 1 : 0; // same for this. + }; + a.onclick = () => { // When the button is triggered, This code runs. + clicked = !clicked; + toggle(); + }; + return () => { + clicked || ((clicked = !0), toggle()); + }; +}; +// Tab options +function tabOptionsMenuSwitcher() { + let buttonTabs = document.getElementById("optionMenuTabs"), + tabOptions = [ + document.getElementById("tabAppearance"), + document.getElementById("tabOptions"), + document.getElementById("tabControls"), + document.getElementById("tabAbout"), + ]; + for (let g = 1; g < tabOptions.length; g++) tabOptions[g].style.display = "none"; + let e = 0; + for (let g = 0; g < buttonTabs.children.length; g++) + buttonTabs.children[g].addEventListener("click", () => { + e !== g && + (buttonTabs.children[e].classList.remove("active"), // Remove the active class + buttonTabs.children[g].classList.add("active"), // Add the clicked active class + (tabOptions[e].style.display = "none"), // Dont display the old menu. + (tabOptions[g].style.display = "block"), // Display the menu. + (e = g)) + }); +} function resizeEvent() { + if (settings.graphical.quality === undefined) { + settings.graphical.quality = 1; + }; let scale = window.devicePixelRatio; - if (!settings.graphical.fancyAnimations) { + if (settings.graphical.lowResolution) { scale *= 0.5; } + if (typeof settings.graphical.quality === 'string' || settings.graphical.quality instanceof String) { + callofduty = new Image(); // Create new img element + if (settings.graphical.quality == "cod") { + callofduty.src = "https://image.api.playstation.com/cdn/EP0002/CUSA12443_00/VgKYOxWoNSp4mNJ2KvzEFVBWN0idCM5I.png?w=440" + } + } else { + scale *= settings.graphical.quality + } + if (settings.graphical.quality == "1dim") { + global.screenWidth = window.innerWidth * scale; + global.screenHeight = 1 * scale; + } else if (settings.graphical.quality == "d1dim") { + global.screenWidth = 1 * scale; + global.screenHeight = window.innerHeight * scale; + } else if (settings.graphical.quality == "1pix") { + global.screenWidth = 1 * scale; + global.screenHeight = 1 * scale; + } else { global.screenWidth = window.innerWidth * scale; global.screenHeight = window.innerHeight * scale; + } c.resize(global.screenWidth, global.screenHeight); global.ratio = scale; global.screenSize = Math.min(1920, Math.max(window.innerWidth, 1280)); @@ -222,6 +1318,9 @@ var ctx = c.getContext("2d"); var c2 = document.createElement("canvas"); var ctx2 = c2.getContext("2d"); ctx2.imageSmoothingEnabled = true; +// important functions +tabOptionsMenuSwitcher(); +toggleOptionsMenu(); // Animation things function Smoothbar(value, speed, sharpness = 3, lerpValue = 0.025) { let time = Date.now(); @@ -239,7 +1338,7 @@ function Smoothbar(value, speed, sharpness = 3, lerpValue = 0.025) { display = util.lerp(display, value, lerpValue); if (Math.abs(value - display) < 0.1 && round) display = value; return display; - }, + }, force: (val) => { display = value = val; }, @@ -258,7 +1357,7 @@ global.player = { cy: 0, screenx: 0, screeny: 0, - target: calculateTarget(), + target: !global.mobile ? calculateTarget() : window.canvas.target, name: "", lastUpdate: 0, time: 0, @@ -284,7 +1383,7 @@ function parseTheme(string){ stripped += '='; let data = atob(stripped); - let name = 'Unknown Theme', + let name = 'Unknown Theme', author = ''; let index = data.indexOf('\x00'); if (index === -1) return null; @@ -334,7 +1433,6 @@ function parseTheme(string){ } return { name, author, content }; } catch (e) {} - // Decode from JSON try { let output = JSON.parse(string); @@ -379,27 +1477,100 @@ function parseTheme(string){ } // This starts the game and sets up the websocket function startGame() { + if (!global.gameStart) { + PlaySound69(); + clearInterval(nIntervId); + // release our intervalID from the variable + nIntervId = null; // Set flag global.gameLoading = true; console.log('Started connecting.') + //set start achievement + util.submitAchievementToLocalStorage("startachievement"); + } + + if (global.mobile) { + document.getElementById("optMobile").display = "block" + util.submitAchievementToLocalStorage("startachievement"); + var d = document.body; + d.requestFullscreen ? d.requestFullscreen() + : d.msRequestFullscreen ? d.msRequestFullscreen() + : d.mozRequestFullScreen ? d.mozRequestFullScreen() + : d.webkitRequestFullscreen && d.webkitRequestFullscreen(); + } // Get options util.submitToLocalStorage("optFancy"); + util.submitToLocalStorage("optLowResolution"); util.submitToLocalStorage("centerTank"); util.submitToLocalStorage("optBorders"); + util.submitToLocalStorage("optResolution"); util.submitToLocalStorage("optNoPointy"); + util.submitToLocalStorage("optOgIcon"); + util.submitToLocalStorage("disableDeathSounds"); + util.submitToLocalStorage("optNoEmojis"); util.submitToLocalStorage("autoLevelUp"); + util.submitToLocalStorage("optMobile"); util.submitToLocalStorage("optPredictive"); util.submitToLocalStorage("optScreenshotMode"); util.submitToLocalStorage("coloredHealthbars"); util.submitToLocalStorage("seperatedHealthbars"); - settings.graphical.fancyAnimations = !document.getElementById("optFancy").checked; + /*util.submitToLocalStorage("oioioi"); + util.submitToLocalStorage("dejected"); + util.submitToLocalStorage("worldsend"); + util.submitToLocalStorage("nerosong"); + util.submitToLocalStorage("anybody"); + util.submitToLocalStorage("resurgam"); + util.submitToLocalStorage("longing"); + util.submitToLocalStorage("apotheosis"); + util.submitToLocalStorage("killa"); + util.submitToLocalStorage("failedconnection"); + util.submitToLocalStorage("ascension"); + util.submitToLocalStorage("nadir"); + util.submitToLocalStorage("phacktomine"); + util.submitToLocalStorage("polychromatism"); + util.submitToLocalStorage("demol1sh"); + util.submitToLocalStorage("demoli2h"); + util.submitToLocalStorage("d3molish"); + util.submitToLocalStorage("souven1r"); + util.submitToLocalStorage("2ouvenir"); + util.submitToLocalStorage("routine2"); + util.submitToLocalStorage("routin3s"); + util.submitToLocalStorage("jitt3rs"); + util.submitToLocalStorage("atomic");*/ + util.submitToLocalStorage("optNoGrid"); + // GUI + util.submitToLocalStorage("optRenderGui"); + util.submitToLocalStorage("optRenderLeaderboard"); + util.submitToLocalStorage("optRenderNames"); + util.submitToLocalStorage("optRenderHealth"); + util.submitToLocalStorage("optRenderScores"); + util.submitToLocalStorage("optReducedInfo"); + util.submitToLocalStorage("showCrosshair"); + util.submitToLocalStorage("showJoystick"); + global.ISTHEGODAMNFUCKINGGAMEON = "yeah"; + settings.graphical.fancyAnimations = document.getElementById("optFancy").checked; settings.graphical.centerTank = document.getElementById("centerTank").checked; settings.graphical.pointy = !document.getElementById("optNoPointy").checked; - settings.game.autoLevelUp = document.getElementById("autoLevelUp").checked; + settings.game.optOgIcon = !document.getElementById("optOgIcon").checked; + settings.game.disableDeathSounds = document.getElementById("disableDeathSounds").checked; + settings.game.optNoEmojis = !document.getElementById("optNoEmojis").checked; + settings.game.autoLevelUp = !document.getElementById("autoLevelUp").checked; settings.lag.unresponsive = document.getElementById("optPredictive").checked; settings.graphical.screenshotMode = document.getElementById("optScreenshotMode").checked; settings.graphical.coloredHealthbars = document.getElementById("coloredHealthbars").checked; settings.graphical.seperatedHealthbars = document.getElementById("seperatedHealthbars").checked; + settings.graphical.lowResolution = document.getElementById("optLowResolution").checked; + settings.graphical.showGrid = !document.getElementById("optNoGrid").checked; + // GUI + global.GUIStatus.renderGUI = document.getElementById("optRenderGui").checked; + global.GUIStatus.renderLeaderboard = document.getElementById("optRenderLeaderboard").checked; + global.GUIStatus.renderPlayerNames = document.getElementById("optRenderNames").checked; + global.GUIStatus.renderPlayerScores = document.getElementById("optRenderScores").checked; + global.GUIStatus.renderhealth = document.getElementById("optRenderHealth").checked; + global.GUIStatus.minimapReducedInfo = document.getElementById("optReducedInfo").checked; + global.mobileStatus.enableCrosshair = document.getElementById("showCrosshair").checked; + global.mobileStatus.showJoysticks = document.getElementById("showJoystick").checked; + switch (document.getElementById("optBorders").value) { case "normal": settings.graphical.darkBorders = settings.graphical.neon = false; @@ -416,18 +1587,71 @@ function startGame() { settings.graphical.darkBorders = settings.graphical.neon = true; break; } + switch (document.getElementById("optResolution").value) { + case "normal": + settings.graphical.quality = 1; + break; + case "low": + settings.graphical.quality = 0.75; + break; + case "high": + settings.graphical.quality = 1.5; + break; + case "higher": + settings.graphical.quality = 2; + break; + case "rtx": + settings.graphical.quality = 4; + break; + case "really low": + settings.graphical.quality = 0.5; + break; + case "really really low": + settings.graphical.quality = 0.25; + break; + case "unplayable": + settings.graphical.quality = 0.1; + break; + case "1d": + settings.graphical.quality = "1dim"; + break; + case "d1": + settings.graphical.quality = "d1dim"; + break; + case "onepixel": + settings.graphical.quality = "1pix"; + break; + case "codbo4": + settings.graphical.quality = "cod"; + break; + case "drugs": + settings.graphical.quality = "trippy"; + break; + } + switch (document.getElementById("optMobile").value) { + case "desktop": + global.mobile = false; + break; + case "mobileWithBigJoysticks": + global.mobileStatus.useBigJoysticks = true; + break; + } util.submitToLocalStorage("optColors"); + if (!global.gameStart) { let a = document.getElementById("optColors").value; - color = color[a === "" ? "normal" : a]; + color = color[a === "" ? "nero" : a]; if (a == "custom") { let customTheme = document.getElementById("optCustom").value; color = parseTheme(customTheme).content; util.submitToLocalStorage("optCustom"); } + } gameDraw.color = color; // Other more important stuff let playerNameInput = document.getElementById("playerNameInput"); let playerKeyInput = document.getElementById("playerKeyInput"); + let autolevelUpInput = document.getElementById("autoLevelUp").checked; + global.autolvlUp = autolevelUpInput; // Name and keys util.submitToLocalStorage("playerNameInput"); util.submitToLocalStorage("playerKeyInput"); @@ -436,34 +1660,49 @@ function startGame() { // Change the screen global.screenWidth = window.innerWidth; global.screenHeight = window.innerHeight; - document.getElementById("startMenuWrapper").style.maxHeight = "0px"; + document.getElementById("startMenuWrapper").style = "display: block; pointer-events: none; inset: 0; animation: fadezoomout 300ms forwards;"; document.getElementById("gameAreaWrapper").style.opacity = 1; + setTimeout(() => { + document.getElementById("startMenuWrapper").style = "display: none;"; + }, 1e3); + + if (!global.gameStart) { + document.getElementById("hideongamestart").style.zIndex = "-3"; + document.getElementById("canvas").style.width = "120px"; + document.getElementById("canvas").style.height = "72px"; + document.getElementById("content").style.zIndex = "6"; + document.getElementById("canvas").style.top = "90%"; + document.getElementById("canvas").style.position = "relative"; // Set up the socket if (!global.socket) { - global.socket = socketInit(26301); + global.socket = socketInit(3000); } if (!global.animLoopHandle) { animloop(); } + // initialize canvas. window.canvas.socket = global.socket; - setInterval(() => moveCompensation.iterate(global.socket.cmd.getMotion()), 1000 / 30); + setInterval(() => moveCompensation.iterate(global.motion), 1000 / 30); + canvas.init(); + } document.getElementById("gameCanvas").focus(); - window.onbeforeunload = () => true; + if (!global.gameStart) window.onbeforeunload = () => true; + if (settings.game.optNoEmojis) { + trollface = new Image(); // Create new img element + } } -// Background clearing function clearScreen(clearColor, alpha) { ctx.fillStyle = clearColor; ctx.globalAlpha = alpha; ctx.fillRect(0, 0, global.screenWidth, global.screenHeight); ctx.globalAlpha = 1; } -// Text functions function arrayifyText(rawText) { //we want people to be able to use the section sign in writing too // string with double § txt col txt txt // "...§text§§text§..." => [..., "text", "", "text", ...] => [..., "text§text", ...] // this code is balanced on tight threads, holy shit - let textArrayRaw = rawText.split('§'), + let textArrayRaw = rawText.split(/§|;;/), textArray = []; if (!(textArrayRaw.length & 1)) { textArrayRaw.unshift(''); @@ -481,12 +1720,13 @@ function arrayifyText(rawText) { } return textArray; } -const measureText = (text, fontSize, withHeight = false) => { +function measureText(text, fontSize, withHeight = false) { fontSize += settings.graphical.fontSizeBoost; ctx.font = "bold " + fontSize + "px Ubuntu"; let measurement = ctx.measureText(arrayifyText(text).reduce((a, b, i) => (i & 1) ? a : a + b, '')); return withHeight ? { width: measurement.width, height: fontSize } : measurement.width; -}; +} + function drawText(rawText, x, y, size, defaultFillStyle, align = "left", center = false, fade = 1, stroke = true, context = ctx) { size += settings.graphical.fontSizeBoost; // Get text dimensions and resize/reset the canvas @@ -561,6 +1801,162 @@ function drawText(rawText, x, y, size, defaultFillStyle, align = "left", center } context.restore(); } + +// Library: mltext.js +// Desciption: Extends the CanvasRenderingContext2D that adds two functions: mlFillText and mlStrokeText. +// +// The prototypes are: +// +// function mlFillText(text,x,y,w,h,vAlign,hAlign,lineheight); +// function mlStrokeText(text,x,y,w,h,vAlign,hAlign,lineheight); +// +// Where vAlign can be: "top", "center" or "button" +// And hAlign can be: "left", "center", "right" or "justify" +// Author: Jordi Baylina. (baylina at uniclau.com) +// License: GPL +// Date: 2013-02-21 + +function mlFunction(text, x, y, w, h, hAlign, vAlign, lineheight, textsize, defaultFillStyle = color.guiwhite, fn = "strokeText") { + textsize += settings.graphical.fontSizeBoost; + // Get text dimensions and resize/reset the canvas + let offset = textsize / 5, + ratio = 1; + if (ctx.getTransform) { + ratio = ctx.getTransform().d; + offset *= ratio; + } + if (ratio !== 1) { + textsize *= ratio; + } + ctx.font = "bold " + textsize + "px Ubuntu"; + text = text.replace(/[\n]/g, " \n "); + text = text.replace(/\r/g, ""); + lineheight += settings.graphical.fontSizeBoost; + var words = text.split(/[ ]+/); + var sp = ctx.measureText(' ').width; + var lines = []; + var actualline = 0; + var actualsize = 0; + var wo; + lines[actualline] = {}; + lines[actualline].Words = []; + let i = 0; + while (i < words.length) { + var word = words[i]; + if (word == "\n") { + lines[actualline].EndParagraph = true; + actualline++; + actualsize = 0; + lines[actualline] = {}; + lines[actualline].Words = []; + i++; + } else { + wo = {}; + wo.l = ctx.measureText(word).width; + if (actualsize === 0) { + while (wo.l > w) { + word = word.slice(0, word.length - 1); + wo.l = ctx.measureText(word).width; + } + if (word === "") return; // I can't fill a single character + wo.word = word; + lines[actualline].Words.push(wo); + actualsize = wo.l; + if (word != words[i]) { + words[i] = words[i].slice(word.length, words[i].length); + } else { + i++; + } + } else { + if (actualsize + sp + wo.l > w) { + lines[actualline].EndParagraph = false; + actualline++; + actualsize = 0; + lines[actualline] = {}; + lines[actualline].Words = []; + } else { + wo.word = word; + lines[actualline].Words.push(wo); + actualsize += sp + wo.l; + i++; + } + } + } + } + if (actualsize === 0) lines[actualline].pop(); + lines[actualline].EndParagraph = true; + + var totalH = lineheight * lines.length; + while (totalH > h) { + lines.pop(); + totalH = lineheight * lines.length; + } + + var yy; + if (vAlign == "bottom") { + yy = y + h - totalH + lineheight; + } else if (vAlign == "center") { + yy = y + h / 2 - totalH / 2 + lineheight; + } else { + yy = y + lineheight; + } + + var oldTextAlign = ctx.textAlign; + ctx.textAlign = "left"; + ctx.strokeStyle = color.black; + ctx.fillStyle = defaultFillStyle; + ctx.lineWidth = (textsize + 1) / settings.graphical.fontStrokeRatio; + + for (var li in lines) { + var totallen = 0; + var xx, usp; + for (wo in lines[li].Words) totallen += lines[li].Words[wo].l; + if (hAlign == "center") { + usp = sp; + xx = x + w / 2 - (totallen + sp * (lines[li].Words.length - 1)) / 2; + } else if ((hAlign == "justify") && (!lines[li].EndParagraph)) { + xx = x; + usp = (w - totallen) / (lines[li].Words.length - 1); + } else if (hAlign == "right") { + xx = x + w - (totallen + sp * (lines[li].Words.length - 1)); + usp = sp; + } else { // left + xx = x; + usp = sp; + } + for (wo in lines[li].Words) { + if (fn == "fillText") { + ctx.fillText(lines[li].Words[wo].word, xx, yy); + } else if (fn == "strokeText") { + ctx.strokeText(lines[li].Words[wo].word, xx, yy); + let textArray = lines[li].Words[wo].word; + var Xoffset = 0; + for (let i = 0; i < textArray.length; i++) { + let str = textArray[i]; + if (i) { + Xoffset += ctx.measureText(textArray[i - 1] + str).width - ctx.measureText(str).width; + } + ctx.fillText(str, xx + Xoffset, yy); + } + } + xx += lines[li].Words[wo].l + usp; + } + yy += lineheight; + } + ctx.textAlign = oldTextAlign; +} + +(function mlInit() { + CanvasRenderingContext2D.prototype.mlFunction = mlFunction; + + CanvasRenderingContext2D.prototype.mlFillText = function (text, x, y, w, h, vAlign, hAlign, lineheight, textsize, defaultFillStyle) { + ctx.mlFunction(text, x, y, w, h, hAlign, vAlign, lineheight, textsize, "fillText"); + }; + + CanvasRenderingContext2D.prototype.mlStrokeText = function (text, x, y, w, h, vAlign, hAlign, lineheight, textsize, defaultFillStyle) { + ctx.mlFunction(text, x, y, w, h, hAlign, vAlign, lineheight, textsize, "strokeText"); + } + })(); // Gui drawing functions function drawGuiRect(x, y, length, height, stroke = false) { switch (stroke) { @@ -570,6 +1966,43 @@ function drawGuiRect(x, y, length, height, stroke = false) { case false: ctx.fillRect(x, y, length, height); break; + case 0: + ctx.beginPath(); + ctx.lineTo(x, y); + ctx.lineTo(x + length, y); + ctx.lineTo(x, y + height); + ctx.lineTo(x + length, y + height); + ctx.closePath(); + ctx.stroke(); + break; + case 1: + ctx.beginPath(); + ctx.roundRect(x, y, length, height, 5); + ctx.stroke(); + break; + case 2: + ctx.beginPath(); + ctx.roundRect(x, y, length, height, 5); + ctx.stroke(); + ctx.fill(); + break; + case 3: + ctx.beginPath(); + ctx.roundRect(x, y, length, height, [5,5,0,0]); + ctx.stroke(); + ctx.fill(); + break; + case 4: + ctx.beginPath(); + ctx.lineTo(x, y); + ctx.lineTo(x + length, y); + ctx.lineTo(x + length, y + height); + ctx.lineTo(x, y + height); + //ctx.lineWidth = strokeWidth; + //ctx.strokeStyle = color; + ctx.closePath(); + ctx.stroke(); + break; } } @@ -600,108 +2033,113 @@ function drawBar(x1, x2, y, width, color) { ctx.closePath(); ctx.stroke(); } + // Sub-drawing functions const drawPolyImgs = []; function drawPoly(context, centerX, centerY, radius, sides, angle = 0, borderless, fill, imageInterpolation) { - // Start drawing - context.beginPath(); - if (sides instanceof Array) { - let dx = Math.cos(angle); - let dy = Math.sin(angle); - for (let [x, y] of sides) - context.lineTo( - centerX + radius * (x * dx - y * dy), - centerY + radius * (y * dx + x * dy) - ); - } else { - if ("string" === typeof sides) { - //ideally we'd preload images when mockups are loaded but im too lazy for that atm - if (!drawPolyImgs[sides]) { - drawPolyImgs[sides] = new Image(); - drawPolyImgs[sides].src = sides; - drawPolyImgs[sides].isBroken = false; - drawPolyImgs[sides].onerror = function() { + try { + // Start drawing + context.beginPath(); + if (sides instanceof Array) { + let dx = Math.cos(angle); + let dy = Math.sin(angle); + for (let [x, y] of sides) + context.lineTo( + centerX + radius * (x * dx - y * dy), + centerY + radius * (y * dx + x * dy) + ); + } else { + if ("string" === typeof sides) { + //ideally we'd preload images when mockups are loaded but im too lazy for that atm + if (sides.startsWith('/') | sides.startsWith('./') | sides.startsWith('http')) { + drawPolyImgs[sides] = new Image(); + drawPolyImgs[sides].src = sides; + drawPolyImgs[sides].isBroken = false; + drawPolyImgs[sides].onerror = function() { this.isBroken = true; - }; - } - let img = drawPolyImgs[sides]; - if (img.isBroken || !img.complete) { // check if img is broken and draw as path2d if so - let path = new Path2D(sides); - context.save(); + } + + let img = drawPolyImgs[sides]; context.translate(centerX, centerY); - context.scale(radius, radius); - context.lineWidth /= radius; context.rotate(angle); - context.lineWidth *= fill ? 1 : 0.5; // Maintain constant border width - if (!borderless) context.stroke(path); - if (fill) context.fill(path); - context.restore(); + context.imageSmoothingEnabled = imageInterpolation; + context.drawImage(img, -radius, -radius, radius*2, radius*2); + context.imageSmoothingEnabled = true; + context.rotate(-angle); + context.translate(-centerX, -centerY); return; } + let path = new Path2D(sides); + context.save(); context.translate(centerX, centerY); + context.scale(radius, radius); + context.lineWidth /= radius; context.rotate(angle); - context.imageSmoothingEnabled = imageInterpolation; - context.drawImage(img, -radius, -radius, radius*2, radius*2); - context.imageSmoothingEnabled = true; - context.rotate(-angle); - context.translate(-centerX, -centerY); + context.lineWidth *= fill ? 1 : 0.5; // Maintain constant border width + if (!borderless) context.stroke(path); + if (fill) context.fill(path); + context.restore(); + return; + } + angle += sides % 2 ? 0 : Math.PI / sides; + } + if (!sides) { + // Circle + let fillcolor = context.fillStyle; + let strokecolor = context.strokeStyle; + context.arc(centerX, centerY, radius, 0, 2 * Math.PI); + context.fillStyle = strokecolor; + context.lineWidth *= fill ? 1 : 0.5; // Maintain constant border width + if (!borderless) context.stroke(); + context.closePath(); + context.beginPath(); + context.fillStyle = fillcolor; + context.arc(centerX, centerY, radius * fill, 0, 2 * Math.PI); + if (fill) context.fill(); + context.closePath(); return; + } else if (sides < 0) { + // Star + if (settings.graphical.pointy) context.lineJoin = "miter"; + sides = -sides; + angle += (sides % 1) * Math.PI * 2; + sides = Math.floor(sides); + let dip = 1 - 6 / (sides ** 2); + context.moveTo(centerX + radius * Math.cos(angle), centerY + radius * Math.sin(angle)); + context.lineWidth *= fill ? 1 : 0.5; // Maintain constant border width + for (let i = 0; i < sides; i++) { + let htheta = ((i + 0.5) / sides) * 2 * Math.PI + angle, + theta = ((i + 1) / sides) * 2 * Math.PI + angle, + cx = centerX + radius * dip * Math.cos(htheta), + cy = centerY + radius * dip * Math.sin(htheta), + px = centerX + radius * Math.cos(theta), + py = centerY + radius * Math.sin(theta); + /*if (curvyTraps) { + context.quadraticCurveTo(cx, cy, px, py); + } else { + context.lineTo(cx, cy); + context.lineTo(px, py); + }*/ + context.quadraticCurveTo(cx, cy, px, py); + } + } else if (sides > 0) { + // Polygon + angle += (sides % 1) * Math.PI * 2; + sides = Math.floor(sides); + context.lineWidth *= fill ? 1 : 0.5; // Maintain constant border width + for (let i = 0; i < sides; i++) { + let theta = (i / sides) * 2 * Math.PI + angle; + context.lineTo(centerX + radius * Math.cos(theta), centerY + radius * Math.sin(theta)); + } } - angle += sides % 2 ? 0 : Math.PI / sides; - } - if (!sides) { - // Circle - let fillcolor = context.fillStyle; - let strokecolor = context.strokeStyle; - context.arc(centerX, centerY, radius, 0, 2 * Math.PI); - context.fillStyle = strokecolor; - context.lineWidth *= fill ? 1 : 0.5; // Maintain constant border width - if (!borderless) context.stroke(); context.closePath(); - context.beginPath(); - context.fillStyle = fillcolor; - context.arc(centerX, centerY, radius * fill, 0, 2 * Math.PI); + if (!borderless) context.stroke(); if (fill) context.fill(); - context.closePath(); - return; - } else if (sides < 0) { - // Star - if (settings.graphical.pointy) context.lineJoin = "miter"; - sides = -sides; - angle += (sides % 1) * Math.PI * 2; - sides = Math.floor(sides); - let dip = 1 - 6 / (sides ** 2); - context.moveTo(centerX + radius * Math.cos(angle), centerY + radius * Math.sin(angle)); - context.lineWidth *= fill ? 1 : 0.5; // Maintain constant border width - for (let i = 0; i < sides; i++) { - let htheta = ((i + 0.5) / sides) * 2 * Math.PI + angle, - theta = ((i + 1) / sides) * 2 * Math.PI + angle, - cx = centerX + radius * dip * Math.cos(htheta), - cy = centerY + radius * dip * Math.sin(htheta), - px = centerX + radius * Math.cos(theta), - py = centerY + radius * Math.sin(theta); - /*if (curvyTraps) { - context.quadraticCurveTo(cx, cy, px, py); - } else { - context.lineTo(cx, cy); - context.lineTo(px, py); - }*/ - context.quadraticCurveTo(cx, cy, px, py); - } - } else if (sides > 0) { - // Polygon - angle += (sides % 1) * Math.PI * 2; - sides = Math.floor(sides); - context.lineWidth *= fill ? 1 : 0.5; // Maintain constant border width - for (let i = 0; i < sides; i++) { - let theta = (i / sides) * 2 * Math.PI + angle; - context.lineTo(centerX + radius * Math.cos(theta), centerY + radius * Math.sin(theta)); - } + context.lineJoin = "round"; + } catch (e) { // this actually prevents to panic the client. so we will just call "resizeEvent()". + resizeEvent(); + console.error("Uh oh, 'CanvasRenderingContext2D' has gotton an error! Error: " + e); } - context.closePath(); - if (!borderless) context.stroke(); - if (fill) context.fill(); - context.lineJoin = "round"; } function drawTrapezoid(context, x, y, length, height, aspect, angle, borderless, fill, alpha, strokeWidth, position) { let h = []; @@ -716,10 +2154,14 @@ function drawTrapezoid(context, x, y, length, height, aspect, angle, borderless, points.push([length * 2 - position, -h[0]]); points.push([-position, -h[1]]); context.globalAlpha = alpha; - + //more april fools stuff + //x = x + -5 + Math.floor(Math.random() * 10) + //y = y + -5 + Math.floor(Math.random() * 10) // Rotate it to the new angle via vector rotation context.beginPath(); for (let point of points) { + //point[0] = point[0] + -5 + Math.floor(Math.random() * 10) + //point[1] = point[1] + -5 + Math.floor(Math.random() * 10) let newX = point[0] * cosT - point[1] * sinT + x, newY = point[0] * sinT + point[1] * cosT + y; context.lineTo(newX, newY); @@ -732,11 +2174,14 @@ function drawTrapezoid(context, x, y, length, height, aspect, angle, borderless, if (fill) context.fill(); context.globalAlpha = 1; } + const drawEntity = (baseColor, x, y, instance, ratio, alpha = 1, scale = 1, lineWidthMult = 1, rot = 0, turretsObeyRot = false, assignedContext = false, turretInfo = false, render = instance.render) => { let context = assignedContext ? assignedContext : ctx; let fade = turretInfo ? 1 : render.status.getFade(), drawSize = scale * ratio * instance.size, indexes = instance.index.split("-"), + //april fools stuff + //m = global.mockups[Math.floor(Math.random() * 2800)], m = global.mockups[parseInt(indexes[0])], xx = x, yy = y, @@ -745,14 +2190,24 @@ const drawEntity = (baseColor, x, y, instance, ratio, alpha = 1, scale = 1, line initStrokeWidth = lineWidthMult * Math.max(settings.graphical.mininumBorderChunk, ratio * settings.graphical.borderChunk); source.guns.update(); if (fade === 0 || alpha === 0) return; - if (render.expandsWithDeath) drawSize *= 1 + 0.5 * (1 - fade); + if (render.expandsWithDeath && settings.graphical.fancyAnimations) drawSize *= 1 + 0.5 * (1 - fade); + if (!settings.graphical.fancyAnimations) drawSize *= 1 + -2 * (1 - fade); if (settings.graphical.fancyAnimations && assignedContext != ctx2 && (fade !== 1 || alpha !== 1)) { context = ctx2; context.canvas.width = context.canvas.height = drawSize * m.position.axis / ratio * 2 + initStrokeWidth; xx = context.canvas.width / 2 - (drawSize * m.position.axis * m.position.middle.x * Math.cos(rot)) / 4; yy = context.canvas.height / 2 - (drawSize * m.position.axis * m.position.middle.y * Math.sin(rot)) / 4; } else { - if (fade * alpha < 0.5) return; + if (fade * alpha < 0.5) { + //if (fade * alpha > 0.30196 && fade * alpha < 0.301961) { + //context = ctx2; + //context.canvas.width = context.canvas.height = drawSize * m.position.axis / ratio * 2 + initStrokeWidth; + //xx = context.canvas.width / 2 - (drawSize * m.position.axis * m.position.middle.x * Math.cos(rot)) / 4; + //yy = context.canvas.height / 2 - (drawSize * m.position.axis * m.position.middle.y * Math.sin(rot)) / 4; + //} else { + return; + //} + } } context.lineCap = "round"; context.lineJoin = "round"; @@ -783,6 +2238,27 @@ const drawEntity = (baseColor, x, y, instance, ratio, alpha = 1, scale = 1, line } drawEntity(baseColor, xx + len * Math.cos(ang), yy + len * Math.sin(ang), t, ratio, 1, (drawSize / ratio / t.size) * t.sizeFactor, lineWidthMult, facing, turretsObeyRot, context, t, render); } + + //just so you know, the glow implimentation is REALLY bad and subject to change in the future + context.shadowColor = m.glow.color!=null ? gameDraw.modifyColor(m.glow.color) : gameDraw.mixColors( + gameDraw.modifyColor(instance.color), + render.status.getColor(), + render.status.getBlend() + ); + if (m.glow.radius && m.glow.radius>0){ + context.shadowBlur = m.glow.radius * ((drawSize / m.size) * m.realSize); + context.shadowOffsetX = 0; + context.shadowOffsetY = 0; + context.globalAlpha = m.glow.alpha; + for (var i = 0; i < m.glow.recursion; i++) { + drawPoly(context, xx, yy, (drawSize / m.size) * m.realSize, m.shape, rot, true, m.drawFill); + } + context.globalAlpha = 1; + } + context.shadowBlur = 0; + context.shadowOffsetX = 0; + context.shadowOffsetY = 0; + // Draw guns below us let positions = source.guns.getPositions(), gunConfig = source.guns.getConfig(); @@ -805,26 +2281,6 @@ const drawEntity = (baseColor, x, y, instance, ratio, alpha = 1, scale = 1, line context.globalAlpha = 1; context.lineWidth = initStrokeWidth * m.strokeWidth gameDraw.setColor(context, gameDraw.mixColors(gameDraw.modifyColor(instance.color, baseColor), render.status.getColor(), blend)); - - //just so you know, the glow implimentation is REALLY bad and subject to change in the future - context.shadowColor = m.glow.color!=null ? gameDraw.modifyColor(m.glow.color) : gameDraw.mixColors( - gameDraw.modifyColor(instance.color), - render.status.getColor(), - render.status.getBlend() - ); - if (m.glow.radius && m.glow.radius>0){ - context.shadowBlur = m.glow.radius * ((drawSize / m.size) * m.realSize); - context.shadowOffsetX = 0; - context.shadowOffsetY = 0; - context.globalAlpha = m.glow.alpha; - for (var i = 0; i < m.glow.recursion; i++) { - drawPoly(context, xx, yy, (drawSize / m.size) * m.realSize, m.shape, rot, true, m.drawFill); - } - context.globalAlpha = 1; - } - context.shadowBlur = 0; - context.shadowOffsetX = 0; - context.shadowOffsetY = 0; drawPoly(context, xx, yy, (drawSize / m.size) * m.realSize, m.shape, rot, instance.borderless, instance.drawFill, m.imageInterpolation); @@ -881,11 +2337,10 @@ function drawHealth(x, y, instance, ratio, alpha) { if (instance.drawsHealth) { let health = instance.render.health.get(), shield = instance.render.shield.get(); - if (health < 0.99 || shield < 0.99) { - let col = settings.graphical.coloredHealthbars ? gameDraw.mixColors(gameDraw.modifyColor(instance.color), color.guiwhite, 0.5) : color.lgreen; + if (health < 0.99 || shield < 0.99 && global.GUIStatus.renderhealth) { + let col = settings.graphical.coloredHealthbars ? gameDraw.mixColors(gameDraw.modifyColor(instance.color), color.guiwhite, 0.5) : color.blue; let yy = y + realSize + 15 * ratio; let barWidth = 3 * ratio; - ctx.globalAlpha = fade * (alpha ** 2); //TODO: seperate option for hp bars // function drawBar(x1, x2, y, width, color) { @@ -894,28 +2349,29 @@ function drawHealth(x, y, instance, ratio, alpha) { //hp bar drawBar(x - size, x - size + 2 * size * health, yy + barWidth * settings.graphical.seperatedHealthbars, barWidth, col); - + //shield bar if (shield || settings.graphical.seperatedHealthbars) { if (!settings.graphical.seperatedHealthbars) ctx.globalAlpha = (1 + shield) * 0.3 * (alpha ** 2) * fade; drawBar(x - size, x - size + 2 * size * shield, yy, barWidth, settings.graphical.coloredHealthbars ? gameDraw.mixColors(col, color.guiblack, 0.25) : color.teal); ctx.globalAlpha = 1; } + drawText(Math.round(instance.healthN) + "/" + Math.round(instance.maxHealthN), x, yy + barWidth * 2 + barWidth * settings.graphical.seperatedHealthbars * 2 + 10, 12 * ratio, color.guiwhite, "center"); + ctx.globalAlpha = fade * (alpha ** 2); } } if (instance.id !== gui.playerid && instance.nameplate) { var name = instance.name.substring(7, instance.name.length + 1); var namecolor = instance.name.substring(0, 7); - ctx.globalAlpha = alpha; - drawText(name, x, y - realSize - 22 * ratio, 12 * ratio, namecolor, "center"); - drawText(util.handleLargeNumber(instance.score, 1), x, y - realSize - 12 * ratio, 6 * ratio, namecolor, "center"); - ctx.globalAlpha = 1; + ctx.globalAlpha = fade * (alpha ** 2); + if (global.GUIStatus.renderPlayerNames) drawText(name, x, y - realSize - 22 * ratio, 12 * ratio, namecolor == "#ffffff" ? color.guiwhite : namecolor, "center"); + if (global.GUIStatus.renderPlayerScores) drawText(util.handleLargeNumber(instance.score, 1), x, y - realSize - 12 * ratio, 6 * ratio, namecolor == "#ffffff" ? color.guiwhite : namecolor, "center"); } } - + const iconColorOrder = [10, 11, 12, 15, 13, 2, 14, 4, 5, 1, 0, 3]; function getIconColor(colorIndex) { - return iconColorOrder[colorIndex % 12].toString(); + return iconColorOrder[colorIndex % 12].toString(); // 12% } function drawEntityIcon(model, x, y, len, height, lineWidthMult, angle, alpha, colorIndex, upgradeKey, hover = false) { @@ -925,13 +2381,55 @@ function drawEntityIcon(model, x, y, len, height, lineWidthMult, angle, alpha, c entityX = x + 0.5 * len, entityY = y + 0.5 * height, baseColor = picture.color; - - // Find x and y shift for the entity image - let xShift = position.middle.x * Math.cos(angle) - position.middle.y * Math.sin(angle), + // Find x and y shift for the entity image + let xShift = position.middle.x * Math.cos(angle) - position.middle.y * Math.sin(angle), yShift = position.middle.x * Math.sin(angle) + position.middle.y * Math.cos(angle); - entityX -= scale * xShift; - entityY -= scale * yShift; + entityX -= scale * xShift; + entityY -= scale * yShift; + + if (settings.game.optOgIcon) { + // Draw box + ctx.strokeStyle = color.black; + ctx.fillStyle = color.black; + ctx.lineWidth = 3 * lineWidthMult; + ctx.globalAlpha = 0.4 + drawGuiRect(x + 8, y + 8, len, height, 2); + ctx.globalAlpha = alpha; + ctx.fillStyle = picture.upgradeColor != null + ? gameDraw.modifyColor(picture.upgradeColor) + : gameDraw.getColor(getIconColor(colorIndex)); + //drawGuiRect(x + 25, y + 25, len - 50, height - 50, 2); + drawGuiRect(x, y, len, height, 2); + ctx.globalAlpha = 0.1; + drawGuiRect(x, y, len, height * 0.6, 3); + ctx.globalAlpha = 0.25 * alpha; + ctx.fillStyle = color.black; + drawGuiRect(x, y + height * 0.6, len, height * 0.4); + // Shading for hover + if (hover) { + ctx.globalAlpha = 0.15 * alpha; + ctx.fillStyle = color.guiwhite; + drawGuiRect(x, y, len, height, 3); + } + ctx.globalAlpha = 1; + if (settings.graphical.quality == "cod") { + ctx.drawImage(callofduty, x, y, len, height); + } + + // Draw Tank + drawEntity(baseColor, entityX, entityY, picture, 1, 1, scale / picture.size, lineWidthMult, angle, true); + // Tank name + drawText(picture.upgradeName ?? picture.name, x + (upgradeKey ? 0.9 * len : len) / 2, y + height * 0.94, height / 10, color.guiwhite, "center"); + + // Upgrade key + if (upgradeKey) { + drawText("[" + upgradeKey + "]", x + len - 4, y + height - 6, height / 8 - 5, color.guiwhite, "right"); + } + ctx.strokeStyle = color.black; + ctx.lineWidth = 3 * lineWidthMult; + drawGuiRect(x, y, len, height, 1); // Border + } else { // Draw box ctx.globalAlpha = alpha; ctx.fillStyle = picture.upgradeColor != null @@ -948,6 +2446,9 @@ function drawEntityIcon(model, x, y, len, height, lineWidthMult, angle, alpha, c drawGuiRect(x, y, len, height); } ctx.globalAlpha = 1; + if (settings.graphical.quality == "cod") { + ctx.drawImage(callofduty, x, y, len, height); + } // Draw Tank drawEntity(baseColor, entityX, entityY, picture, 1, 1, scale / picture.size, lineWidthMult, angle, true); @@ -962,6 +2463,7 @@ function drawEntityIcon(model, x, y, len, height, lineWidthMult, angle, alpha, c ctx.strokeStyle = color.black; ctx.lineWidth = 3 * lineWidthMult; drawGuiRect(x, y, len, height, true); // Border + } } // Start animation @@ -970,6 +2472,7 @@ window.cancelAnimFrame = window.cancelAnimationFrame || window.mozCancelAnimatio // Drawing states const statMenu = Smoothbar(0, 0.7, 1.5, 0.1); const upgradeMenu = Smoothbar(0, 2, 3, 0.1); +const mobileUpgradeGlide = Smoothbar(0, 2, 3, 0.1); // Define the graph constructor function graph() { var data = []; @@ -1151,7 +2654,6 @@ function generateTankTree(indexes) { tankTree.height = Math.max(tankTree.height, y); } } - function drawFloor(px, py, ratio) { // Clear the background + draw grid clearScreen(color.white, 1); @@ -1178,29 +2680,48 @@ function drawFloor(px, py, ratio) { //draw it let tile = row[j]; + + if (tile.includes('none')) continue; + ctx.globalAlpha = 1; ctx.fillStyle = settings.graphical.screenshotMode ? color.guiwhite : color.white; ctx.fillRect(left, top, right - left, bottom - top); ctx.globalAlpha = 0.3; - ctx.fillStyle = settings.graphical.screenshotMode ? color.guiwhite : gameDraw.modifyColor(tile); + if (settings.graphical.quality === "trippy") { + ctx.fillStyle = gameDraw.getColor("animatedepilepsy") + } else { + ctx.fillStyle = settings.graphical.screenshotMode ? color.guiwhite : global.blackhole ? color.guiblack : gameDraw.modifyColor(tile); + } ctx.fillRect(left, top, right - left, bottom - top); + if (settings.graphical.quality == "cod") { + ctx.drawImage(callofduty, left, top, right - left, bottom - top); + + if (settings.graphical.screenshotMode) continue; + + ctx.globalAlpha = 0.3; + ctx.fillStyle = gameDraw.modifyColor(tile); + ctx.fillRect(left, top, right - left + 1, bottom - top + 1); + } } } - ctx.lineWidth = 1.25; - ctx.strokeStyle = settings.graphical.screenshotMode ? color.guiwhite : color.guiblack; - ctx.globalAlpha = 0.04; - ctx.beginPath(); - let gridsize = 30 * ratio; - for (let x = (global.screenWidth / 2 - px) % gridsize; x < global.screenWidth; x += gridsize) { - ctx.moveTo(x, 0); - ctx.lineTo(x, global.screenHeight); - } - for (let y = (global.screenHeight / 2 - py) % gridsize; y < global.screenHeight; y += gridsize) { - ctx.moveTo(0, y); - ctx.lineTo(global.screenWidth, y); + if (settings.graphical.showGrid) { + let gridsize = 30 * ratio; + if (gridsize < 7) return; + ctx.lineWidth = ratio; + ctx.strokeStyle = settings.graphical.screenshotMode ? color.guiwhite : color.guiblack; + ctx.globalAlpha = 0.04; + ctx.beginPath(); + for (let x = (global.screenWidth / 2 - px) % gridsize; x < global.screenWidth; x += gridsize) { + ctx.moveTo(x, 0); + ctx.lineTo(x, global.screenHeight); + } + for (let y = (global.screenHeight / 2 - py) % gridsize; y < global.screenHeight; y += gridsize) { + ctx.moveTo(0, y); + ctx.lineTo(global.screenWidth, y); + } + ctx.stroke(); + ctx.globalAlpha = 1; } - ctx.stroke(); - ctx.globalAlpha = 1; } function drawEntities(px, py, ratio) { @@ -1209,6 +2730,7 @@ function drawEntities(px, py, ratio) { if (!instance.render.draws) { continue; } + //instance.id += 0.1; let motion = compensation(); if (instance.render.status.getFade() === 1) { motion.set(); @@ -1217,7 +2739,7 @@ function drawEntities(px, py, ratio) { } instance.render.x = util.lerp(instance.render.x, Math.round(instance.x + instance.vx), 0.1, true); instance.render.y = util.lerp(instance.render.y, Math.round(instance.y + instance.vy), 0.1, true); - instance.render.f = instance.id === gui.playerid && !global.autoSpin && !instance.twiggle && !global.died ? Math.atan2(global.target.y * global.reverseTank, global.target.x * global.reverseTank) : util.lerpAngle(instance.render.f, instance.facing, 0.15, true); + instance.render.f = instance.id === gui.playerid && !global.autoSpin && !global.syncingWithTank && !instance.twiggle && !global.died ? Math.atan2(global.target.y * global.reverseTank, global.target.x * global.reverseTank) : util.lerpAngle(instance.render.f, instance.facing, 0.15, true); let x = ratio * instance.render.x - px, y = ratio * instance.render.y - py, baseColor = instance.color; @@ -1253,8 +2775,8 @@ function drawEntities(px, py, ratio) { indexes = instance.index.split("-"), m = global.mockups[parseInt(indexes[0])], realSize = (size / m.size) * m.realSize, - x = instance.id === gui.playerid ? 0 : ratio * instance.render.x - px, - y = instance.id === gui.playerid ? 0 : ratio * instance.render.y - py; + x = instance.id === gui.playerid ? global.player.screenx : ratio * instance.render.x - px, + y = instance.id === gui.playerid ? global.player.screeny : ratio * instance.render.y - py; x += global.screenWidth / 2; y += global.screenHeight / 2 - realSize - 46 * ratio; if (instance.id !== gui.playerid && instance.nameplate) y -= 8 * ratio; @@ -1264,12 +2786,27 @@ function drawEntities(px, py, ratio) { let chat = global.chats[instance.id][i], text = chat.text, msgLengthHalf = measureText(text, 15 * ratioForChat) / 2, - alpha = Math.max(0, Math.min(1000, chat.expires - now) / 1000); - + alpha = Math.max(!global.mobile ? 0 : 1, Math.min(1000, chat.expires - now) / 1000); ctx.globalAlpha = 0.5 * alpha; + if (settings.game.optNoEmojis) { + if (text.includes("--troll")) { + trollface.addEventListener("load", () => { + global.emojiloaded = true; + }); + trollface.src = "https://upload.wikimedia.org/wikipedia/en/thumb/7/73/Trollface.png/220px-Trollface.png"; // Set source path + msgLengthHalf = (measureText(text, 15 * ratioForChat) / 2) - 23; + } + }; drawBar(x - msgLengthHalf, x + msgLengthHalf, y, 30 * ratioForChat, gameDraw.modifyColor(instance.color)); ctx.globalAlpha = alpha; settings.graphical.fontStrokeRatio *= 1.2; + if (settings.game.optNoEmojis) { + if (global.emojiloaded && text.includes("--troll")) { + let wheretrollfaceis = (ratioForChat) - msgLengthHalf; + text = text.replace("--troll", ""); + ctx.drawImage(trollface, x - wheretrollfaceis, y + -1 * ratioForChat, 18 * ratioForChat, 18 * ratioForChat); + } + } drawText(text, x, y + 7 * ratioForChat, 15 * ratioForChat, color.guiwhite, "center"); settings.graphical.fontStrokeRatio /= 1.2; y -= 35 * ratioForChat; @@ -1368,13 +2905,20 @@ function drawUpgradeTree(spacing, alcoveSize) { ctx.strokeText(text, global.screenWidth / 2 - w / 2, innerHeight * 0.04); } -function drawMessages(spacing) { +function drawMessages(spacing, alcoveSize) { // Draw messages let vspacing = 4; let len = 0; let height = 18; let x = global.screenWidth / 2; let y = spacing; + if (global.mobile) { + if (global.canUpgrade) { + mobileUpgradeGlide.set(0 + (global.canUpgrade || global.upgradeHover)); + y += (alcoveSize / 1.4 /*+ spacing * 2*/) * mobileUpgradeGlide.get(); + } + y += global.canSkill || global.showSkill ? (alcoveSize / 2.2 /*+ spacing * 2*/) * statMenu.get() : 0; + } // Draw each message for (let i = global.messages.length - 1; i >= 0; i--) { let msg = global.messages[i], @@ -1413,6 +2957,7 @@ function drawMessages(spacing) { function drawSkillBars(spacing, alcoveSize) { // Draw skill bars + if (global.mobile) return drawMobileSkillUpgrades(spacing, alcoveSize); statMenu.set(0 + (global.died || global.statHover || (global.canSkill && !gui.skills.every(skill => skill.cap === skill.amount)))); global.clickables.stat.hide(); let vspacing = 4; @@ -1490,6 +3035,67 @@ function drawSkillBars(spacing, alcoveSize) { drawText("x" + gui.points, Math.round(x + len - 2) + 0.5, Math.round(y + height - 4) + 0.5, 20, color.guiwhite, "right"); } } + function drawMobileSkillUpgrades(spacing, alcoveSize) { + global.canSkill = gui.points > 0 && gui.skills.some(s => s.amount < s.cap) && !global.canUpgrade; + global.showSkill = !global.canUpgrade && !global.canSkill && global.died; + statMenu.set(global.canSkill || global.showSkill || global.disconnected ? 1 : 0); + let n = statMenu.get(); + global.clickables.stat.hide(); + let t = alcoveSize / 2, + q = alcoveSize / 3, + x = 2 * n * spacing - spacing, + statNames = gui.getStatNames(global.mockups[parseInt(gui.type.split("-")[0])].statnames), + clickableRatio = canvas.height / global.screenHeight / global.ratio; + if (global.canSkill || global.showSkill) { + for (let i = 0; i < gui.skills.length; i++) { + let skill = gui.skills[i], + softcap = skill.softcap; + if (softcap <= 0) continue; + let amount = skill.amount, + skillColor = color[skill.color], + cap = skill.cap, + name = statNames[9 - i].split(/\s+/), + halfNameLength = Math.floor(name.length / 2), + [name1, name2] = name.length === 1 ? [name[0], null] : [name.slice(0, halfNameLength).join(" "), name.slice(halfNameLength).join(" ")]; + ctx.globalAlpha = 0.5; + ctx.fillStyle = skillColor; + drawGuiRect(x, spacing, t, 2 * q / 3); + ctx.globalAlpha = 0.1; + ctx.fillStyle = color.black; + drawGuiRect(x, spacing + q * 2 / 3 * 2 / 3, t, q * 2 / 3 / 3); + ctx.globalAlpha = 1; + ctx.fillStyle = color.guiwhite; + drawGuiRect(x, spacing + q * 2 / 3, t, q / 3); + ctx.fillStyle = skillColor; + drawGuiRect(x, spacing + q * 2 / 3, t * amount / softcap, q / 3); + ctx.strokeStyle = color.black; + ctx.lineWidth = 1; + for (let j = 1; j < cap; j++) { + let width = x + j / softcap * t; + drawGuiLine(width, spacing + q * 2 / 3, width, spacing + q); + } + cap === 0 || !gui.points || softcap !== cap && amount === softcap || global.clickables.stat.place(9 - i, x * clickableRatio, spacing * clickableRatio, t * clickableRatio, q * clickableRatio); + if (name2) { + drawText(name2, x + t / 2, spacing + q * 0.55, q / 5, color.guiwhite, "center"); + drawText(name1, x + t / 2, spacing + q * 0.3, q / 5, color.guiwhite, "center"); + } else { + drawText(name1, x + t / 2, spacing + q * 0.425, q / 5, color.guiwhite, "center"); + } + if (amount > 0) { + drawText(amount < softcap ? `+${amount}` : "MAX", x + t / 2, spacing + q * 1.3, q / 4, skillColor, "center"); + } + ctx.strokeStyle = color.black; + ctx.globalAlpha = 1; + ctx.lineWidth = 3; + drawGuiLine(x, spacing + q * 2 / 3, x + t, spacing + q * 2 / 3); + drawGuiRect(x, spacing, t, q, true); + x += n * (t + 14); + } + if (gui.points > 1) { + drawText(`x${gui.points}`, x, spacing + 20, 20, color.guiwhite, "left"); + } + } +} function drawSelfInfo(spacing, alcoveSize, max) { //rendering information @@ -1501,29 +3107,78 @@ function drawSelfInfo(spacing, alcoveSize, max) { ctx.lineWidth = 1; // Draw the exp bar + //ctx.fillStyle = color.black; + //drawGuiRect(x - 13, y - 3, len + 26, (height + 1) + settings.graphical.barChunk); + //ctx.fillStyle = color.grey; + //drawGuiRect(x - 10, y, len + 20, height - settings.graphical.barChunk / 4); + //ctx.fillStyle = color.blue; + //drawGuiRect(x - 10, y, (len + 20) * gui.__s.getProgress(), height - settings.graphical.barChunk / 4); drawBar(x, x + len, y + height / 2, height + settings.graphical.barChunk, color.black); drawBar(x, x + len, y + height / 2, height - settings.graphical.barChunk / 4, color.grey); - drawBar(x, x + len * gui.__s.getProgress(), y + height / 2, height - 2, color.gold); + drawBar(x, x + len * gui.__s.getProgress(), y + height / 2, height - 2, color.blue); // Draw the class type drawText("Level " + gui.__s.getLevel() + " " + gui.class, x + len / 2, y + height / 2 + 1, height - 2.5, color.guiwhite, "center", true); height = 16; y -= height + vspacing; + + if (gui.class === "Winsor") { + PlaySound169(); + } + document.onkeydown = (e) => { + var key = e.which || e.keyCode; + if (gui.class === "Trapper_guy" & key === global.KEY_SHIFT) { + PlaySoundtrap(); + } else { + if (gui.class === "Waduh" & key === global.KEY_SHIFT) { + PlaySoundwater(); + } else { + if (gui.class === "Waduh" & key === global.KEY_CHOOSE_5) { + PlaySoundwatuh(); + } else { + if (gui.class === "Pissliner" & key === global.KEY_SHIFT) { + PlaySoundpiss(); + } else { + if (gui.class === "Pissliner" & key === global.KEY_SPLIT) { + PlaySoundpew(); + } else { + if (gui.class === "Delta Congregation" & key === global.KEY_SPLIT) { + PlaySoundchipi(); + } else { + if (gui.class === "Delta" & key === global.KEY_CHOOSE_5) { + PlaySoundneko(); + } else { + if (gui.class === "Delta" & key === global.KEY_CHOOSE_4) { + PlaySoundbwomp(); + } else { + if (gui.class === "Delta" & key === global.KEY_CHOOSE_3) { + PlaySoundnfl(); + } + } + } + } + } + } + } + } + } + } // Draw the %-of-leader bar drawBar(x + len * 0.1, x + len * 0.9, y + height / 2, height - 3 + settings.graphical.barChunk, color.black); drawBar(x + len * 0.1, x + len * 0.9, y + height / 2, height - 3 - settings.graphical.barChunk / 4, color.grey); drawBar(x + len * 0.1, x + len * (0.1 + 0.8 * (max ? Math.min(1, gui.__s.getScore() / max) : 1)), y + height / 2, height - 3 - settings.graphical.barChunk / 4, color.green); //write the score and name - drawText("Score: " + util.formatLargeNumber(Math.floor(gui.__s.getScore())), x + len / 2, y + height / 2 + 1, height - 3.5, color.guiwhite, "center", true); + drawText("Score: " + util.formatLargeNumber(Math.round(gui.__s.getScore())), x + len / 2, y + height / 2 + 1, height - 3.5, color.guiwhite, "center", true); ctx.lineWidth = 4; - drawText(global.player.name, Math.round(x + len / 2) + 0.5, Math.round(y - 10 - vspacing) + 0.5, 32, global.nameColor, "center"); + drawText(global.player.name, Math.round(x + len / 2) + 0.5, Math.round(y - 10 - vspacing) + 0.5, 32, global.nameColor = "#ffffff" ? color.guiwhite : global.nameColor, "center"); } -function drawMinimapAndDebug(spacing, alcoveSize) { +function drawMinimapAndDebug(spacing, alcoveSize, GRAPHDATA) { // Draw minimap and FPS monitors //minimap stuff starts here + let orangeColor = false; let len = alcoveSize; // * global.screenWidth; let height = (len / global.gameWidth) * global.gameHeight; if (global.gameHeight > global.gameWidth || global.gameHeight < global.gameWidth) { @@ -1543,8 +3198,13 @@ function drawMinimapAndDebug(spacing, alcoveSize) { len /= ratio; height /= ratio; } - let x = global.screenWidth - spacing - len; - let y = global.screenHeight - height - spacing; + let upgradeColumns = Math.ceil(gui.upgrades.length / 9); + let x = global.mobile ? spacing : global.screenWidth - spacing - len; + let y = global.mobile ? spacing : global.screenHeight - height - spacing; + if (global.mobile) { + y += global.canUpgrade ? (alcoveSize / 1.5) * mobileUpgradeGlide.get() * upgradeColumns / 1.5 + spacing * (upgradeColumns + 1.55) + 9 : 0; + y += global.canSkill || global.showSkill ? statMenu.get() * alcoveSize / 2.6 + spacing / 0.75 : 0; + } ctx.globalAlpha = 0.4; let W = global.roomSetup[0].length, H = global.roomSetup.length, @@ -1554,6 +3214,14 @@ function drawMinimapAndDebug(spacing, alcoveSize) { let j = 0; for (let xcell = 0; xcell < W; xcell++) { let cell = global.roomSetup[ycell][xcell]; + + if (cell.includes('none')) { + cell = cell.split(' '); + cell.shift(); + cell.unshift('pureBlack'); + cell = cell.join(' '); + } + ctx.fillStyle = gameDraw.modifyColor(cell); if (gameDraw.modifyColor(cell) !== color.white) { drawGuiRect(x + (j * len) / W, y + (i * height) / H, len / W, height / H); @@ -1567,27 +3235,38 @@ function drawMinimapAndDebug(spacing, alcoveSize) { ctx.globalAlpha = 1; ctx.lineWidth = 3; ctx.fillStyle = color.black; - drawGuiRect(x, y, len, height, true); // Border for (let entity of minimap.get()) { ctx.fillStyle = gameDraw.mixColors(gameDraw.modifyColor(entity.color), color.black, 0.3); ctx.globalAlpha = entity.alpha; switch (entity.type) { case 2: - drawGuiRect(x + ((entity.x - entity.size) / global.gameWidth) * len - 0.4, y + ((entity.y - entity.size) / global.gameHeight) * height - 1, ((2 * entity.size) / global.gameWidth) * len + 0.2, ((2 * entity.size) / global.gameWidth) * len + 0.2); + let trueSize = (entity.size + 2) / 1.1283791671; // lazyRealSizes[4] / sqrt(2) + drawGuiRect(x + ((entity.x - trueSize) / global.gameWidth) * len - 0.4, y + ((entity.y - trueSize) / global.gameHeight) * height - 1, ((2 * trueSize) / global.gameWidth) * len + 0.2, ((2 * trueSize) / global.gameWidth) * len + 0.2); break; case 1: drawGuiCircle(x + (entity.x / global.gameWidth) * len, y + (entity.y / global.gameHeight) * height, (entity.size / global.gameWidth) * len + 0.2); break; case 0: - if (entity.id !== gui.playerid) drawGuiCircle(x + (entity.x / global.gameWidth) * len, y + (entity.y / global.gameHeight) * height, 2); + if (entity.id !== gui.playerid) drawGuiCircle(x + (entity.x / global.gameWidth) * len, y + (entity.y / global.gameHeight) * height, !global.mobile ? 2 : 3.5); break; } } ctx.globalAlpha = 1; + ctx.lineWidth = 3; + ctx.fillStyle = color.black; + if (settings.game.optOgIcon) { + drawGuiRect(x, y, len, height, 1); // Border ctx.lineWidth = 1; + } else { + drawGuiRect(x, y, len, height, true); // Border ctx.lineWidth = 1; + } ctx.lineWidth = 1; ctx.strokeStyle = color.guiblack; ctx.fillStyle = color.guiblack; - drawGuiCircle(x + (global.player.cx / global.gameWidth) * len - 1, y + (global.player.cy / global.gameHeight) * height - 1, 2, false); + drawGuiCircle(x + (global.player.cx / global.gameWidth) * len - 0, y + (global.player.cy / global.gameHeight) * height - 1, !global.mobile ? 2 : 3.5, false); + if (global.mobile) { + x = global.screenWidth - spacing - len; + y = global.screenHeight - spacing; + } if (global.showDebug) { drawGuiRect(x, y - 40, len, 30); lagGraph(lag.get(), x, y - 40, len, 30, color.teal); @@ -1597,20 +3276,28 @@ function drawMinimapAndDebug(spacing, alcoveSize) { //minimap stuff ends here //debug stuff if (!global.showDebug) y += 14 * 3; + if ((100 * gui.fps).toFixed(2) < 100) orangeColor = true; + if (global.metrics.rendertime < 10) orangeColor = true; // Text if (global.showDebug) { - drawText("Open Source Arras", x + len, y - 50 - 5 * 14 - 2, 15, "#B6E57C", "right"); - drawText("Prediction: " + Math.round(GRAPHDATA) + "ms", x + len, y - 50 - 4 * 14, 10, color.guiwhite, "right"); - drawText(`Bandwidth: ${gui.bandwidth.in} in, ${gui.bandwidth.out} out`, x + len, y - 50 - 3 * 14, 10, color.guiwhite, "right"); - drawText("Update Rate: " + global.metrics.updatetime + "Hz", x + len, y - 50 - 2 * 14, 10, color.guiwhite, "right"); - drawText((100 * gui.fps).toFixed(2) + "% : " + global.metrics.rendertime + " FPS", x + len, y - 50 - 1 * 14, 10, global.metrics.rendertime > 10 ? color.guiwhite : color.orange, "right"); + drawText("Nero Engine v3.51", x + len, y - 50 - 8 * 14 - 2, 15, "#6a36e3", "right"); + drawText("Prediction: " + Math.round(GRAPHDATA) + "ms : " + global.mspt + " mspt", x + len, y - 50 - 7 * 14, 10, color.guiwhite, "right"); + // drawText(`Bandwidth: ${gui.bandwidth.in} in, ${gui.bandwidth.out} out`, x + len, y - 50 - 3 * 14, 10, color.guiwhite, "right"); + drawText("Memory: " + global.metrics.rendergap.toFixed(1) + " Mib : " + "Class: " + gui.class, x + len, y - 50 - 3 * 14, 10, color.guiwhite, "right"); + drawText("Update Version: " + "v3.52", x + len, y - 50 - 6 * 14, 10, color.guiwhite, "right"); + drawText("Update Rate: " + global.metrics.updatetime + "Hz", x + len, y - 50 - 5 * 14, 10, color.guiwhite, "right"); + drawText("Server Speed: " + (100 * gui.fps).toFixed(2) + "% : Client Speed: " + global.metrics.rendertime + " FPS", x + len, y - 50 - 4 * 14, 10, orangeColor ? color.orange : color.guiwhite, "right"); + drawText("Kills: " + global.metrics.killcount + " Shapes: " + global.metrics.shapecount, x + len, y - 50 - 2 * 14, 10, color.guiwhite, "right"); + drawText("Song: " + global.music2.songname, x + len, y - 50 - 1 * 14, 10, color.guiwhite, "right"); drawText(global.metrics.latency + " ms - " + global.serverName, x + len, y - 50, 10, color.guiwhite, "right"); - } else { - drawText("Open Source Arras", x + len, y - 50 - 2 * 14 - 2, 15, "#B6E57C", "right"); - drawText((100 * gui.fps).toFixed(2) + "% : " + global.metrics.rendertime + " FPS", x + len, y - 50 - 1 * 14, 10, global.metrics.rendertime > 10 ? color.guiwhite : color.orange, "right"); + document.getElementById("content").style.opacity = 1; + } else if (!global.GUIStatus.minimapReducedInfo) { + drawText("Nero Engine v3.5", x + len, y - 50 - 2 * 14 - 2, 15, "#2eabe6", "right"); + drawText((100 * gui.fps).toFixed(2) + "% : " + global.metrics.rendertime + " FPS", x + len, y - 50 - 1 * 14, 10, orangeColor ? color.orange : color.guiwhite, "right"); drawText(global.metrics.latency + " ms : " + global.metrics.updatetime + "Hz", x + len, y - 50, 10, color.guiwhite, "right"); - } - global.fps = global.metrics.rendertime; + document.getElementById("content").style.opacity = 0; + document.getElementById("content").style.left = x - spacing - 120 + } else drawText("Open Source Arras", x + len, y - 22 - 2 * 14 - 2, 15, "#1081E5", "right"); } function drawLeaderboard(spacing, alcoveSize, max) { @@ -1621,6 +3308,16 @@ function drawLeaderboard(spacing, alcoveSize, max) { let height = 14; let x = global.screenWidth - len - spacing; let y = spacing + height + 7; + if (!lb.data.length) return; + // Animation things + let mobileGlide = mobileUpgradeGlide.get(); + if (global.mobile) { + if (global.canUpgrade) { + y += (alcoveSize / 1.4) * mobileGlide; + } + y += global.canSkill || global.showSkill ? (alcoveSize / 2.2 /*+ spacing * 2*/) * statMenu.get() : 0; + } + drawText("Leaderboard", Math.round(x + len / 2) + 0.5, Math.round(y - 6) + 0.5, height + 3.5, color.guiwhite, "center"); y += 7; for (let i = 0; i < lb.data.length; i++) { @@ -1631,7 +3328,7 @@ function drawLeaderboard(spacing, alcoveSize, max) { drawBar(x, x + len * shift, y + height / 2, height - 3.5, gameDraw.modifyColor(entry.barColor)); // Leadboard name + score let nameColor = entry.nameColor || "#FFFFFF"; - drawText(entry.label + (": " + util.handleLargeNumber(Math.round(entry.score))), x + len / 2, y + height / 2, height - 5, nameColor, "center", true); + drawText(entry.label + (": " + util.handleLargeNumber(Math.round(entry.score))), x + len / 2, y + height / 2, height - 5, nameColor == "#ffffff" ? color.guiwhite : nameColor, "center", true); // Mini-image let scale = height / entry.position.axis, xx = x - 1.5 * height - scale * entry.position.middle.x * Math.SQRT1_2, @@ -1649,12 +3346,13 @@ function drawAvailableUpgrades(spacing, alcoveSize) { let internalSpacing = 15; let len = alcoveSize / 2; let height = len; - + // Animation processing - let columnCount = Math.max(3, Math.floor(gui.upgrades.length ** 0.55)); +// let columnCount = Math.max(Math.ceil(gui.upgrades.length / 5), 3); + global.columnCount = Math.max(global.mobile ? 9 : 3, Math.ceil(gui.upgrades.length / 3)); upgradeMenu.set(0); if (!global.canUpgrade) { - upgradeMenu.force(-columnCount * 3) + upgradeMenu.force(-global.columnCount * 3) global.canUpgrade = true; } let glide = upgradeMenu.get(); @@ -1672,7 +3370,7 @@ function drawAvailableUpgrades(spacing, alcoveSize) { let lastBranch = -1; let upgradeHoverIndex = global.clickables.upgrade.check({x: global.mouse.x, y: global.mouse.y}); upgradeSpin += 0.01; - + for (let i = 0; i < gui.upgrades.length; i++) { let upgrade = gui.upgrades[i]; let upgradeBranch = upgrade[0]; @@ -1680,7 +3378,7 @@ function drawAvailableUpgrades(spacing, alcoveSize) { let model = upgrade[2]; // Draw either in the next row or next column - if (ticker === columnCount || upgradeBranch != lastBranch) { + if (ticker === global.columnCount || upgradeBranch != lastBranch) { x = xStart; y += height + internalSpacing; if (upgradeBranch != lastBranch) { @@ -1699,11 +3397,13 @@ function drawAvailableUpgrades(spacing, alcoveSize) { if (y > initialY) initialY = y; rowWidth = x; - - global.clickables.upgrade.place(i, x * clickableRatio, y * clickableRatio, len * clickableRatio, height * clickableRatio); - let upgradeKey = getClassUpgradeKey(upgradeNum); - - drawEntityIcon(model, x, y, len, height, 1, upgradeSpin, 0.6, colorIndex++, upgradeKey, upgradeNum == upgradeHoverIndex); + +// global.clickables.upgrade.place(i, y * clickableRatio, x * clickableRatio, len * clickableRatio, height * clickableRatio); + global.clickables.upgrade.place(i, x * clickableRatio, y * clickableRatio, len * clickableRatio, height * clickableRatio); + let upgradeKey = getClassUpgradeKey(upgradeNum); + +// drawEntityIcon(model, y, x, len, height, 1, upgradeSpin, 0.5, colorIndex++, upgradeKey); + drawEntityIcon(model, x, y, len, height, 1, upgradeSpin, 0.6, colorIndex++, !global.mobile ? upgradeKey : false, !global.mobile ? upgradeNum == upgradeHoverIndex : false); ticker++; upgradeNum++; @@ -1722,7 +3422,7 @@ function drawAvailableUpgrades(spacing, alcoveSize) { global.clickables.skipUpgrades.place(0, (buttonX - m / 2) * clickableRatio, buttonY * clickableRatio, m * clickableRatio, h * clickableRatio); // Upgrade tooltip - if (upgradeHoverIndex > -1 && upgradeHoverIndex < gui.upgrades.length) { + if (upgradeHoverIndex > -1 && upgradeHoverIndex < gui.upgrades.length && !global.mobile) { let picture = gui.upgrades[upgradeHoverIndex][2]; if (picture.upgradeTooltip.length > 0) { let boxWidth = measureText(picture.name, alcoveSize / 10), @@ -1755,7 +3455,161 @@ function drawAvailableUpgrades(spacing, alcoveSize) { global.clickables.skipUpgrades.hide(); } } +// MOBILE UI FUNCTIONS +function drawMobileJoysticks() { + // Draw the joysticks. + let radius = Math.min( + global.mobileStatus.useBigJoysticks ? global.screenWidth * 0.8 : global.screenWidth * 0.6, + global.mobileStatus.useBigJoysticks ? global.screenHeight * 0.16 : global.screenHeight * 0.12 + ); + ctx.globalAlpha = 0.3; + ctx.fillStyle = "#ffffff"; + ctx.beginPath(); + ctx.arc( + (global.screenWidth * 1) / 6, + (global.screenHeight * 2) / 3, + radius, + 0, + 2 * Math.PI + ); + ctx.arc( + (global.screenWidth * 5) / 6, + (global.screenHeight * 2) / 3, + radius, + 0, + 2 * Math.PI + ); + ctx.fill(); + ctx.globalAlpha = 0.5; + ctx.fillStyle = "#ffffff"; + ctx.beginPath(); + if (global.mobileStatus.showJoysticks) { + ctx.arc( + canvas.movementTouchPos.x + (global.screenWidth * 1) / 6, + canvas.movementTouchPos.y + (global.screenHeight * 2) / 3, + radius / 2.5, + 0, + 2 * Math.PI + ); + ctx.arc( + canvas.controlTouchPos.x + (global.screenWidth * 5) / 6, + canvas.controlTouchPos.y + (global.screenHeight * 2) / 3, + radius / 2.5, + 0, + 2 * Math.PI + ); + } + ctx.fill(); + // crosshair + if (global.mobileStatus.showCrosshair && global.mobileStatus.enableCrosshair) { + const crosshairpos = { + x: global.screenWidth / 2 + global.player.target.x, + y: global.screenHeight / 2 + global.player.target.y + }; + ctx.lineWidth = 1; + ctx.globalAlpha = 1; + ctx.strokeStyle = "#202020" + ctx.beginPath(); + ctx.moveTo(crosshairpos.x, crosshairpos.y - 20); + ctx.lineTo(crosshairpos.x, crosshairpos.y + 20); + ctx.moveTo(crosshairpos.x - 20, crosshairpos.y); + ctx.lineTo(crosshairpos.x + 20, crosshairpos.y); + ctx.closePath(); + ctx.stroke(); + } +} + +function makeButton(index, x, y, width, height, text, clickableRatio) { + // Set the clickable's position + global.clickables.mobileButtons.place(index, x * clickableRatio, y * clickableRatio, width * clickableRatio, height * clickableRatio); + + // Draw boxes + ctx.globalAlpha = 0.5; + ctx.fillStyle = color.grey; + drawGuiRect(x, y, width, height); + ctx.globalAlpha = 0.1; + ctx.fillStyle = color.black; + drawGuiRect(x, y + height * 0.6, width, height * 0.4); + ctx.globalAlpha = 1; + + // Draw text + drawText(text, x + width / 2, y + height * 0.5, height * 0.6, color.guiwhite, "center", true); + + // Draw the borders + ctx.strokeStyle = color.black; + ctx.lineWidth = 3; + drawGuiRect(x, y, width, height, true); +} + +function makeButtons(buttons, startX, startY, baseSize, clickableRatio, spacing) { + let x = startX, y = startY, index = 0; + + for (let row = 0; row < buttons.length; row++) { + for (let col = 0; col < buttons[row].length; col++) { + makeButton(buttons[row][col][3] ?? index, x, y, baseSize * (buttons[row][col][1] ?? 1), baseSize * (buttons[row][col][2] ?? 1), buttons[row][col][0], clickableRatio); + x += baseSize * (buttons[row][col][1] ?? 1) + spacing; + index++; + } + + x = startX; + y += Math.max(...buttons[row].map(b => baseSize * (b[2] ?? 1))) + spacing; + } +} + +function drawMobileButtons(spacing, alcoveSize) { + if (global.clickables.mobileButtons.active == null) global.clickables.mobileButtons.active = false; + if (global.clickables.mobileButtons.altFire == null) global.clickables.mobileButtons.altFire = false; + + // Hide the buttons + global.clickables.mobileButtons.hide(); + + // Some animations. + mobileUpgradeGlide.set(0 + (global.canUpgrade || global.upgradeHover)); + + // Some sizing variables + let clickableRatio = global.canvas.height / global.screenHeight / global.ratio; + let upgradeColumns = Math.ceil(gui.upgrades.length / 9); + let yOffset = 0; + if (global.mobile) { + yOffset += global.canUpgrade ? (alcoveSize / 1.5 /*+ spacing * 2*/) * mobileUpgradeGlide.get() * upgradeColumns / 1.5 + spacing * (upgradeColumns + 1.55) + -17.5 : 0; + yOffset += global.canSkill || global.showSkill ? statMenu.get() * alcoveSize / 2.6 + spacing / 0.75 : 0; + } + let buttons; + let baseSize = (alcoveSize - spacing * 2) / 3; + + if (global.mobile) { + buttons = global.clickables.mobileButtons.active ? [ + [[global.clickables.mobileButtons.active ? "-" : "+"], [`Alt ${global.clickables.mobileButtons.altFire ? "Manual" : "Disabled"}`, 6], [`${!document.fullscreenElement ? "Full" : "Exit Full"} Screen`, 5]], + [["Autofire", 3.5], ["Reverse", 3.5], ["Self-Destruct", 5]], + [["Autospin", 3.5], ["Override", 3.5], ["Level Up", 5]], + [["Action", 3.5], ["Special", 3.5], ["Chat", 5]], + ] : [ + [[global.clickables.mobileButtons.active ? "-" : "+"]], + ]; + } + if (global.clickables.mobileButtons.altFire) buttons.push([["\u2756", 2, 2]]); + let len = alcoveSize; + let height = (len / global.gameWidth) * global.gameHeight; + if (global.gameHeight > global.gameWidth || global.gameHeight < global.gameWidth) { + let ratio = [ + global.gameWidth / global.gameHeight, + global.gameHeight / global.gameWidth, + ]; + len /= ratio[1] * 1.5; + height /= ratio[1] * 1.5; + if (len > alcoveSize * 2) { + ratio = len / (alcoveSize * 2); + } else if (height > alcoveSize * 2) { + ratio = height / (alcoveSize * 2); + } else { + ratio = 1; + } + len /= ratio; + height /= ratio; + } + makeButtons(buttons, len + spacing * 2, yOffset + spacing, baseSize, clickableRatio, spacing); +} const gameDrawAlive = (ratio, drawRatio) => { let GRAPHDATA = 0; // Prep stuff @@ -1772,7 +3626,7 @@ const gameDrawAlive = (ratio, drawRatio) => { py = ratio * global.player.rendery; // Get the player's target - calculateTarget(); + if (!global.mobile) calculateTarget(); //draw the in game stuff drawFloor(px, py, ratio); @@ -1787,15 +3641,22 @@ const gameDrawAlive = (ratio, drawRatio) => { let lb = leaderboard.get(); let max = lb.max; global.canSkill = !!gui.points && !global.showTree; + global.fps = global.metrics.rendertime; if (global.showTree) { drawUpgradeTree(spacing, alcoveSize); } else { - drawMessages(spacing); - drawSkillBars(spacing, alcoveSize); - drawSelfInfo(spacing, alcoveSize, max); - drawMinimapAndDebug(spacing, alcoveSize); - drawLeaderboard(spacing, alcoveSize, max, lb); - drawAvailableUpgrades(spacing, alcoveSize); + if (global.mobile) { // MOBILE UI + drawMobileJoysticks(); + drawMobileButtons(spacing, alcoveSize); + } + if (global.GUIStatus.renderGUI) { + drawMessages(spacing, alcoveSize); + drawSkillBars(spacing, alcoveSize); + drawSelfInfo(spacing, alcoveSize, max); + drawMinimapAndDebug(spacing, alcoveSize, GRAPHDATA); + if (global.GUIStatus.renderLeaderboard) drawLeaderboard(spacing, alcoveSize, max, lb); + drawAvailableUpgrades(spacing, alcoveSize); + } else drawAvailableUpgrades(spacing, alcoveSize); } global.metrics.lastrender = getNow(); }; @@ -1823,8 +3684,8 @@ let getKills = () => { : destruction < 75 ? "👺" : destruction < 100 ? "🌶️" : "💯" ) + " " + (!killCountTexts.length ? "A true pacifist" : - killCountTexts.length == 1 ? killCountTexts.join(" and ") : - killCountTexts.slice(0, -1).join(", ") + " and " + killCountTexts[killCountTexts.length - 1]) + killCountTexts.length == 1 ? killCountTexts.join(" and ") : + killCountTexts.slice(0, -1).join(", ") + " and " + killCountTexts[killCountTexts.length - 1]) ); }; let getDeath = () => { @@ -1840,12 +3701,56 @@ let getDeath = () => { } return txt; }; +let getTips = () => { + let txt = "❓ "; + if (global.finalKillers.length) { + txt += "lol you died"; + } else if (!global.autolvlUp) { + txt += "Enable auto-level up in the options menu to get level 45"; + } else { + txt += "Kill players and polygons to get more score"; + } + return txt; +}; const gameDrawDead = () => { clearScreen(color.black, 0.25); let ratio = util.getScreenRatio(); scaleScreenRatio(ratio, true); let shift = animations.deathScreen.get(); ctx.translate(0, -shift * global.screenHeight); + let x = global.screenWidth / 2, + y = global.screenHeight / 2 - 50, + len = 140, + position = global.mockups[parseInt(gui.type.split("-")[0])].position, + scale = len / position.axis, + xx = global.screenWidth / 2 - scale * position.middle.x * 0.707, + yy = global.screenHeight / 2 - 35 + scale * position.middle.y * 0.707, + picture = util.getEntityImageFromMockup(gui.type, gui.color), + baseColor = picture.color, + timestamp = Math.floor(Date.now() /1000); + drawEntity(baseColor, (xx - 190 - len / 2 + 0.5) | 0, (yy - 10 + 0.5) | 0, picture, 1.5, 1, (0.5 * scale) / picture.realSize, 1, -Math.PI / 4, true); + drawText("Level " + gui.__s.getLevel(), x - 275, y - -80, 14, color.guiwhite, "center"); + drawText(picture.name, x - 275, y - -110, 24, color.guiwhite, "center"); + drawText(timestamp + '', x, y - 80, 10, color.guiwhite, "center"); + if (global.player.name == "") { + drawText("Your Score: ", x - 170, y - 30, 24, color.guiwhite); + } else { + drawText(global.player.name + "'s Score: ", x - 170, y - 30, 24, color.guiwhite); + } + drawText(util.formatLargeNumber(Math.round(global.finalScore.get())), x - 170, y + 25, 50, color.guiwhite); + drawText("⌚ Survived for " + util.timeForHumans(Math.round(global.finalLifetime.get())), x - 170, y + 55, 16, color.guiwhite); + drawText(getKills(), x - 170, y + 77, 16, color.guiwhite); + drawText(getDeath(), x - 170, y + 99, 16, color.guiwhite); + drawText(getTips(), x - 170, y + 122, 16, color.guiwhite); + drawText("🦆 The server was " + +(100 * gui.fps).toFixed(0) + "%" + " active", x - 170, y + 144, 16, color.guiwhite); + drawText(global.cannotRespawn ? global.respawnTimeout ? "(" + global.respawnTimeout + " Secon" + `${global.respawnTimeout <= 1 ? 'd' : 'ds'} ` + "left to respawn)" : "(you cannot respawn!)" : global.mobile ? "(tap to respawn)" : "(press enter to respawn)", x, y + 189, 16, color.guiwhite, "center"); ctx.translate(0, shift * global.screenHeight); +}; +const gameDrawOldDead = () => { + clearScreen(color.black, 0.25); + let ratio = util.getScreenRatio(); + scaleScreenRatio(ratio, true); + let shift = global.enableSlideAnimation ? animations.deathScreen.get() : animations.deathScreen.getNoLerp(); + ctx.translate(0, -shift * global.screenHeight); let x = global.screenWidth / 2, y = global.screenHeight / 2 - 50; let len = 140, @@ -1865,34 +3770,100 @@ const gameDrawDead = () => { drawText("(press enter to respawn)", x, y + 125, 16, color.guiwhite, "center"); ctx.translate(0, shift * global.screenHeight); }; +const gameDrawWiki = () => { + clearScreen(color.black, 0.5); + let ratio = util.getScreenRatio(); + scaleScreenRatio(ratio, true); + let shift = animations.deathScreen.get(); + ctx.translate(0, -shift * global.screenHeight); + let x = global.screenWidth / 2 - 215, + y = global.screenHeight / 2 - 50; + let len = 140, + position = global.mockups[parseInt(gui.type.split("-")[0])].position, + scale = len / position.axis, + xx = global.screenWidth / 2 - scale * position.middle.x * 0.707 - 215, + yy = global.screenHeight / 2 - 35 + scale * position.middle.y * 0.707, + picture = util.getEntityImageFromMockup(global.wikidisplaytank.toString(), color.blue), + baseColor = picture.color; + if (eval(`tankdescs.${picture.className}`) !== undefined) { + tanktype = eval(`tankdescs.${picture.className}.type`); + tankdesc = eval(`tankdescs.${picture.className}.desc`); + tanktier = eval(`tankdescs.${picture.className}.tier`); + tankweap = eval(`tankdescs.${picture.className}.weapons`); + tankabil = eval(`tankdescs.${picture.className}.abilities`); + tankweak = eval(`tankdescs.${picture.className}.weak`); + tankupto = eval(`tankdescs.${picture.className}.upgradesto`); + tankupfr = eval(`tankdescs.${picture.className}.upgradesfrom`); + tankorgn = eval(`tankdescs.${picture.className}.origin`); + tankupad = eval(`tankdescs.${picture.className}.updateadded`); + } else { + tanktype = "???"; + tankdesc = "???"; + tanktier = "???"; + tankweap = "???"; + tankabil = "???"; + tankweak = "???"; + tankupto = ["Tier 2: ???", "Tier 3: ???", "Tier 4: ???", "Misc: ???"]; + tankupad = "???"; + tankupfr = "???"; + tankorgn = "???"; + }; + drawEntity(baseColor, (xx - 190 - len / 2 + 0.5) | 0, (yy - 10 + 0.5) | 0, picture, 1.5, 1, (0.6 * scale) / picture.realSize, 1, -Math.PI / 4, true); + drawText(picture.name, (xx - 190 - len / 2 + 0.5) | 0, (yy + 78.5 + 0.5) | 0, 18, color.guiwhite, "center"); + drawText("Class." + picture.className, (xx - 190 - len / 2 + 0.5) | 0, (yy - 80 + 0.5) | 0, 14, color.guiwhite, "center"); + drawText(global.wikidisplaytank.toString(), (xx - 190 - len / 2 + 0.5) | 0, (yy - 100 + 0.5) | 0, 16, color.guiwhite, "center"); + drawText("Description:", x - 185, y - 70, 17, color.guiwhite, "left"); + ctx.mlStrokeText(tankdesc, x - 185, y - 70, 215, 200, 'top', 'left', 20, 14); + drawText("[Esc] Exit Entity Debugger", 10, global.screenHeight - 79, 12, color.guiwhite, "left"); + drawText("[Enter] Search Entity ID", 10, global.screenHeight - 56, 12, color.guiwhite, "left"); + drawText("[F] Become Entity (Sandbox Only)", 10, global.screenHeight - 33, 12, color.guiwhite, "left"); + drawText("[A] Cycle Left || [D] Cycle Right", 10, global.screenHeight - 10, 12, color.guiwhite, "left"); + drawGuiLine(x + 40, y - 90, x + 40, (yy + 58 + 0.5)); + drawText("Tier: " + tanktier, x + 60, y - 75, 14, color.guiwhite, "left"); + drawText("Weapons: " + tankweap, x + 60, y - 52, 14, color.guiwhite, "left"); + drawText("Abilities: " + tankabil, x + 60, y - 29, 14, color.guiwhite, "left"); + drawText("Upgrades From: " + tankupfr, x + 60, y - 6, 14, color.guiwhite, "left"); + drawText("Weak To: " + tankweak, x + 60, y + 17, 14, color.guiwhite, "left"); + drawText("Type: " + tanktype, x + 60, y + 40, 14, color.guiwhite, "left"); + drawText("Update: " + tankupad, x + 60, y + 63, 14, color.guiwhite, "left"); + drawText("Origin: " + tankorgn, x + 60, y + 86, 14, color.guiwhite, "left"); + drawGuiLine(x + 300, y - 90, x + 300, (yy + 58 + 0.5)); + drawText("Upgrades To: ", x + 320, y - 75, 14, color.guiwhite, "left"); + global.wikiclassname = picture.className + ctx.mlStrokeText(tankupto[0] + " \n " + tankupto[1] + " \n " + tankupto[2] + " \n " + tankupto[3], x + 320, y - 75, 350, 200, 'top', 'left', 16, 11); + ctx.translate(0, shift * global.screenHeight); +}; const gameDrawBeforeStart = () => { let ratio = util.getScreenRatio(); scaleScreenRatio(ratio, true); - clearScreen(color.white, 0.5); - let shift = animations.connecting.get(); + clearScreen(color.white, 1); + let shift = global.enableSlideAnimation ? animations.connecting.get() : animations.connecting.getNoLerp(); ctx.translate(0, -shift * global.screenHeight); drawText("Connecting...", global.screenWidth / 2, global.screenHeight / 2, 30, color.guiwhite, "center"); drawText(global.message, global.screenWidth / 2, global.screenHeight / 2 + 30, 15, color.lgreen, "center"); + drawText(global.tips, global.screenWidth / 2, global.screenHeight / 2 + 90, 15, color.guiwhite, "center"); ctx.translate(0, shift * global.screenHeight); }; const gameDrawDisconnected = () => { + util.submitAchievementToLocalStorage("disconnectachievement"); let ratio = util.getScreenRatio(); scaleScreenRatio(ratio, true); clearScreen(gameDraw.mixColors(color.red, color.guiblack, 0.3), 0.25); - let shift = animations.disconnected.get(); + let shift = global.enableSlideAnimation ? animations.disconnected.get() : animations.disconnected.getNoLerp(); ctx.translate(0, -shift * global.screenHeight); drawText("Disconnected", global.screenWidth / 2, global.screenHeight / 2, 30, color.guiwhite, "center"); drawText(global.message, global.screenWidth / 2, global.screenHeight / 2 + 30, 15, color.orange, "center"); ctx.translate(0, shift * global.screenHeight); }; const gameDrawError = () => { + util.submitAchievementToLocalStorage("disconnectachievement"); let ratio = util.getScreenRatio(); scaleScreenRatio(ratio, true); clearScreen(gameDraw.mixColors(color.red, color.guiblack, 0.2), 0.35); - let shift = animations.error.get(); + let shift = global.enableSlideAnimation ? animations.error.get() : animations.error.getNoLerp(); ctx.translate(0, -shift * global.screenHeight); drawText("There has been an error!", global.screenWidth / 2, global.screenHeight / 2 - 50, 50, color.guiwhite, "center"); - drawText("Check the browser console for details.", global.screenWidth / 2, global.screenHeight / 2, 30, color.guiwhite, "center"); + drawText("(This means The Dev is A Moron and The Game is Bugged)", global.screenWidth / 2, global.screenHeight / 1.8, 20, color.blue, "center"); drawText(global.message, global.screenWidth / 2, global.screenHeight / 2 + 30, 15, color.orange, "center"); ctx.translate(0, shift * global.screenHeight); }; @@ -1900,13 +3871,14 @@ const gameDrawError = () => { function animloop() { global.animLoopHandle = window.requestAnimFrame(animloop); gameDraw.reanimateColors(); - global.player.renderv += (global.player.view - global.player.renderv) / 30; + global.player.renderv += (global.player.view - global.player.renderv) / 10; var ratio = settings.graphical.screenshotMode ? 2 : util.getRatio(); // Set the drawing style ctx.lineCap = "round"; ctx.lineJoin = "round"; // Draw the game if (global.gameStart && !global.disconnected) { + lagachloop(); global.time = getNow(); if (global.time - lastPing > 1000) { // Latency @@ -1929,24 +3901,39 @@ function animloop() { } else if (!global.disconnected) { gameDrawBeforeStart(); } - if (global.died) { + if (global.died) { // Womp Womp you died gameDrawDead(); + if (settings.game.disableDeathSounds) { + PlaySound420(); + } + global.metrics.killcount = 0; + global.metrics.shapecount = 0; + } else { + if (global.stopthefuckingkillsoundyouprick) { + metalpipe.pause(); + metalpipe.currentTime = 0; + global.stopthefuckingkillsoundyouprick = false; + console.log("Respawned") + } } - if (global.disconnected) { + if (global.disconnected) { // Draw disconnection screen if the client lost connection to the server. gameDrawDisconnected(); } + if (global.wiki) { + gameDrawWiki(); + } ctx.translate(-0.5, -0.5); - //oh no we need to throw an error! } catch (e) { - + //hold on.... - gameDrawError(); + gameDrawError(); // Draw the error screen. ctx.translate(-0.5, -0.5); - + //okay, NOW throw the error! throw e; + } } -})(util, global, settings, Canvas, color, gameDraw, socketStuff); +})(util, global, settings, Canvas, color, gameDraw, socketStuff); \ No newline at end of file diff --git a/public/changelog.html b/public/changelog.html index 0d2f173ba..ba4c8af40 100644 --- a/public/changelog.html +++ b/public/changelog.html @@ -1,18 +1,709 @@ -
-

Title 1: optional description

- optional date -
    -
  • Change 1
  • -
  • Lorem ipsum dolor sit amet consectetur adipisicing elit. Accusantium, excepturi.
  • -
  • Change 3
  • -
-
-
-

Title 2: optional description

- optional date -
    -
  • Change 1
  • -
  • Change 2
  • -
  • Change 3
  • -
-
\ No newline at end of file +
+

Update 3.5

+ [2025] +
    +
  • Added 3 new tracks
  • +
  • slightly improved server loading
  • +
  • added water with physics
  • +
  • added minishot
  • +
  • added the minishot branches
  • +
  • added new 75 kill achivement
  • +
  • minos prime skin
  • +
  • nerfed firecracker
  • +
  • added new ffa map
  • +
  • addded the rest of the tier 3 upgrade variants for minishot to the rest of the tier 2 branches
  • +
  • added mini mortar variations of the t2 tanks
  • +
  • made assblasters back thruster bullets transparent
  • +
  • added submachine gun branch to machine gun
  • +
  • fixed date since creation counter turning to a year ahead when its not supposed to
  • +
  • added missing tanks to unavailable developer
  • +
  • added missing stat names to tanks
  • +
  • fixed turret danger values
  • +
  • fixed a bug where recoil wouldnt exist if upgrading from beyonet
  • +
  • removed scope from twiper
  • +
  • added flashfire
  • +
  • buffed firecrackers reload time
  • +
  • buffed shape health
  • +
  • added shadow
  • +
  • fixed Hypothermia not actually shooting ice traps
  • +
  • renamed acidilizer and icilizer to arsenic and devils breath
  • +
  • allowed you to set your tank to any entity via debug/wiki menu in sandbox
  • +
  • fixed the rocks not reflecting bullets in sandbox server
  • +
  • added numbers for health bar
  • +
  • buffed swarm tank damage by a multiplier of 2
  • +
  • nerfed flail damage from 3 to 1.95
  • +
  • buffed whirlwind damage from 1.875 to 4
  • +
  • buffed revolutionist turrets reload from 0.45 to 0.9
  • +
  • made jump smashers bullets half opacity
  • +
  • bayonet reload nerfed from 1 to 1.3
  • +
  • fixed cloner not cloning
  • +
  • nerfed probe cloning reload
  • +
  • buffed cloner branch cloning speed
  • +

    Ay, Anguish on that beat ho'

    +
+
+
+

Update 3.4

+ [2024] +
    +
  • buffed backshield
  • +
  • added slasher and attacker
  • +
  • readded trapception
  • +
  • added homing auto basic to desmos branch
  • +
  • made homing auto-2 upgrade from auto-3
  • +
  • removed auto-2 (except homing auto-2)
  • +
  • fixed upgrading issus
  • +
  • fixed kivaaritehdas
  • +
  • fixed trollface emoji
  • +
  • added sandbox mode
  • +
  • updated sound effects
  • +
  • fixed favicon not appearing on neroio.xyz
  • +
  • balanced rainmaker
  • +
  • fixed wall spawning shift key
  • +
  • added developer basic to testbed
  • +
  • removed mini defender
  • +
  • added ice Trapper branch
  • +
  • nerfed destroyer
  • +
  • nerfed repeater branch
  • +
  • added Kevin and Speed Triple
  • +
  • fixed visual bug with speedtriple
  • +
  • patched crash exploit
  • +

    RANDOM BULLSHIT, GO AGAIN!

    +
+
+
+

Update 3.3

+ [2024] +
    +
  • Added new server
  • +
  • changed menu layout
  • +
  • updated gamemodes
  • +
  • small fixes im too lazy to write
  • +
  • changed server box
  • +
  • small minion bugfixes
  • +
  • forgot to remove mace
  • +
  • dreads update
  • +
  • got rid of trilancer branch
  • +
  • dreadv1 changes
  • +
  • undertow update
  • +
  • removed a bunch of songs from ost
  • +
  • removed european server
  • +
  • updated credits
  • +
  • buffed albequerqe
  • +
  • fixed a bug where cloner hybrid did not show up when upgrading from cloner (dunno how i missed that)
  • +
  • removed ranch, marksman and cocci
  • +
  • fixed a bug where autocloner and cloner hybrid having instant clone respawn time
  • +
  • added visualizer to Nero brella
  • +
  • removed sidewinder
  • +
  • removed ceptions
  • +
  • nerfed auras (-100 aura points)
  • +
  • buffed surges emp attack
  • +
  • added choker
  • +
  • added X-Pathogen
  • +
  • added wyrm
  • +
  • added noble branch
  • +
  • added more descriptions
  • +
  • added gatling gun
  • +
  • removed more ceptions
  • +
  • removed aura branch from tier 1
  • +
  • removed auto branch from tier 1
  • +
  • removed hybrid branch from tier 1
  • +
  • removed flankinception branch
  • +
  • added more machceptioner upgrades
  • +
  • added 4 new ost tracks
  • +
  • fixed debug menu
  • +
  • makes shapes killed on run in debug menu reset on death
  • +
  • fixed solario bossfight
  • +
  • fixed bug where recoil doesnt work when upgrading from lancer tree
  • +
  • added charger
  • +
  • revolutionist now upgrades from whirlwind
  • +
  • saturn now upgrades from revolutionist
  • +
  • added formal dehyde and frostbite
  • +
  • buffed smashers
  • +
  • buffed skaters movement speed
  • +
  • gave pion the hadron ability and changed ring color to red
  • +
  • changed bayonet to tier 3
  • +
  • added icegun, fencer arisaka, wakazashi and fireblanket
  • +
  • removed mirror backshield
  • +
  • fixed death sounds
  • +
  • added wark branch
  • +
  • fixed auto2brid not having its main autocannon
  • +
  • fixed bug where scowerer and swivel2brid did not upgrade from its intended branches
  • +
  • fixed grazerbrid not having its autocannon
  • +
  • fixed the skype achievement
  • +
  • updated loading screen tooltips
  • +
  • fixed wark upgrades
  • +
  • nerfed solarios health from 8000 to 5500
  • +
  • nerfed solarios spin speed
  • +
  • disabled regen during solarios laser attack
  • +

    Big ass update :blehh:

    +
+
+
+

Update 3.2

+ [2024] +
    +
  • Fixed Undertow
  • +
  • Added Surge
  • +
  • Moved Music Checkbox
  • +
  • Bugfixes
  • +
  • Added Katana
  • +
  • Addded Risk Gamemode
  • +
  • Changed look of Revolutionist branch
  • +
  • Skin Issue Fix
  • +
  • Added Mini Defender
  • +
  • Integrated Lancer into Main & Added More Lancer Things
  • +
  • buffed kiva
  • +
  • menu tweaks
  • +
  • Added new servers and domain
  • +
  • Necromancer Rebalance + Gun Rework
  • +
  • Added more killstreak messages and an extra bonus at 100 kills :)
  • +
  • small server side optoimizations
  • +
  • added mobile controls :D (now you can play on the go)
  • +
  • added versitile switching from between pc and mobile controls in the menu
  • +
  • super huge bugfixes and balancing
  • +
  • fixed surge and added lancer range stat
  • +
  • fixed game crashing bug (i put two square brackets)
  • +
  • added respawn cooldown and tips n stuff
  • +
  • added /menu command
  • +
  • added custom keybinds
  • +
  • fixed bug where toggables do not work
  • +
  • fixed maze wall size bug
  • +
  • fixed death sound bug
  • +
  • fixed missing upgrades
  • +
  • added propel branch
  • +
  • added new extra tanks
  • +
  • added jouster branch
  • +
  • fixed mockups bug
  • +
  • balance changes and sidewinder branch rework
  • +
  • optimizations
  • +
  • record and screenshot
  • +
  • updated options ui
  • +
  • added extra gui and ui customization
  • +
  • added keybinds and mobile crosshair
  • +
  • nerfed cloner clone spawn time and added cockatiel
  • +
  • balanced propel stuff
  • +
  • added new server
  • +
  • boss stuff
  • +
  • tokay event + skin
  • +
  • finished solario boss
  • +
  • updated checkboxes
  • +
  • nerfed auras
  • +

    RANDOM BULLSHIT, GO!

    +
+
+
+

Update 3.1

+ [2024] +
    +
  • Fixed date since counter
  • +
  • Added BackShield & Mirror Shield
  • +
  • Fixed Tag Gamemode
  • +
  • Removed Stats Temporarily
  • +
  • Changed Bot Leveling
  • +
  • Nerfs & Buffs
  • +
  • Reorganized Entities
  • +
  • Added New Color System
  • +
  • Fixed Color System
  • +
  • New DFX Maze Map
  • +
  • Added Apotheosis V2 & Depredation Remastered V2 By Deltafyrex and Killa By Action Agenda (DFX Edit) To OST
  • +
  • Fixed Siege
  • +
  • Fixed Movement System
  • +
  • Fixed Death Sounds
  • +
  • Revamped Menu Popups
  • +
  • Added TwinSniper Branch And More to Acid And Chiller Branch
  • +
  • Fixed Music Bug, And Added Aura Basic, Jump Smasher And Whirlwind To The Main game
  • +
  • Fixed Shields
  • +
  • Moved Aura From Tier 3 To Tier 2 And Added Aura Branch
  • +
  • Added Flail & Buffed Auras
  • +
  • Added Firecracker, Douverie & Auto-2 Branch
  • +
  • Added Brella (upgrades from backshield) And Lancer Branch
  • +
  • Added More Options For Quality Of Life Features
  • +
  • Added New Achievements & Skins
  • +
  • Fixed Player Skin Bug
  • +
  • Fixed Color System Again And Added Glow + Nerfs/Buffs And other Bug Fixes
  • +

    Update 3.11 [2024]

    +
  • Fixed Desmos + 8 New OST Tracks
  • +
  • Added Music Selector And Fixed Music Bugs
  • +
  • Added In Game Audio Visualizer
  • +
  • Fixed Server Selector
  • +
  • Added A Beta Cocci
  • +
  • Small Menu & Ui Updates
  • +
  • Fixed Desmos AI Bug & Undertow
  • +
  • Nerfed Some Things
  • +

    Holay Molay

    +
+
+
+

Update 3.0

+ [2024] +
    +
  • Added Clubbin
  • +
  • Testing Achievements
  • +
  • Added Reset Achievements Button
  • +
  • Added Start Achievement
  • +
  • Added and Fixed Achievement Details
  • +
  • Added Disconnect, Lag, And Killstreak Achievement
  • +
  • Removed Kill Achievement cuz it dont work
  • +
  • Added New Special Achievement Type
  • +
  • Added Special Piss.io Achievement And Funny Skype Achievement
  • +
  • Re-Added And Fixed 5 Killstreak Achievement Again
  • +
  • Added Server to Client Functions
  • +
  • Added 10 Killstreak Achievement
  • +
  • Changed Debug Menu
  • +
  • Added Kill Amount In Debug
  • +
  • Added Audio Visualizer in the title screen
  • +
  • Fixed Embed Not Working Properly
  • +
  • Fixed Bug Where Audio Visualizer Appears In Game
  • +
  • Added Token And Discord Achievement
  • +
  • Added Achievements Tab
  • +
  • Removed Ach Testing
  • +
  • Added Credits Button
  • +
  • fixed credits interfering with changelog
  • +
  • added credits-changelog animation transition
  • +
  • moved credits button (its 1:08 am im soooooo tired)
  • +
  • Fixed Game Breaking Bug
  • +
  • Added Contagion Branch To Subduer & Trapper
  • +
  • Added Longing And Resurgam By Amaryllis To The OST
  • +
  • added credits ach
  • +
  • Added 2 New Branches For Desmos
  • +
  • Testing Skins
  • +
  • Added Beta Skin Menu
  • +
  • Fixed Skin Bug
  • +
  • Fixed Crashing On Respawn
  • +
  • Added More Detail To Skin Menu
  • +
  • Added Cat Code and Chickensandwhichman Skin
  • +
  • Added Daily Tanks
  • +
  • Added Plenty New Skins, New Achievements And Made Achievements Unlockable
  • +
  • Added Skater & Hitman
  • +
  • Added New "Duality" Map
  • +

    Update 2.93 [2024]

    +
  • David Goggins Event
  • +
  • Updated Menu
  • +
  • Added Marksman Branch To Sniper And Car Branch To
  • +
  • Added Trollface Emote (add --troll to the end of a chat message)
  • +
  • Added Waterfall, Acid, Cooler, Rainmaker And New Options Layout
  • +
  • Added Notes Tab + Live Counter
  • +
  • Added More Customization, Graphics, Helecopter And Fixed Music Bug
  • +
  • Added Reverie Branch And Injector
  • +
  • Added Debugger Menu
  • +
  • You Can Now Color Messages With §
  • +

    Niners fucking lost Again Bruh...Fuck Taylor Swift

    +
+
+
+

Update 2.9

+ [2024] +
    +
  • Added Motor
  • +
  • Added Kivaaharatedas (i did not spell that right)
  • +
  • Added Equilibrium, Revobrid, Subverter
  • +
  • shrapnel testing
  • +
  • removed unfinished aimbot/boosting testing
  • +
  • Added Basic Hybrid Tier 3 branch
  • +
  • Bug Fixed Colors
  • +
  • Added Tanks of my friends and tank soundboard support
  • +
  • Added the rest of the Basic Hybrid branch (tier 4)
  • +
  • Fixed changelog not appearing
  • +
  • Added beta music support including 5 songs
  • +
  • changed start button look to not shade out and actually work like a button
  • +
  • fixed debug key (again)
  • +
  • fixed screen tearing
  • +
  • worked bullet spawn position
  • +
  • Better organized dev menu and changed the way utilities looks
  • +
  • Added music recognition in the debug key to see the song name & artist
  • +
  • Added new song (Anybody can find Love (except You) by hkmori
  • +
  • fixed debug not recognizing a song and not updating after a song is finished
  • +
  • Testing wall colors/effects
  • +
  • Added Shield Turrets
  • +
  • Added new tiles (dance floor+black)
  • +
  • added new "banquet" map
  • +
  • Finished Revolutionist Branch
  • +
  • Added Inception & Albuquerque
  • +
  • im a fucking moron
  • +
  • Added Machceptioner & Tailgator
  • +
  • Added Interceptor, Twinceptioner, Inceptionist branch, hybrid/auto ver of inception branch
  • +
  • Added Desmos/Inception/Bascrid Ception
  • +
  • fixed the ceptionist turrets/autobullet turrets
  • +
  • nerfed shit
  • +
  • fixed some upgrades not appearing
  • +
  • no players (dead game and nobody plays is sadly)
  • +
  • so it turns out i forgot to give twinceptionist the right bullets so i fixed that :/
  • +
  • fixed flankcept branch turrets
  • +

    Update 2.91 [2024]

    +
  • Added the subduer branch
  • +
  • Fixed The Rest of the menu buttons and fixed sound effects
  • +
  • Added flankduer
  • +
  • Added Binary branch, Pathogen branch, mitochondrion branch, Subduer-Hybrid branch and Auto-Subduer Branch
  • +
  • fixed missing upgrades
  • +

    Hey! vsauce, Michael here. the game is stable and non buggy...or is it?

    +
+
+
+

Update 2.8

+ [2023] +
    +
  • Tank Adding Wave Two (ex. hadron, dictator, railgun + more)
  • +
  • Debug Key Bug Fix (how ironic)
  • +
  • Fixed Rng Images Bugging Out
  • +
  • Testing Whirlwind Branch
  • +
  • Fixed Maze Gamemode
  • +
  • Added Tooltips (beta)
  • +
  • Added Status Effects (beta+devevent)
  • +
  • Added Addon Support
  • +
  • Fixed button Shadows
  • +
  • Upgraded APS++ Updating Speed
  • +
  • New Mouse Controller
  • +
  • Keybind Fix
  • +
  • Enter can cancel a chat message being sent
  • +
  • CoNgReGaTiOn JuMpScArEs
  • +
  • Images on Tanks/Sound Effects For Tanks (dev)
  • +
  • Blackhole (dont ask just roll with it)
  • +
  • P A P Y R U S
  • +
  • Fixed Some Lag Holding Down Server Speed
  • +
  • 109.43.21.5.14
  • +
  • Added Desmos Branch
  • +
  • Theres Prob More But I Forgor
  • +

    wahhh... (i forgor why im crying)

    +
+
+
+

Update 2.7

+ [2023] +
    +
  • Debuffed Many Tanks
  • +
  • Migrated to new host
  • +
  • Removed all Nero Exclusive Tanks From The Game (for now anyway, dont worry)
  • +
  • Added "revolutionist" to testbed"
  • +
  • Massive Testbed overhaul
  • +
  • Added a funny randomly generated image on the start screen
  • +
  • Readded Sounds, design and other previous widgets
  • +
  • Hired new devs
  • +
  • did some tweaks to bots
  • +
  • got rid of the "nero" theme and the server list
  • +
  • added easter eggs
  • +
  • added random funny image
  • +

    Update 2.71 [2023]

    +
  • Tank Adding Wave One (ex. auto branch, revolutionist, cloner + more)
  • +
  • plenty of new dev features
  • +
  • added gamemode polls (once theres enough people)
  • +

    There are Easter Eggs All Over The Main Menu, You Might Find Something...

    +
+
+
+

Update 2.6

+ [2023] +
    +
  • replaced smashers origional upgrade path with the "armoury" tree -added lancer and smasher upgrades to armoury tree
  • +
  • added "Sword", "Injector" and "Fencer" to lancer upgrades
  • +
  • buffed drone tanks, twin tanks & tank health
  • +
  • added "Dictator" -added "Tripwire"
  • +
  • added "Barricade", "Twister", "Cyclone" and "Architect" -added "Tri-Trapper" tree -added "auto tritrapper", "auto armour" and "autolancer"
  • +
  • added "eagle" and "bulwark"
  • +
  • updated debug menu
  • +
  • removed hivemind from basic
  • +
  • added cloner upgrade
  • +
  • added hivemind and "splitter" to cloner upgrade
  • +
  • added "auto cloner", "auto flamethrower", "flamethrower hybrid" and "lancer hybrid"
  • +
  • updated colorscheme and other color related things
  • +
  • updated teams on 2tdm after 3 team bug -added all new Rock Maze gamemode
  • +

    Ryerson Loves Burger King

    +
+
+
+

Update 2.5

+ [2023] +
    +
  • added new tanks into beta for further testing
  • +
  • hired new devs
  • +
  • neroio discord is up
  • +
  • added new mascallenus tank and section
  • +
  • hired new beta testers
  • +
  • added new easter eggs
  • +
  • tested 2nd server opening
  • +
  • added "Scanner" and "hadoken"
  • +
  • nerfed Hahaugobrr
  • +
  • promoted lucas medieros to co-owner of the game
  • +
  • demoted a few staff
  • +
  • added 2TDM game mode
  • +
  • woomy event is back! now with free access to testbed
  • +
  • added "flankdrive", "twindrive" and "machinedrive"
  • +
  • fixed trapper look
  • +
  • added "infantry", "musket", "Traprid", "Auto Traprid", "Snigrav", "AsWdragafora", "Assasolak", "Builifacate", "Rifagiulus", "Auto Snigrav"
  • +
  • added "flamethrower", "Baker", "Wildfire" and "Equinox"
  • +
  • new nero.io default theme instead of using arras's
  • +
  • added insane af tanks to testbed
  • +
  • added "lancer"
  • +

    Open Na Noor

    +
+
+
+

Update 2.4

+ [2023] +
    +
  • added 2 new admin commands
  • +
  • added homing auto Basic
  • +
  • added bosses tab to AIT
  • +
  • bwomp AA $$ €€
  • +
  • added easter egg name colors
  • +
  • added the tanks "mercury", "venus", "earth", "mars", "jupiter", "saturn", "uranus", and "neptune"
  • +
  • added a new boss
  • +
  • added more natural spawning bosses
  • +
  • added "SpawnTrap"
  • +
  • updated bot names
  • +
  • ended woomy event
  • +

    Oh great red Text of the Changelog, What is your Wisdom?

    +
+
+
+

Update 2.3

+ [2023] +
    +
  • added "maleficator", "stalker", "landmine", "jumpsmash", "speedbent", "heavy3", and re-added "twindrive", "interceptioner", the "drive" subtree to autobasic, plus increased map size
  • +
  • fixed and debuffed jumpsmash
  • +
  • debuffed speedbent
  • +
  • added a public changelog (the one your looking at now)
  • +
  • added the red text
  • +
  • updated sounds and styles
  • +
  • added the "corrupted" button
  • +

    So Hows Ur Day?

    + +
+
+
+

Update 2.2

+ [2023] +
    +
  • added more tanks into beta
  • +
  • added sounds and updated client backround
  • +
  • Decoration finished
  • +
  • started decoration on migration host
  • +
  • added chat feature
  • +
  • migration big fixes
  • +
  • WE DID IT! MIGRATION COMPLETE!
  • +
  • during migration found multiple small bugs that was fixed
  • +
  • 2nd failed migrating attempt, starting yet another
  • +
  • fixed crashing bug
  • +
  • 2nd attempt at migrating
  • +
  • added random bot and skill classes
  • +
  • made bots more op
  • +
  • fixed a bot bug
  • +
  • downgraded bots
  • +
  • added tank visualizers
  • +
  • buffed bots a tiny bit more
  • +
  • fixed visualizer bug
  • +
  • added "rifle"
  • +
  • fixed "lilfact" upgrade path
  • +
  • added auto "lilfact"
  • +
  • renamed "lilfact" to "spawner"
  • +
  • added secret tanks for update 2.3
  • +
  • minor crash bug fixes
  • +
  • removed "rifle" and "autospawner" from beta
  • +
  • fixed smasher bug
  • +
  • failed "lancer" class attempt
  • +
  • secret tank updates
  • +
  • major bug fixes
  • +
  • rainbow color old client fix
  • +
  • last patches before big update
  • +
  • fixed tiny bug
  • +

    I Know Where You Live

    +
+
+
+

Update 2.1

+ [2022] +
    +
  • fixed the 2 game crashing bugs
  • +
  • tried to migrate to another server host but yet failed due to unknown reasons
  • +
  • added "speedbent" to beta
  • +
  • updated messages
  • +

    tbh im sad the 49ers missed the super bowl :/

    +
+
+
+

Update 2.0

+ [2021] +
    +
  • brought the ception tree into beta tanks
  • +
  • figured out that the "ceptions" arent really ceptions
  • +
  • forgot to add the actual way to access it LOL, also added a REAL machine ceptionist as a test
  • +
  • removed ceptionist and drive tanks as they are too overpowered
  • +
  • added lazer guns
  • +
  • stole code from someone elses server
  • +
  • added beta shock and burn
  • +
  • added some secret really stupid tanks
  • +
  • fixed a tank
  • +
  • removed revolutionist for being too buggy
  • +
  • added new auto class branch
  • +
  • added hivemind
  • +
  • bug fixes
  • +
  • major bug that caused no tanks to be added or bugs fixed causing confusion
  • +
  • crashing bug made game unplayable for large amount of time (like a whole 9 months)
  • +

    Whats Up Guys Quandale Dingle Here

    +
+
+
+

Update 1.9

+ [2021] +
    +
  • testing in progress
  • +
  • approved multiple tanks into the game
  • +
  • did some stupidity and added random stuff and figured out that there is indeed, 12882 lines of code in this project
  • +
  • added some dumb tanks like "mInIfLyInGfAsTeRtHiNgY"
  • +
  • added some cool colored objects on the "AsWdWsA" branch
  • +
  • added a secret tank
  • +
  • messed with some things like homing bullets
  • +
  • removed the homing stuff due to bugs
  • +
  • tried to recreate the "revolutionist" tank from woomy arras
  • +
  • more tests
  • +
  • added auto bullets
  • +
  • added drive tanks into beta testing phase
  • +
  • moved where the secret tank is
  • +
  • debuffed "single"
  • +
  • added "Cascal", "Gunto", "Catalyst", And "Cescav" to beta tanks
  • +
  • added a beta version of the drive tree into the game after some testing
  • +

    What A Dumb Fucking Game!

    +
+
+
+

Update 1.8

+ [2021] +
    +
  • completed and put the poison function into the game
  • +
  • completed and put the freeze function into the game
  • +
  • created a seprate freeze and poison bullets
  • +
  • added a stun function
  • +
  • added a healing and speed function
  • +
  • added a stun, healing and speed bullet shooting tanks
  • +
  • added the "AsWdWsA" branch
  • +
  • fixed poison cannon
  • +
  • renamed the bullets to respected name
  • +
  • renamed the cannons to a respected name
  • +
  • created a page 2 for the mascallenus
  • +
  • put multitanks into testbed
  • +
  • put multitanks into testbed
  • +
  • organized the tanks
  • +
  • removed public testbed
  • +

    :skull:

    +
+
+
+

Update 1.7

+ [2020] +
    +
  • added an admin logger
  • +
  • changed the AI color to pink
  • +
  • changed AI to have twin upgrade instead of basic
  • +
  • expanded the map
  • +
  • changed the colors of the spawning player to be random instead of always red or blue
  • +
  • added the tanks "oof" and "oof2" to mascallenus
  • +
  • added the tank "minibee" to testbed
  • +
  • added the tank "hexa trapper" into the game
  • +
  • added the tank "Paint Brush" into the crayon tree
  • +
  • added the tank "brutalizer"
  • +
  • added "sidewinder"
  • +

    Share with your friends!

    +
+
+
+

Update 1.6

+ [2020] +
    +
  • added the tank "tower mech"
  • +
  • added the "AIT" category into testbed
  • +
  • added a way to get back to a basic tank after becoming testbed
  • +
  • added the tank "crayon"
  • +
  • added the two tanks "marker" and "pastel"
  • +
  • added the tank "pen"
  • +
  • added a kill button to testbed
  • +
  • added the tank "highlighter"
  • +
  • added a way to immediatly upgrade into a basic trapper
  • +
  • invited some friends to help code my game
  • +

    Yo shout out to Lucas Medeiros

    +
+
+
+

Update 1.5

+ [2020] +
    +
  • removed jesus donut
  • +
  • removed DeltaCannon
  • +
  • fixed some bugs with AI's
  • +
  • fixed some bugs with crashers and bosses
  • +
  • added a bunch of testbed tanks into the real thing
  • +
  • removed fairsquare
  • +
  • added flame killa to testbed
  • +
  • removed access to the recently added tanks from testbed to save space
  • +
  • added Boxer to testbed
  • +
  • removed every testbed tank
  • +
  • added categories to test bed like "beta" and "mascallenus"
  • +

    come down today and try some corn, or we will sacrifice your newborn

    +
+
+
+

Update 1.4

+ [2020] +
    +
  • added Lottery to testbed
  • +
  • added hellblazer and Rocketer to testbed
  • +
  • added Nautilus to testbed
  • +
  • added jesus donut to testbed
  • +
  • experimented with bullet effects
  • +
  • added SleamShot
  • +
  • added TrapHard into testbed
  • +

    LMFAO WHAT A BOZO

    +
+
+
+

Update 1.3

+ [2020] +
    +
  • added master
  • +
  • added lilfact
  • +
  • fixed bug with bots
  • +
  • fixed bug with lilfact
  • +
  • ADDED PUBLIC TESTBED
  • +
  • fixed some bugs
  • +
  • fixed testbed problems
  • +
  • fixed testbed key errors regarding platform
  • +
  • added helltank to testbed
  • +
  • added DeltaCannon to testbed
  • +

    DrUgS aRe BaD fOr YoU1!1!

    +
+
+
+

Update 1.2

+ [2020] +
    +
  • server shutdown due to server problems
  • +
  • fixed problem
  • +
  • fixed some more bugs
  • +
  • fixed bug with the upgrades
  • +
  • added 3 pre-made extra tanks (hive shooter, auto assassin, auto cruiser)
  • +
  • added Unlocked
  • +
  • added more ways to get hive shooter
  • +
  • added more ways to get unlocked
  • +
  • added bots
  • +
  • fixed bad bug with Unlocked
  • +

    tbh play a better game than this

    +
+
+
+

Update 1.1

+ [2019] +
    +
  • added revix
  • +
  • added DeltaGunner
  • +

    OH BABY A TRIPLE

    +
+
+
+

Update 1.0

+ [2019] +
    +
  • just opened server
  • +
  • testing new tanks
  • +

    Bwomp

    +
+
+You've Reached The End ?̵̛̤̱̯͕̠̘̬̦̟̼̏͆̍̋̀̃͋͑̈́̂̎̉͒́̇̋͗̆͗̿́́̃́͗̉̈́̓̓͒̑̌͊̎͗̕̚̕͜͠͠͝͠͠?̵̧̢̨͉̹̥̩͕͙̦̞̹͙̣̱̪̫͚͚̋͐̒͐̈́͠?̶̡̢͈̮͉͕̩̣̘͚̳̳̺̹̜̺̹͙̼̤̼̱̣̭̪̘̖̊̅̽̃̎͋̽̇͂͆̽̃̇̏͒͋͗̾̀̉̐͘͜͠?̷̧̧̨̡̛̛̪̠̝̖̪̖͓̝̖̣͖͚̖̗̼̬̯̦̹̯͖̮̥͚͓̙͇̥̼͍̠̟̙̫̫̞̆̔́̊̆̓̿́̑̇̅̄̀̑̄̇̆̀̓͐̾̄̽̒̃͝͝ͅ?̶̢̧̢̢̧̧̛̣̳̮̝̳̞̞̙̟͓̝̬̤͎̂͛͆̓͑̌͌̂̽ \ No newline at end of file diff --git a/public/credits.html b/public/credits.html new file mode 100644 index 000000000..acfeb00a1 --- /dev/null +++ b/public/credits.html @@ -0,0 +1,54 @@ +
+

Deltafyrex

+ [Lead Dev, Game Owner and Discord Owner] +
    +
  • mains kivaaritehdas
  • +
  • favorite colors are cyan, white and black
  • +
  • the reason you get disconnected often while in game lol
  • +
  • game founder
  • +
  • working on nero since 2019
  • +
+
+
+

Anguish

+ [Co-Developer] +
    +
  • Made Minishot
  • +
  • Quesadilla is the best tank
  • +
  • The other reason why you get disconnected while in game lmao
  • +
  • When Rapture tank?
  • +
  • Typps s lpt
  • +
  • Slacks off TOO MUCH
  • +
  • I main Taco
  • +
+
+
+

123Pet

+ [Lead Beta Tester] +
    +
  • finds plenty of bugs
  • +
  • plays the game often
  • +
+
+
+

Ultimate primal

+ [Beta Tester] +
    +
  • actually cares about nero.io
  • +
  • Pretty fun to have around
  • +
  • quite a chill fellow
  • +
  • will definitely destroy you
  • +
+
+
+

Special Thanks:

+ [Other Special Thank-you's] +
    +
  • SafariSE (helped delta start out on creating nero all those years ago)
  • +
  • APS++ Developers (very nice)
  • +
  • "Wait What!?" (Creator of Phoarras)
  • +
  • JBX (Helps with Server stuff)
  • +
  • E guy (Helped Delta test everything in 2023-2024)
  • +
+
+You've Reached The End OwO ?̵̛̤̱̯͕̠̘̬̦̟̼̏͆̍̋̀̃͋͑̈́̂̎̉͒́̇̋͗̆͗̿́́̃́͗̉̈́̓̓͒̑̌͊̎͗̕̚̕͜͠͠͝͠͠?̵̧̢̨͉̹̥̩͕͙̦̞̹͙̣̱̪̫͚͚̋͐̒͐̈́͠?̶̡̢͈̮͉͕̩̣̘͚̳̳̺̹̜̺̹͙̼̤̼̱̣̭̪̘̖̊̅̽̃̎͋̽̇͂͆̽̃̇̏͒͋͗̾̀̉̐͘͜͠?̷̧̧̨̡̛̛̪̠̝̖̪̖͓̝̖̣͖͚̖̗̼̬̯̦̹̯͖̮̥͚͓̙͇̥̼͍̠̟̙̫̫̞̆̔́̊̆̓̿́̑̇̅̄̀̑̄̇̆̀̓͐̾̄̽̒̃͝͝ͅ?̶̢̧̢̢̧̧̛̣̳̮̝̳̞̞̙̟͓̝̬̤͎̂͛͆̓͑̌͌̂̽ diff --git a/public/favicon.ico b/public/favicon.ico index 263db474e..23a67e49d 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/public/favicon.png b/public/favicon.png new file mode 100644 index 000000000..9f5538b63 Binary files /dev/null and b/public/favicon.png differ diff --git a/public/google777bc33c0347b790.html b/public/google777bc33c0347b790.html new file mode 100644 index 000000000..4ca51f561 --- /dev/null +++ b/public/google777bc33c0347b790.html @@ -0,0 +1 @@ +google-site-verification: google777bc33c0347b790.html \ No newline at end of file diff --git a/public/icon32x32.png b/public/icon32x32.png deleted file mode 100644 index df137ff10..000000000 Binary files a/public/icon32x32.png and /dev/null differ diff --git a/public/index.html b/public/index.html index 602027ceb..2cf2d4705 100644 --- a/public/index.html +++ b/public/index.html @@ -3,63 +3,330 @@ - + - + + + + - Open Source Arras + + Nero.io - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
- +
+ +
-
-
This Arras.io Private Server runs on Open Source Arras.
For more info, visit the GitHub Repository.

Not an official Arras.io project. We are not associated with Arras.io or Momentum Studios.
+
+ + +
+

view notes ▸

+
+
+ +
+
Nero.io runs on Open Source Arras. For more info,
visit the APS++ GitHub Repository by Taureon And Join The Nero.io Discord With The Widget In The Top Right
+
+

Date Since Creation

+
+
-
-

Open Source Arras

+

Connecting...

- - - +
+

-

view options ▸

+

view options  

-
+

- Advanced Controls:
- - - - - - - - -
E - auto-fire C - auto-spin
R - disable AI N - level up
V - reverse tank F - auto-alt
B - reverse mouse O - self-destruct
T - show tank treeM - maximize stat
X - spin lock P - developer tank*
* = requires valid token
- Options: +
AppearanceOptionsControlsMisc
+
+
Themes
+ - - - - - - - - - - - - - - - - - - -
+ + + + + + + + + + + + + + +
+
UI Elements
+ + + + + + + + + + + + + +
+ +
+
+
Performance
+ + + + + + +
+ + + +
+
Miscellaneous
+ + + + + +
+ + +
+ +
Mobile Miscellaneous
+ + + + +
+
+
+
Advanced Controls
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
E - Auto-fire
C - Auto-spin
R - Disable AI
N - Level up
V - Reverse tank
B - Reverse click
G - Auto-alt
O - Self-destruct
T - Show tree
F - Action
M - Maximize stat
X - Spin lock
L - Debug
F6  - Show wiki
F1  - Switch song
Z - Record
Enter         - Chat
Q - Screenshot
+
+
+ + +
Resources
+
+
-
- +
+
-
+
+
+
+
+ + +
+
+
+

Achievements

+
+
+ +
+ +
+ +
+
+
+

Skins

+
+
+

Default

+
+ + +
+ +
◉ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○
+
+ + + +
+ @@ -141,24 +741,51 @@

view options ▸

- + \ No newline at end of file diff --git a/public/browser.js b/public/lib/browser.js similarity index 100% rename from public/browser.js rename to public/lib/browser.js diff --git a/public/lib/canvas.js b/public/lib/canvas.js index d12f84314..741e8c8c7 100644 --- a/public/lib/canvas.js +++ b/public/lib/canvas.js @@ -1,5 +1,7 @@ import { global } from "./global.js"; import { settings } from "./settings.js"; +import * as socketStuff from "./socketInit.js"; +let { gui } = socketStuff; class Canvas { constructor() { @@ -7,26 +9,39 @@ class Canvas { this.target = global.target; this.socket = global.socket; this.directions = []; + this.movement = { + up: false, + down: false, + left: false, + right: false + }; + this.moving = false; - this.chatInput = document.getElementById('chatInput'); - this.chatInput.addEventListener('keydown', event => { + this.chatInput = document.getElementById("chatInput"); + this.chatInput.addEventListener("keydown", (event) => { if (![global.KEY_ENTER, global.KEY_ESC].includes(event.keyCode)) return; this.chatInput.blur(); this.cv.focus(); this.chatInput.hidden = true; if (!this.chatInput.value) return; - if (event.keyCode === global.KEY_ENTER) this.socket.talk('M', this.chatInput.value); + if (event.keyCode === global.KEY_ENTER) + this.socket.talk("M", this.chatInput.value); this.chatInput.value = ""; }); - - this.cv = document.getElementById('gameCanvas'); - this.cv.addEventListener('mousemove', event => this.mouseMove(event), false); - this.cv.addEventListener('mousedown', event => this.mouseDown(event), false); - this.cv.addEventListener('mouseup', event => this.mouseUp(event), false); - this.cv.addEventListener('keypress', event => this.keyPress(event), false); - this.cv.addEventListener('keydown', event => this.keyDown(event), false); - this.cv.addEventListener('keyup', event => this.keyUp(event), false); - this.cv.addEventListener('wheel', event => this.wheel(event), false); + this.wikiInput = document.getElementById("wikiTankThing"); + this.wikiInput.addEventListener('keydown', event => { + if (global.wiki && global.gameStart) { + if (event.keyCode === global.KEY_ENTER) { + if (this.wikiInput.value != "") { + global.wikidisplaytank = this.wikiInput.value; + this.wikiInput.value = ""; + } + this.cv.focus(); + } + } + }); + + this.cv = document.getElementById("gameCanvas"); this.cv.resize = (width, height) => { this.cv.width = this.width = width; this.cv.height = this.height = height; @@ -37,8 +52,49 @@ class Canvas { this.spinLock = true; this.treeScrollSpeed = 0.5; this.treeScrollSpeedMultiplier = 1; + this.optMobile = document.getElementById("optMobile"); global.canvas = this; } + init() { + global.mobile && optMobile.value == "mobile" || optMobile.value == "mobileWithBigJoysticks" ? ( // Mobile + this.mobilecv = this.cv, + this.controlTouch = null, + this.movementTouch = null, + this.movementTouchPos = { x: 0, y: 0 }, + this.controlTouchPos = { x: 0, y: 0 }, + this.mobilecv.addEventListener("touchstart", (event) => this.touchStart(event), false), + this.mobilecv.addEventListener("touchmove", (event) => this.touchMove(event), false), + this.mobilecv.addEventListener("touchend", (event) => this.touchEnd(event), false), + this.mobilecv.addEventListener("touchcancel", (event) => this.touchEnd(event), false) + ) : ( // PC + this.cv.addEventListener("mousemove", (event) => this.mouseMove(event), false), + this.cv.addEventListener("mousedown", (event) => this.mouseDown(event), false), + this.cv.addEventListener("mouseup", (event) => this.mouseUp(event), false), + this.cv.addEventListener("keypress", (event) => this.keyPress(event), false), + this.cv.addEventListener("wheel", (event) => this.wheel(event), false) + ); + this.cv.addEventListener("keydown", (event) => this.keyDown(event), false); + this.cv.addEventListener("keyup", (event) => this.keyUp(event), false); + } + calculateMovement() { + let x = this.movement.right - this.movement.left; + let y = this.movement.down - this.movement.up; + global.motion = { x, y }; + if (x === 0 && y === 0) { + global.movement = 0; + if (this.moving) { + this.socket.cmd.set(0, false); + this.moving = false; + } + } + else { + global.movement = Math.atan2(y, x); + if (!this.moving) { + this.socket.cmd.set(0, true); + this.moving = true; + } + } + } wheel(event) { if (!global.died && global.showTree) { if (event.deltaY > 1) { @@ -59,22 +115,30 @@ class Canvas { } } keyDown(event) { + let changedMovement = false; switch (event.keyCode) { case global.KEY_SHIFT: if (global.showTree) this.treeScrollSpeedMultiplier = 5; - else this.socket.cmd.set(6, true); + else this.socket.cmd.set(3, true); + let shifted = true; break; - case global.KEY_ENTER: // Enter to respawn - if (global.died) { - this.socket.talk('s', global.playerName, 0, 1 * settings.game.autoLevelUp); + if (global.died && !global.cannotRespawn) { + global.killsoundready = true; + global.stopthefuckingkillsoundyouprick = true; + this.socket.talk("s", global.playerName, 0, 1 * settings.game.autoLevelUp, global.skin); global.died = false; - break; + break; + } + + if (global.wiki && global.gameStart) { + this.wikiInput.focus(); + break; } // or to talk instead - if (this.chatInput.hidden && global.gameStart) { + if (this.chatInput.hidden && global.gameStart && !global.cannotRespawn) { this.chatInput.hidden = false; this.chatInput.focus(); break; @@ -82,160 +146,263 @@ class Canvas { break; case global.KEY_UP_ARROW: - if (!global.died && global.showTree) return global.scrollVelocityY = -this.treeScrollSpeed * this.treeScrollSpeedMultiplier; + if (!global.died && global.showTree) + return (global.scrollVelocityY = + -this.treeScrollSpeed * this.treeScrollSpeedMultiplier); case global.KEY_UP: - this.socket.cmd.set(0, true); + this.movement.up = true; + changedMovement = true; break; case global.KEY_DOWN_ARROW: - if (!global.died && global.showTree) return global.scrollVelocityY = +this.treeScrollSpeed * this.treeScrollSpeedMultiplier; + if (!global.died && global.showTree) + return (global.scrollVelocityY = + +this.treeScrollSpeed * this.treeScrollSpeedMultiplier); case global.KEY_DOWN: - this.socket.cmd.set(1, true); + this.movement.down = true; + changedMovement = true; break; case global.KEY_LEFT_ARROW: - if (!global.died && global.showTree) return global.scrollVelocityX = -this.treeScrollSpeed * this.treeScrollSpeedMultiplier; + if (!global.died && global.showTree) + return (global.scrollVelocityX = + -this.treeScrollSpeed * this.treeScrollSpeedMultiplier); case global.KEY_LEFT: - this.socket.cmd.set(2, true); + if (global.wiki && global.gameStart) { + global.wikidisplaytank = parseInt(global.wikidisplaytank) - 1; + } else { + this.movement.left = true; + changedMovement = true; + } break; case global.KEY_RIGHT_ARROW: - if (!global.died && global.showTree) return global.scrollVelocityX = +this.treeScrollSpeed * this.treeScrollSpeedMultiplier; + if (!global.died && global.showTree) + return (global.scrollVelocityX = + +this.treeScrollSpeed * this.treeScrollSpeedMultiplier); case global.KEY_RIGHT: - this.socket.cmd.set(3, true); + if (global.wiki && global.gameStart) { + global.wikidisplaytank = parseInt(global.wikidisplaytank) + 1; + } else { + this.movement.right = true; + changedMovement = true; + } break; case global.KEY_MOUSE_0: - this.socket.cmd.set(4, true); + this.socket.cmd.set(1, true); break; case global.KEY_MOUSE_1: - this.socket.cmd.set(5, true); + this.socket.cmd.set(2, true); break; case global.KEY_MOUSE_2: - this.socket.cmd.set(6, true); + this.socket.cmd.set(3, true); break; case global.KEY_LEVEL_UP: - this.socket.talk('L'); + this.socket.talk("L"); break; case global.KEY_FUCK_YOU: - this.socket.talk('0'); + this.socket.talk("0"); break; case global.KEY_BECOME: - this.socket.talk('H'); + if (global.wiki && global.gameStart) { + this.socket.talk("setclass", global.wikiclassname); + console.log("set class!") + } else { + this.socket.talk("H"); + } break; case global.KEY_MAX_STAT: global.statMaxing = true; break; case global.KEY_SUICIDE: - this.socket.talk('1'); + this.socket.talk("1"); + break; + case global.KEY_TELEPORT: + this.socket.talk("testTeleport"); + break; + case global.KEY_SMALLER_TANK: + this.socket.talk("smallerTank"); + break; + case global.KEY_BIGGER_TANK: + this.socket.talk("biggerTank"); + break; + case global.KEY_SMALLER_FOV: + this.socket.talk("smallerFOV"); + break; + case global.KEY_BIGGER_FOV: + this.socket.talk("biggerFOV"); + break; + case global.KEY_GOD_MODE: + this.socket.talk("godmodeButton"); + break; + case global.KEY_INVISIBLE: + this.socket.talk("invisibility"); + break; + case global.KEY_CAN_BE_ON_LEADERBOARD: + this.socket.talk("canBeOnLeaderboard"); + break; + case global.KEY_STRONG: + this.socket.talk("keyStrong"); + break; + case global.KEY_WATCH_THIS: + this.socket.talk("watchThis"); + break; + case global.KEY_DRAG: + this.socket.talk("drag"); + break; + case global.KEY_SPAWN_WALL: + if (shifted) { this.socket.talk("randomTestKey"); } else { this.socket.talk("spawnWall"); }; + break; + case global.KEY_ABILITY: + this.socket.cmd.set(7, true); + break; + case global.KEY_HEAL: + this.socket.talk("heal"); + break; + case global.KEY_WIKI: + global.wiki = true; + document.querySelector("#wikiTankThing").style.display = 'block'; + break; + case global.KEY_ESC: + global.wiki = false; + document.querySelector("#wikiTankThing").style.display = 'none'; + break; + case global.KEY_CHANGE_SONG: + global.music2.currentTime = 9999; break; } if (!event.repeat) { switch (event.keyCode) { case global.KEY_AUTO_SPIN: global.autoSpin = !global.autoSpin; - this.socket.talk('t', 0); + this.socket.talk("t", 0, true); break; case global.KEY_AUTO_FIRE: - this.socket.talk('t', 1); + this.socket.talk("t", 1, true); break; case global.KEY_OVER_RIDE: - this.socket.talk('t', 2); - break; - case global.KEY_REVERSE_MOUSE: //client side only, no server effects except message - this.inverseMouse = !this.inverseMouse; - this.socket.talk('t', 3); - break; - case global.KEY_REVERSE_TANK: //client side only, no server effects except message - this.reverseDirection = !this.reverseDirection; - this.socket.talk('t', 4); + this.socket.talk("t", 2, true); break; case global.KEY_AUTO_ALT: - this.socket.talk('t', 5); + this.socket.talk("t", 3, true); break; case global.KEY_SPIN_LOCK: this.spinLock = !this.spinLock; - this.socket.talk('t', 6); + global.createMessage(this.spinLock ? "Spinlock disabled." : "Spinlock enabled."); + this.socket.talk("t", 4, false); + break; + case global.KEY_REVERSE_MOUSE: + this.inverseMouse = !this.inverseMouse; + global.createMessage(this.inverseMouse ? "Reverse mouse enabled." : "Reverse mouse disabled."); + break; + case global.KEY_REVERSE_TANK: + this.reverseDirection = !this.reverseDirection; + global.createMessage(this.reverseDirection ? "Reverse tank enabled." : "Reverse tank disabled."); + break; + case global.KEY_DEBUG: + global.showDebug = !global.showDebug; break; case global.KEY_CLASS_TREE: global.treeScale = 1; global.showTree = !global.showTree; break; + case global.KEY_RECORD: + this.record(); + break; + case global.KEY_SCREENSHOT: + this.screenshot(); + break; } if (global.canSkill) { let skill = [ - global.KEY_UPGRADE_ATK, global.KEY_UPGRADE_HTL, global.KEY_UPGRADE_SPD, - global.KEY_UPGRADE_STR, global.KEY_UPGRADE_PEN, global.KEY_UPGRADE_DAM, - global.KEY_UPGRADE_RLD, global.KEY_UPGRADE_MOB, global.KEY_UPGRADE_RGN, - global.KEY_UPGRADE_SHI + global.KEY_UPGRADE_ATK, + global.KEY_UPGRADE_HTL, + global.KEY_UPGRADE_SPD, + global.KEY_UPGRADE_STR, + global.KEY_UPGRADE_PEN, + global.KEY_UPGRADE_DAM, + global.KEY_UPGRADE_RLD, + global.KEY_UPGRADE_MOB, + global.KEY_UPGRADE_RGN, + global.KEY_UPGRADE_SHI, ].indexOf(event.keyCode); - if (skill >= 0) this.socket.talk('x', skill, 1 * global.statMaxing); + if (skill >= 0) this.socket.talk("x", skill, 1 * global.statMaxing); } if (global.canUpgrade) { switch (event.keyCode) { case global.KEY_CHOOSE_1: - this.socket.talk('U', 0); + this.socket.talk("U", 0, parseInt(gui.upgrades[0][0])); break; case global.KEY_CHOOSE_2: - this.socket.talk('U', 1); + this.socket.talk("U", 1, parseInt(gui.upgrades[1][0])); break; case global.KEY_CHOOSE_3: - this.socket.talk('U', 2); + this.socket.talk("U", 2, parseInt(gui.upgrades[2][0])); break; case global.KEY_CHOOSE_4: - this.socket.talk('U', 3); + this.socket.talk("U", 3, parseInt(gui.upgrades[3][0])); break; case global.KEY_CHOOSE_5: - this.socket.talk('U', 4); + this.socket.talk("U", 4, parseInt(gui.upgrades[4][0])); break; case global.KEY_CHOOSE_6: - this.socket.talk('U', 5); + this.socket.talk("U", 5, parseInt(gui.upgrades[5][0])); break; } } } + if (changedMovement) this.calculateMovement(); } keyUp(event) { + let changedMovement = false; switch (event.keyCode) { case global.KEY_SHIFT: if (global.showTree) this.treeScrollSpeedMultiplier = 1; - else this.socket.cmd.set(6, false); + else this.socket.cmd.set(3, false); + let shifted = false; break; case global.KEY_UP_ARROW: global.scrollVelocityY = 0; case global.KEY_UP: - this.socket.cmd.set(0, false); + this.movement.up = false; + changedMovement = true; break; case global.KEY_DOWN_ARROW: global.scrollVelocityY = 0; case global.KEY_DOWN: - this.socket.cmd.set(1, false); + this.movement.down = false; + changedMovement = true; break; case global.KEY_LEFT_ARROW: global.scrollVelocityX = 0; case global.KEY_LEFT: - this.socket.cmd.set(2, false); + this.movement.left = false; + changedMovement = true; break; case global.KEY_RIGHT_ARROW: global.scrollVelocityX = 0; case global.KEY_RIGHT: - this.socket.cmd.set(3, false); + this.movement.right = false; + changedMovement = true; break; case global.KEY_MOUSE_0: - this.socket.cmd.set(4, false); + this.socket.cmd.set(1, false); break; case global.KEY_MOUSE_1: - this.socket.cmd.set(5, false); + this.socket.cmd.set(2, false); break; case global.KEY_MOUSE_2: - this.socket.cmd.set(6, false); + this.socket.cmd.set(3, false); break; case global.KEY_MAX_STAT: global.statMaxing = false; break; } + if (changedMovement) this.calculateMovement(); } mouseDown(mouse) { if (!this.socket) return; - let primaryFire = 4, - secondaryFire = 6; - if (this.inverseMouse) [primaryFire, secondaryFire] = [secondaryFire, primaryFire]; + let primaryFire = 1, + secondaryFire = 3; + if (this.inverseMouse) + [primaryFire, secondaryFire] = [secondaryFire, primaryFire]; switch (mouse.button) { case 0: let mpos = { @@ -244,17 +411,18 @@ class Canvas { }; let statIndex = global.clickables.stat.check(mpos); if (statIndex !== -1) { - this.socket.talk('x', statIndex, 0); + this.socket.talk("x", statIndex, 0); } else if (global.clickables.skipUpgrades.check(mpos) !== -1) { global.clearUpgrades(); } else { let upgradeIndex = global.clickables.upgrade.check(mpos); - if (upgradeIndex !== -1) this.socket.talk('U', upgradeIndex); + if (upgradeIndex !== -1 && upgradeIndex < gui.upgrades.length) + this.socket.talk("U", upgradeIndex, parseInt(gui.upgrades[upgradeIndex][0])); else this.socket.cmd.set(primaryFire, true); } break; case 1: - this.socket.cmd.set(5, true); + this.socket.cmd.set(2, true); break; case 2: this.socket.cmd.set(secondaryFire, true); @@ -263,15 +431,16 @@ class Canvas { } mouseUp(mouse) { if (!this.socket) return; - let primaryFire = 4, - secondaryFire = 6; - if (this.inverseMouse) [primaryFire, secondaryFire] = [secondaryFire, primaryFire]; + let primaryFire = 1, + secondaryFire = 3; + if (this.inverseMouse) + [primaryFire, secondaryFire] = [secondaryFire, primaryFire]; switch (mouse.button) { case 0: this.socket.cmd.set(primaryFire, false); break; case 1: - this.socket.cmd.set(5, false); + this.socket.cmd.set(2, false); break; case 2: this.socket.cmd.set(secondaryFire, false); @@ -279,13 +448,263 @@ class Canvas { } } mouseMove(mouse) { - global.statHover = global.clickables.hover.check({ - x: mouse.clientX * global.ratio, - y: mouse.clientY * global.ratio, - }) === 0; + global.statHover = + global.clickables.hover.check({ + x: mouse.clientX * global.ratio, + y: mouse.clientY * global.ratio, + }) === 0; if (!this.spinLock) return; global.mouse.x = mouse.clientX * global.ratio; global.mouse.y = mouse.clientY * global.ratio; } + touchStart(e) { + e.preventDefault(); + if (global.died && !global.cannotRespawn) { + this.socket.talk("s", global.playerName, 0, 1 * settings.game.autoLevelUp, global.skin); + global.died = false; + global.autoSpin = false; + global.resetTarget(); + } else { + for (let touch of e.changedTouches) { + let mpos = { + x: touch.clientX * global.ratio, + y: touch.clientY * global.ratio, + }; + let id = touch.identifier; + let buttonIndex = global.clickables.mobileButtons.check(mpos); + if (buttonIndex !== -1) { + switch (buttonIndex) { + case 0: + global.clickables.mobileButtons.active = !global.clickables.mobileButtons.active; + break; + case 1: + if (global.clickables.mobileButtons.active) { + global.clickables.mobileButtons.altFire = + !global.clickables.mobileButtons.altFire; + if (!global.clickables.mobileButtons.altFire) + this.socket.cmd.set(3, false); + } else if (global.isInverted) + (global.isInverted = false), this.socket.cmd.set(3, false); + else (global.isInverted = true), this.socket.cmd.set(3, true); + break; + case 2: + if (!document.fullscreenElement) { + var d = document.body; + d.requestFullscreen + ? d.requestFullscreen() + : d.msRequestFullscreen + ? d.msRequestFullscreen() + : d.mozRequestFullScreen + ? d.mozRequestFullScreen() + : d.webkitRequestFullscreen && d.webkitRequestFullscreen(); + } else { + document.exitFullscreen(); + } + break; + case 3: + this.socket.talk("t", 1, true); + break; + case 4: + this.reverseDirection = !this.reverseDirection; + global.reverseTank = -global.reverseTank; + global.createMessage(this.reverseDirection ? "Reverse tank enabled." : "Reverse tank disabled."); + break; + case 5: + global.clickables.mobileButtons.active = false; + this.socket.talk("1"); + break; + case 6: + global.autoSpin = !global.autoSpin; + this.socket.talk("t", 0, true); + break; + case 7: + this.socket.talk("t", 2, true); + break; + case 8: + this.socket.talk("L"); + break; + case 9: + this.socket.talk("H"); + break; + case 10: + this.socket.talk("0"); + break; + case 11: + if (this.chatInput.hidden && global.gameStart && !global.cannotRespawn) { + this.chatInput.hidden = false; + this.chatInput.focus(); + } else { + this.chatInput.hidden = true; + this.cv.focus(); + } + break; + default: + throw new Error("Unknown button index."); + } + } else { + let statIndex = global.clickables.stat.check(mpos); + if (statIndex !== -1) this.socket.talk("x", statIndex, 0); + else if (global.clickables.skipUpgrades.check(mpos) !== -1) + global.clearUpgrades(); + else { + let upgradeIndex = global.clickables.upgrade.check(mpos); + if (upgradeIndex !== -1) + this.socket.talk("U", upgradeIndex, parseInt(gui.upgrades[upgradeIndex][0])); + else { + let onLeft = mpos.x < this.cv.width / 2; + if (this.movementTouch === null && onLeft) { + this.movementTouch = id; + } else if (this.controlTouch === null && !onLeft) { + this.controlTouch = id; + this.socket.cmd.set(1, true); + } + } + } + } + } + this.touchMove(e); + } + } + touchMove(e) { + e.preventDefault(); + for (let touch of e.changedTouches) { + let mpos = { + x: touch.clientX * global.ratio, + y: touch.clientY * global.ratio, + }; + let id = touch.identifier; + + if (this.movementTouch === id) { + let radius = Math.min( + global.screenWidth * 0.6, + global.screenHeight * 0.12 + ); + let cx = (mpos.x - (this.cv.width * 1) / 6) / (radius / 64); + let cy = (mpos.y - (this.cv.height * 2) / 3) / (radius / 64); + let r = Math.sqrt(cx ** 2 + cy ** 2); + let angle = Math.atan2(cy, cx); + if (r > radius) { + cx = Math.cos(angle) * radius / 1.05; + cy = Math.sin(angle) * radius / 1.05; + } + this.movementTouchPos = { x: cx, y: cy }; + global.movement = angle; + if (!this.moving) { + global.motion = { + x: Math.cos(global.movement), + y: Math.sin(global.movement) + }; + this.socket.cmd.set(0, true); + this.moving = true; + } + } else if (this.controlTouch === id) { + global.mobileStatus.showCrosshair = true; + let radius = Math.min( + global.screenWidth * 0.6, + global.screenHeight * 0.12 + ); + let cx = (mpos.x - (this.cv.width * 5) / 6) / (radius / 64); + let cy = (mpos.y - (this.cv.height * 2) / 3) / (radius / 64); + let touchX = cx / (radius / 64); + let touchY = cy / (radius / 64); + let r = Math.sqrt(cx ** 2 + cy ** 2); + let angle = Math.atan2(cy, cx); + if (r > radius) { + touchX = Math.cos(angle) * radius / 1.05; + touchY = Math.sin(angle) * radius / 1.05; + } + this.controlTouchPos = { x: touchX, y: touchY }; + if (this.spinLock) { + if (cx < -radius) cx = -radius; + else if (cx > radius) cx = radius; + if (cy < -radius) cy = -radius; + else if (cy > radius) cy = radius; + this.target.x = ((cx / radius) * global.screenWidth) / 2; + this.target.y = ((cy / radius) * global.screenHeight) / 2; + } + } + } + global.mouse = this.target; + } + touchEnd(e) { + e.preventDefault(); + for (let touch of e.changedTouches) { + let id = touch.identifier; + + if (this.movementTouch === id) { + this.movementTouch = null; + this.movementTouchPos = { x: 0, y: 0 }; + global.movement = 0; + if (this.moving) { + global.motion = { x: 0, y: 0 }; + this.socket.cmd.set(0, false); + this.moving = false; + } + } else if (this.controlTouch === id) { + this.controlTouch = null; + this.controlTouchPos = { x: 0, y: 0 }; + this.socket.cmd.set(1, false); + global.mobileStatus.showCrosshair = false; + } + } + } + record() { + if (this.cv.captureStream && window.MediaRecorder) + if (this.videoRecorder) + switch (this.videoRecorder.state) { + case "inactive": + global.createMessage("Recorder started!", 2_000); + this.videoRecorder.start(); + break; + case "recording": + global.createMessage("Recorder stopped! Saving file...", 5_000); + this.videoRecorder.stop(); + } + else { + if (!global.gameStart) return; + let e = []; + this.videoRecorder = new MediaRecorder(this.cv.captureStream(60)); + this.videoRecorder.ondataavailable = (a) => e.push(a.data); + this.videoRecorder.onstop = () => { + let a = new Blob(e, { + type: this.videoRecorder.mimeType, + }); + e.length = 0; + let k = URL.createObjectURL(a), + q = document.createElement("a"); + q.style.display = "none"; + q.setAttribute("download", "nero.mp4"); + q.setAttribute("href", k); + document.body.appendChild(q); + setTimeout(() => { + URL.revokeObjectURL(k); + document.body.removeChild(q); + }, 100); + q.click(); + }; + global.createMessage("Recorder started!", 2_000); + this.videoRecorder.start(); + } + else + global.createMessage("Recording video requires an up-to-date browser.", 6_000); + } + screenshot() { + var x = this.cv.toDataURL(), + k = atob(x.split(",")[1]); + x = x.split(",")[0].split(":")[1].split(";")[0]; + let p = new Uint8Array(k.length); + for (let a = 0; a < k.length; a++) p[a] = k.charCodeAt(a); + let q = URL.createObjectURL(new Blob([p], {type: x})), + w = document.createElement("a"); + w.style.display = "none"; + w.setAttribute("download", "nero-screenshot.png"); + w.setAttribute("href", q); + document.body.appendChild(w); + setTimeout(() => { + URL.revokeObjectURL(q); + document.body.removeChild(w); + }, 100); + w.click(); + } } -export { Canvas } \ No newline at end of file +export { Canvas }; \ No newline at end of file diff --git a/public/lib/color.js b/public/lib/color.js index 9293836ab..e3dd6dcdf 100644 --- a/public/lib/color.js +++ b/public/lib/color.js @@ -1,4 +1,33 @@ var color = { + "nero": { + "teal": "#9EFFE0", + "lgreen": "#87FF8D", + "orange": "#FFB675", + "yellow": "#FDF380", + "lavender": "#b58efd", + "aqua": "#7adbba", + "pink": "#FFBDDD", + "vlgrey": "#E8EBF7", + "lgrey": "#b6b7ba", + "guiwhite": "#F0F0F0", + "black": "#484848", + "blue": "#52A8EB", + "green": "#8ABC3F", + "red": "#FC4E51", + "gold": "#EFC74B", + "purple": "#8D6ADF", + "magenta": "#ED2891", + "grey": "#A7A7AF", + "dgrey": "#726F6F", + "white": "#F0F8FA", + "guiblack": "#000000", + "mustard": "#c49608", + "tangerine": "#ec7b0f", + "brown": "#895918", + "cyan": "#13808e", + "paletteSize": 10, + "border": 0.65 + }, "normal": { "teal": "#7ad3db", "lgreen": "#b9e87e", @@ -28,6 +57,35 @@ var color = { "paletteSize": 20, "border": 0.6509803921568628 }, + neroclassic: { + "teal": "#7ADBBC", + "lgreen": "#B9E87E", + "orange": "#E7896D", + "yellow": "#FDF380", + "lavender": "#842da1", + "aqua": "#7adbba", + "pink": "#EF99C3", + "vlgrey": "#E8EBF7", + "lgrey": "#AA9F9E", + "guiwhite": "#F0F0F0", + "black": "#484848", + "blue": "#3CA4CB", + "green": "#8ABC3F", + "red": "#E03E41", + "gold": "#EFC74B", + "purple": "#8D6ADF", + "magenta": "#CC669C", + "grey": "#A7A7AF", + "dgrey": "#726F6F", + "white": "#a9abcf", + "guiblack": "#000000", + "mustard": "#c49608", + "tangerine": "#ec7b0f", + "brown": "#895918", + "cyan": "#13808e", + "paletteSize": 10, + "border": 0.3 + }, "dark": { "teal": "#6ecedc", "lgreen": "#0c491d", @@ -609,4 +667,4 @@ var color = { "border": 0 } }; -export { color } +export { color } \ No newline at end of file diff --git a/public/lib/config.js b/public/lib/config.js new file mode 100644 index 000000000..5135a4bca --- /dev/null +++ b/public/lib/config.js @@ -0,0 +1,99 @@ +import { global } from "./global.js"; +import { util } from "./util.js"; + +// You add stuff in here! + +// functions. + +function createMessage(con, dur = 10_000) { + global.messages.push({ + text: con, + status: 2, + alpha: 0, + time: Date.now() + dur, + }); +}; + +// globals. + +// general tips +// options tips +// rules n stuff +// gameplay tips +// facts +// goofy shit + +global.tips = [[ // You can edit this! + "Tip: You can make your own nero.io with the source code linked at the top right of the title screen.", + "Tip: You can play nero on mobile by opening the game on your phone!", + "Tip: Join the nero.io discord with the link in the title screen for the latest updates and news!", + "Tip: Subscribe to deltafyrex on youtube for shitposts, streams and more!", + "Tip: Follow deltafyrex on twitter for more information and news on the game.", + "Tip: Feeling lonely and sad? Join the nero.io discord server to talk to people just like you!", + "Tip: Want to play nero.io 1? click the button at the top right of the title screen.", + "Tip: You can change songs in game with F1 or whatever you set the change song keybind to.", + "Tip: Want to enable music? click the checkbox at the top of the title screen!", + "Tip: Unlock in game cosmetics and player skins by completing the achivements found in the \n" + +"achievements menu located at the top of the title screen", + "Tip: Change and equip your unlocked skins in the skins menu located at the top of the title screen", + "Tip: View the game credits with its respected button underneath the changelog <3", + "Tip: Is there an empty or unfinished entity wiki entry? send in your own descriptions and \n" + +"info on the entry through discord and it could end up in the game!", + "Tip: Do you have a suggestion for the game? if so, send it to us on our discord!", + "Tip: Like the game? share it with your friends, the more the merrier!" + ], [ + "Tip: You can change ui stuff like seperate health wnd shield bars and curvy traps in the options menu.", + "Tip: If nero is running like gta 5 on windows xp, you can either go to the optomization section \n" + +"in the options menu or get a pc that didnt come from a macdonalds happy meal 💀.", + "Tip: Like death sounds? think they are funny? enable them in the options menu!", + "Tip: You can change what soundtracks play ingame when music is turned on by going to the options menu", + "Tip: You can view and change your keybinds in the options menu.", + "Tip: You can create your own theme with the custom theme maker using the link in the options menu." + ], [ + "Teaming in FFA is stupid, dont do it, i mean then again theres nothing really stopping you.", + "Exploits arent cool, it breaks the balance and unfairness of the game, if you find one. tell me", + "Multiboxing is stupid, your literally cheating with more tanks instead of just one, dont be a jerk." + ], [ + "Tip: Theres a wide variety of tanks in nero.io, be open to different tanks! you might like them.", + "Tip: Nests are different color tiles on the map that can spawn things like bosses and stronger shapes!", + "Tip: Not all tanks work as intended, expect some bugs while using some of them.", + "Tip: Many nero.io tanks have special gimmicks, try experimenting with them to see how they work!", + "Tip: Want to know information about an entity or tank? press F7 on pc to view the in game entity wiki!", + "Tip: This game is very unpredictable! be prepared for anything that could happen.", + "Tip: Want to view the title screen in game? just type /menu in the chat bar!", + "Tip: There are many different classes and weapons in this game, and its important to know what they do.", + ], [ + "Did you know that nero has been worked on for more than 5 years! look at the notes section in the \n" + +"title screen for a live counter since release!", + "The first ever custom nero tank was named revix, i wonder why.....", + "Nero is actually a spinoff of a another 2d tank game called arras.io which is a spinoff of diep.io", + "Nero was meant to be a combination of arras and woomy arras (there lore on that)" + ], [ + "IM JUST GOODER", + "MAYONNAISE ON AN ESCALATA", + "Nero better than arras, cry about it", + "Want testbed? nuh uh!", + "Im bored of making these tip messages", + "im retarded", + "WOAH ITS WULZY", + "1v1 me noob", + "listen to my music on Soundcloud or perish", + "N U H. U H.", + "Y U H. U H.", + "Your built like the nerd emoji 🤓", + "IM GONNA FLY A PLAAANE INTO A-", + "Nero once a day keeps the social interactions away!", + "Bingle bongle dingle dangle yickety doo yickety da ping pong lippy tappy too taa", + "This tip is sponsored by RAID SHADOW LEGENDS!", + "Don't you have something else better to do?", + "Stop procrastinating, finish what you need to do", + "i hope you die over and over again", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "I WOKE UP AND I GOT FRESH AS HELL ON A MONDAY", + "HE HAS EBOL-LALALALALA", + "I JUST LOST MY DAAAAAWG", + "The plural of Moose is Moose. \n" + +"And the singular of Moose is Moose." + ] +]; +global.createMessage = (content, duration) => createMessage(content, duration); \ No newline at end of file diff --git a/public/lib/gameDraw.js b/public/lib/gameDraw.js index 776c88d91..3ac7abef8 100644 --- a/public/lib/gameDraw.js +++ b/public/lib/gameDraw.js @@ -1,4 +1,3 @@ - import { settings } from "./settings.js"; import { gui } from "./socketInit.js"; @@ -94,10 +93,10 @@ var gameDraw = { //TODO: somehow move the calculation to these in reanimateColors to improve performance colorCache: {}, modifyColor: (color, base = "16 0 1 0 false") => { - // Split into array + // Split into array let colorDetails = color.split(" "), baseDetails = base.split(" "); - + // Color mirroring if (colorDetails[0] == "-1" || colorDetails[0] == "mirror") { colorDetails[0] = baseDetails[0]; @@ -156,21 +155,26 @@ var gameDraw = { lesbian: "", gay: "", bi: "", + nero: "", trans: "", magenta: "", blue_red: "", blue_grey: "", grey_blue: "", red_grey: "", - grey_red: "" + grey_red: "", + sans: "", + epilepsy: "" }, reanimateColors: () => { let now = Date.now(), - //six_gradient = Math.floor((now / 200) % 6), + six_gradient = Math.floor((now / 200) % 6), five_bars = Math.floor((now % 2000) / 400), three_bars = Math.floor((now % 2000) * 3 / 2000), + fourtyfive_bars = Math.floor((now % 4000) * 45 / 4000), blinker = 150 > now % 300, + seizure = 5 > now % 10, lesbian_magenta = "#a50062", lesbian_oredange = "#d62900", @@ -178,7 +182,7 @@ var gameDraw = { lesbian_useSecondSet = five_bars < 2, gay_transition = (now / 2000) % 1, - + ratio = (Math.sin(now / 2000 * Math.PI)) / 2 + 0.5, light_purple = { h: 258/360, s: 1, l: 0.84 }, purple = { h: 265/360, s: 0.69, l: 0.47 }, @@ -186,6 +190,16 @@ var gameDraw = { bi_pink = "#D70071", bi_purple = "#9C4E97", bi_blue = "#0035AA", + + nero_blue1 = "#4287F5", + nero_blue2 = "#3CA2F0", + nero_blue3 = "#70B5FF", + nero_blue4 = "#4B90DB", + nero_blue5 = "#355BBD", + nero_blue6 = "#1F4199", + nero_blue7 = "#242bbd", + nero_blue8 = "#1814E0", + nero_blue9 = "#2668d1", trans_pink = "#f7a8b8", trans_blue = "#55cdfc", @@ -206,27 +220,26 @@ var gameDraw = { gameDraw.animatedColor.grey_blue = blinker ? gameDraw.color.grey : gameDraw.color.blue; gameDraw.animatedColor.red_grey = blinker ? gameDraw.color.red : gameDraw.color.grey; gameDraw.animatedColor.grey_red = blinker ? gameDraw.color.grey : gameDraw.color.red; + gameDraw.animatedColor.epilepsy = seizure ? gameDraw.color.guiblack : gameDraw.color.guiwhite; + + gameDraw.animatedColor.nero = [nero_blue1, "#418CF4", "#4092F3", "#3E97F2", "#3D9DF1", nero_blue2, "#46A6F3", "#51AAF6", "#5BADF9", "#66B1FC", nero_blue3, "#69AEF8", "#61A6F1", "#5A9FE9", "#5297E2", nero_blue4, "#4785D5", "#427BCF", "#3E70C9", "#3966C3", nero_blue5, "#3156B6", "#2C51AF", "#284BA7", "#2346A0", nero_blue6, "#203DA0", "#2138A7", "#2234AF", "#232FB6", nero_blue7, "#2226C4", "#1F22CB", "#1D1DD2", "#1A19D9", nero_blue8, "#1B25DD", "#1E36DA", "#2046D7", "#2357D4", nero_blue9, "#2C6ED8", "#3174DF", "#377BE7", "#3C81EE", "#4287F5"][fourtyfive_bars]; }, animatedColors: { // police 20: true, - flashBlueRed: true, + flashBlueRed: true, 21: true, - flashBlueGrey: true, flashBlueGray: true, 22: true, flashGreyBlue: true, - flashGrayBlue: true, 23: true, flashRedGrey: true, - flashRedGray: true, 24: true, flashGreyRed: true, - flashGrayRed: true, // lesbian 29: true, @@ -243,10 +256,18 @@ var gameDraw = { // bi 38: true, bi: true, - + // magenta 42: true, animatedMagenta: true, + + // nero + 43: true, + animatednero: true, + + // epil + 44: true, + animatedepilepsy: true }, getColor: (colorNumber) => { if (colorNumber[0] == '#') return colorNumber; @@ -413,6 +434,16 @@ var gameDraw = { case "42": case "animatedMagenta": return gameDraw.animatedColor.magenta; + + // nero shit + case "43": + case "animatednero": + case "nero": + return gameDraw.animatedColor.nero; + case "44": + case "animatedepilepsy": + case "epilepsy": + return gameDraw.animatedColor.epilepsy; } }, getColorDark: (givenColor) => { diff --git a/public/lib/global.js b/public/lib/global.js index 36d861af3..a41334345 100644 --- a/public/lib/global.js +++ b/public/lib/global.js @@ -48,61 +48,82 @@ let Region = (size) => { }; const global = { - // Keys and other mathematical constants. You can find the list here: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode - KEY_ESC: 27,// Escape - KEY_ENTER: 13,// Enter - KEY_SHIFT: 16,// Shift - KEY_BECOME: 70,// F - KEY_CHAT: 13,// Enter - KEY_FIREFOOD: 119,// F8 - KEY_SPLIT: 32,// Space + // Keys and other mathematical constants + KEY_ESC: 27, + KEY_ENTER: 13, + KEY_SHIFT: 16, + KEY_BECOME: 70, + KEY_CHAT: 13, + KEY_FIREFOOD: 119, + KEY_SPLIT: 32, - KEY_LEFT: 65,// A - KEY_UP: 87,// W - KEY_RIGHT: 68,// D - KEY_DOWN: 83,// S - KEY_LEFT_ARROW: 37,// ArrowLeft - KEY_UP_ARROW: 38,// ArrowUp - KEY_RIGHT_ARROW: 39,// ArrowRight - KEY_DOWN_ARROW: 40,// ArrowDown + KEY_LEFT: 65, + KEY_UP: 87, + KEY_RIGHT: 68, + KEY_DOWN: 83, + KEY_LEFT_ARROW: 37, + KEY_UP_ARROW: 38, + KEY_RIGHT_ARROW: 39, + KEY_DOWN_ARROW: 40, - KEY_AUTO_SPIN: 67,// C - KEY_AUTO_FIRE: 69,// E - KEY_AUTO_ALT: 71,// G - KEY_OVER_RIDE: 82,// R - KEY_REVERSE_TANK: 86,// V - KEY_REVERSE_MOUSE: 66,// B - KEY_SPIN_LOCK: 88,// X + KEY_AUTO_SPIN: 67, + KEY_AUTO_FIRE: 69, + KEY_AUTO_ALT: 71, + KEY_OVER_RIDE: 82, + KEY_REVERSE_TANK: 86, + KEY_REVERSE_MOUSE: 66, + KEY_SPIN_LOCK: 88, KEY_LEVEL_UP: 78, - KEY_FUCK_YOU: 80,// P - KEY_CLASS_TREE: 84,// T - KEY_MAX_STAT: 77,// M - KEY_SUICIDE: 79,// O - KEY_ZOOM_OUT: 45,// ?? - KEY_ZOOM_IN: 61,// ?? - - KEY_UPGRADE_ATK: 49,// 1 - KEY_UPGRADE_HTL: 50,// 2 - KEY_UPGRADE_SPD: 51,// 3 - KEY_UPGRADE_STR: 52,// 4 - KEY_UPGRADE_PEN: 53,// 5 - KEY_UPGRADE_DAM: 54,// 6 - KEY_UPGRADE_RLD: 55,// 7 - KEY_UPGRADE_MOB: 56,// 8 - KEY_UPGRADE_RGN: 57,// 9 - KEY_UPGRADE_SHI: 48,// 0 - KEY_MOUSE_0: 32,// 32 - KEY_MOUSE_1: 86,// V - KEY_MOUSE_2: 16,// ShiftLeft - KEY_CHOOSE_1: 89,// Y - KEY_CHOOSE_2: 85,// U - KEY_CHOOSE_3: 73,// I - KEY_CHOOSE_4: 72,// H - KEY_CHOOSE_5: 74,// J - KEY_CHOOSE_6: 75,// K + KEY_FUCK_YOU: 192, + KEY_DEBUG: 76, + KEY_CLASS_TREE: 84, + KEY_MAX_STAT: 77, + KEY_SUICIDE: 79, + KEY_ZOOM_OUT: 45, + KEY_ZOOM_IN: 61, + KEY_TELEPORT: 80, + KEY_SMALLER_TANK: 188, + KEY_BIGGER_TANK: 190, + KEY_SMALLER_FOV: 187, + KEY_BIGGER_FOV: 189, + KEY_GOD_MODE: 186, + KEY_INVISIBLE: 222, + KEY_CAN_BE_ON_LEADERBOARD: 113, + KEY_STRONG: 191, + KEY_HEAL: 220, + KEY_WATCH_THIS: 219, + KEY_DRAG: 221, + KEY_SPAWN_WALL: 17, + KEY_RANDOM_TEST: 81, + KEY_CHANGE_SONG: 112, + KEY_ABILITY: 17, + KEY_SCREENSHOT: 81,//Q + KEY_RECORD: 90,//Z + KEY_UPGRADE_ATK: 49, + KEY_UPGRADE_HTL: 50, + KEY_UPGRADE_SPD: 51, + KEY_UPGRADE_STR: 52, + KEY_UPGRADE_PEN: 53, + KEY_UPGRADE_DAM: 54, + KEY_UPGRADE_RLD: 55, + KEY_UPGRADE_MOB: 56, + KEY_UPGRADE_RGN: 57, + KEY_UPGRADE_SHI: 48, + KEY_MOUSE_0: 32, + KEY_MOUSE_1: 86, + KEY_MOUSE_2: 16, + KEY_CHOOSE_1: 89, + KEY_CHOOSE_2: 85, + KEY_CHOOSE_3: 73, + KEY_CHOOSE_4: 72, + KEY_CHOOSE_5: 74, + KEY_CHOOSE_6: 75, + KEY_WIKI: 118, + showTree: false, + scrollX: 0, realScrollX: 0, // Canvas @@ -112,18 +133,25 @@ const global = { gameHeight: 0, xoffset: -0, yoffset: -0, + movement: false, + motion: { x: 0, y: 0 }, gameLoading: false, gameStart: false, disconnected: false, autoSpin: false, + syncingWithTank: false, + respawnTimeout: false, + showDebug: false, died: false, kicked: false, continuity: false, + wiki: false, startPingTime: 0, toggleMassState: 0, backgroundColor: '#f2fbff', lineColor: '#000000', nameColor: "#FFFFFF", + message: "", player: {}, messages: [], mockups: [], @@ -135,6 +163,7 @@ const global = { upgrade: Region(100), hover: Region(1), skipUpgrades: Region(1), + mobileButtons: Region(20), }, statHover: false, upgradeHover: false, @@ -148,7 +177,33 @@ const global = { lastrender: 0, rendergap: 0, lastuplink: 0, + killcount: 0, + shapecount: 0, + }, + mobileStatus: { + enableCrosshair: false, + showCrosshair: false, + useBigJoysticks: false, + showJoysticks: false, }, + GUIStatus: { + renderGUI: false, + renderLeaderboard: false, + renderhealth: false, + renderPlayerNames: false, + renderPlayerScores: false, + minimapReducedInfo: false, + }, + emojiloaded: false, + wikidisplaytank: 25, + wikiclassname: "basic", + ISTHEGODAMNFUCKINGGAMEON: "no", + killsoundready: true, + skin: "", + skinpage: 0, + savedkillcount: 0, + savedshapecount: 0, + lockedornot: 0, mouse: { x: 0, y: 0}, target: { x: 0, y: 0 }, reverseTank: 1, @@ -157,6 +212,13 @@ const global = { ratio: window.devicePixelRatio, mockupLoading: { then: cb => cb() }, treeScale: 1, - chats: {} + chats: {}, + music2: { + src: "", + songname: "", + }, + corruptprogression: 0, + stopthefuckingkillsoundyouprick: false, + blackhole: false }; export { global } diff --git a/public/lib/json/color.json b/public/lib/json/color.json index 6c64942c4..fe6fcaea8 100644 --- a/public/lib/json/color.json +++ b/public/lib/json/color.json @@ -1,4 +1,33 @@ { + "nero": { + "teal": "#9EFFE0", + "lgreen": "#87FF8D", + "orange": "#FFB675", + "yellow": "#FDF380", + "lavender": "#b58efd", + "aqua": "#7adbba", + "pink": "#FFBDDD", + "vlgrey": "#E8EBF7", + "lgrey": "#b6b7ba", + "guiwhite": "#F0F0F0", + "black": "#484848", + "blue": "#52A8EB", + "green": "#8ABC3F", + "red": "#FC4E51", + "gold": "#EFC74B", + "purple": "#8D6ADF", + "magenta": "#ED2891", + "grey": "#A7A7AF", + "dgrey": "#726F6F", + "white": "#F0F8FA", + "guiblack": "#000000", + "mustard": "#c49608", + "tangerine": "#ec7b0f", + "brown": "#895918", + "cyan": "#13808e", + "paletteSize": 10, + "border": 0.65 + }, "normal": { "teal": "#7ad3db", "lgreen": "#b9e87e", @@ -28,6 +57,35 @@ "paletteSize": 20, "border": 0.6509803921568628 }, + neroclassic: { + "teal": "#7ADBBC", + "lgreen": "#B9E87E", + "orange": "#E7896D", + "yellow": "#FDF380", + "lavender": "#842da1", + "aqua": "#7adbba", + "pink": "#EF99C3", + "vlgrey": "#E8EBF7", + "lgrey": "#AA9F9E", + "guiwhite": "#F0F0F0", + "black": "#484848", + "blue": "#3CA4CB", + "green": "#8ABC3F", + "red": "#E03E41", + "gold": "#EFC74B", + "purple": "#8D6ADF", + "magenta": "#CC669C", + "grey": "#A7A7AF", + "dgrey": "#726F6F", + "white": "#a9abcf", + "guiblack": "#000000", + "mustard": "#c49608", + "tangerine": "#ec7b0f", + "brown": "#895918", + "cyan": "#13808e", + "paletteSize": 10, + "border": 0.3 + }, "dark": { "teal": "#6ecedc", "lgreen": "#0c491d", diff --git a/public/lib/json/manifest.json b/public/lib/json/manifest.json index edb615004..8d9cdc749 100644 --- a/public/lib/json/manifest.json +++ b/public/lib/json/manifest.json @@ -1,15 +1,15 @@ { - "name": "Open Source Arras", - "theme_color": "#454b7f", + "name": "Nero.io 2", + "theme_color": "#000000", "background_color": "#484948", - "description": "This server runs on Open Source Arras.", + "description": "Nero.io 2 runs on Open Source Arras.", "orientation": "landscape", "start_url": "/", "scope": "/", "display": "fullscreen", "icons": [{ - "src": "round.png", + "src": "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2023_12_06_0za_Kleki.png?v=1701910145704", "sizes": "96x96", "type": "image/png" }] -} +} \ No newline at end of file diff --git a/public/lib/settings.js b/public/lib/settings.js index 5991c0fe4..739c91b7c 100644 --- a/public/lib/settings.js +++ b/public/lib/settings.js @@ -3,21 +3,25 @@ const settings = { screenshotMode: false, borderChunk: 6, barChunk: 4, - mininumBorderChunk: 3, + mininumBorderChunk: 0.5, deathBlurAmount: 3, darkBorders: false, fancyAnimations: true, - colors: 'normal', + lowResolution: false, + colors: 'nero', pointy: true, + showGrid: true, fontSizeBoost: 1.4, fontStrokeRatio: 4.5, neon: false, coloredHealthbars: false, - seperatedHealthbars: false + seperatedHealthbars: false, + showHealthText: false, + quality: "normal" }, lag: { unresponsive: false, - memory: 60 + memory: 500 }, game: { autoLevelUp: false diff --git a/public/lib/socketInit.js b/public/lib/socketInit.js index 8d841f31f..4fa4c5bb3 100644 --- a/public/lib/socketInit.js +++ b/public/lib/socketInit.js @@ -26,14 +26,14 @@ var serverStart = 0, ], skills: [ { amount: 0, color: 'purple', cap: 1, softcap: 1 }, - { amount: 0, color: 'pink' , cap: 1, softcap: 1 }, - { amount: 0, color: 'blue' , cap: 1, softcap: 1 }, + { amount: 0, color: 'pink', cap: 1, softcap: 1 }, + { amount: 0, color: 'blue', cap: 1, softcap: 1 }, { amount: 0, color: 'lgreen', cap: 1, softcap: 1 }, - { amount: 0, color: 'red' , cap: 1, softcap: 1 }, + { amount: 0, color: 'red', cap: 1, softcap: 1 }, { amount: 0, color: 'yellow', cap: 1, softcap: 1 }, - { amount: 0, color: 'green' , cap: 1, softcap: 1 }, - { amount: 0, color: 'teal' , cap: 1, softcap: 1 }, - { amount: 0, color: 'gold' , cap: 1, softcap: 1 }, + { amount: 0, color: 'green', cap: 1, softcap: 1 }, + { amount: 0, color: 'teal', cap: 1, softcap: 1 }, + { amount: 0, color: 'gold', cap: 1, softcap: 1 }, { amount: 0, color: 'orange', cap: 1, softcap: 1 } ], points: 0, @@ -53,16 +53,17 @@ var serverStart = 0, } }, update: () => { - levelscore = Math.ceil(1.8 * Math.pow(level + 1, 1.8) - 2 * level + 1); - if (sscore.get() - deduction >= levelscore - 0.001) { - deduction += levelscore; + levelscore = Math.ceil(Math.pow(level, 3) * 0.3083); + if (sscore.get() >= levelscore - 0.01) { + deduction = levelscore; level += 1; } }, - getProgress: () => levelscore ? Math.min(1, Math.max(0, (sscore.get() - deduction) / levelscore)) : 0, + getProgress: () => levelscore ? Math.min(1, Math.max(0, (sscore.get() - deduction) / (levelscore - deduction))) : 0, getScore: () => sscore.get(), getLevel: () => level, }, + showhealthtext: false, type: 0, root: "", class: "", @@ -224,6 +225,7 @@ const Entry = class { let indexes = this.index.split("-"), ref = global.mockups[parseInt(indexes[0])]; return { + id: this.id, image: util.getEntityImageFromMockup(this.index, this.color), position: ref.position, barColor: this.bar, @@ -470,7 +472,7 @@ const process = (z = {}) => { z.vy = get.next(); z.size = get.next(); z.facing = get.next(); - z.perceptionAngleIndependence = get.next(); //z.vfacing = get.next(); + z.perceptionAngleIndependence = get.next(); z.defaultAngle = get.next(); z.twiggle = get.next(); z.layer = get.next(); @@ -481,11 +483,15 @@ const process = (z = {}) => { // Update health, flagging as injured if needed if (isNew) { z.health = get.next() / 65535; + z.healthN = get.next(); + z.maxHealthN = get.next(); z.shield = get.next() / 65535; } else { let hh = z.health, ss = z.shield; z.health = get.next() / 65535; + z.healthN = get.next(); + z.maxHealthN = get.next(); z.shield = get.next() / 65535; // Update stuff if (z.health < hh || z.shield < ss) { @@ -508,6 +514,7 @@ const process = (z = {}) => { z.render = { draws: false, expandsWithDeath: z.drawsHealth, + dontDeathAnim: z.name, lastRender: global.player.time, x: z.x, y: z.y, @@ -566,18 +573,15 @@ const process = (z = {}) => { } // Update turrets let turnumb = get.next(); - if (turnumb) { - let b = 1; - } - if (isNew) { + if (isNew || z.turrets.length !== turnumb) { z.turrets = []; for (let i = 0; i < turnumb; i++) { z.turrets.push(process()); } } else { - if (z.turrets.length !== turnumb) { - throw new Error('Mismatch between data turret number and remembered turret number!'); - } + // if (z.turrets.length !== turnumb) { + // throw new Error('Mismatch between data turret number and remembered turret number!'); + // } for (let tur of z.turrets) { tur = process(tur); } @@ -625,6 +629,7 @@ const convert = { let index = get.next(), // Translate the encoded index indices = { + showhealthtext: index & 0x0800, class: index & 0x0400, root: index & 0x0200, topspeed: index & 0x0100, @@ -691,6 +696,9 @@ const convert = { if (indices.class) { gui.class = get.next(); } + if (indices.showhealthtext) { + gui.showhealthtext = get.next(); + } }, broadcast: () => { let all = get.all(); @@ -751,21 +759,17 @@ const protocols = { }; const socketInit = port => { window.resizeEvent(); - let socket = new WebSocket(protocols[location.protocol] + window.serverAdd); + let socket = new WebSocket(protocols[window.connectionAdd] + window.serverAdd); // Set up our socket socket.binaryType = 'arraybuffer'; socket.open = false; // Handle commands let flag = false; let commands = [ - false, // up - false, // down - false, // left - false, // right + false, // moving false, // lmb false, // mmb false, // rmb - false, ]; socket.cmd = { set: (index, value) => { @@ -777,17 +781,13 @@ const socketInit = port => { talk: () => { flag = false; let o = 0; - for (let i = 0; i < 8; i++) { + for (let i = 0; i < commands.length; i++) { if (commands[i]) o += Math.pow(2, i); } let ratio = util.getRatio(); - socket.talk('C', Math.round(global.target.x / ratio), Math.round(global.target.y / ratio), global.reverseTank, o); + socket.talk('C', Math.round(global.target.x / ratio), Math.round(global.target.y / ratio), global.reverseTank, global.movement, o); }, check: () => flag, - getMotion: () => ({ - x: commands[3] - commands[2], - y: commands[1] - commands[0], - }), }; // Learn how to talk socket.talk = async (...message) => { @@ -809,6 +809,18 @@ const socketInit = port => { if (socket.cmd.check()) socket.cmd.talk(); }); }; + var KillSound = new Audio(); + KillSound.volume = 0.5; + function PlaySoundKS() { + KillSound.src = ("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/untitled.wav?v=1733614029212"); + KillSound.play(); + } + var NotifSound = new Audio(); + NotifSound.volume = 0.5; + function PlaySoundNotif() { + NotifSound.src = ("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/123123.wav?v=1734187686345"); + NotifSound.play(); + } // Handle incoming messages socket.onmessage = async function socketMessage(message) { await new Promise(Resolve => setTimeout(Resolve, window.fakeLagMS)); @@ -821,11 +833,15 @@ const socketInit = port => { switch (m.shift()) { case 'w': // welcome to the game if (m[0]) { // Ask to spawn - console.log('The server has welcomed us to the game room. Sending spawn request.'); - socket.talk('s', global.playerName, 1, 1 * settings.game.autoLevelUp); - global.message = ''; + console.log('The server has welcomed us to the game room.'); + global.message = 'Loading mockups, this could take a bit...'; + global.mockupLoading.then(() => { + console.log('Sending spawn request.'); + socket.talk('s', global.playerName, 1, 1 * settings.game.autoLevelUp, global.skin); + global.message = ''; + }); } - break; + break; case 'R': // room setup global.gameWidth = m[0]; global.gameHeight = m[1]; @@ -845,6 +861,40 @@ const socketInit = port => { global.message = m[0]; console.log(m[0]); break; + case "svInfo": // For debugging. + global.serverName = m[0]; + global.mspt = m[1]; + if (global.showDebug) console.log(`mspt: ${global.mspt} total entities on screen: ${global.entities.length} Player X: ${(global.player.renderx).toFixed(1)} Player Y: ${(global.player.rendery).toFixed(1)}`); + break; + case "updateName": // Update the name if needed. + global.player.name = m[0]; + break; + case "achieve": + const achievementTable = ['killachievement', 'killachievement2', 'tokenachievement', 'bossachivement', 'deathachievement'] // lookup table of achievements and their ids + util.submitAchievementToLocalStorage(achievementTable[m[0]]) // whatever code to actually give the player the achievement + break; + case "menu": + document.getElementById("startMenuWrapper").style = "display: block; inset: 0; animation: fadezoomin 300ms forwards;"; + document.getElementById("startMenuWrapper").focus(); + document.getElementById("startButton").innerHTML = "Resume!" + break; + case "killgained": + PlaySoundKS() + global.metrics.killcount += 1; + global.savedkillcount = (Number(localStorage.getItem("savedkills")) + 1); + localStorage.setItem("savedkills", global.savedkillcount.toString()); + break; + case "shapegained": + global.metrics.shapecount += 1; + global.savedshapecount = (Number(localStorage.getItem("savedshapes")) + 1); + localStorage.setItem("savedshapes", global.savedshapecount.toString()); + break; + case "killstreakreset": + global.metrics.killcount = 0; + break; + case "blackhole": + m[0] ? global.blackhole = true : global.blackhole = false; + break case 'c': // force camera move global.player.renderx = global.player.cx = m[0]; global.player.rendery = global.player.cy = m[1]; @@ -863,6 +913,7 @@ const socketInit = port => { if (sync.length < 10) { // Wait a bit just to space things out setTimeout(() => socket.talk('S', getNow()), 10); + global.canThrowSyncClockError = true; global.message = "Syncing clocks, please do not tab away. " + sync.length + "/10..."; } else { // Calculate the clock error @@ -882,25 +933,19 @@ const socketInit = port => { } } clockDiff = Math.round(sum / valid); + global.canThrowSyncClockError = false; // Start the game console.log(sync); - console.log('Syncing complete, calculated clock difference ' + clockDiff + 'ms.'); - global.message = 'Loading mockups, this could take a bit...'; - global.mockupLoading.then(() => { + console.log('Syncing complete, calculated clock difference ' + clockDiff + 'ms. Beginning game.'); console.log('Beginning game.'); global.gameStart = true; global.entities = []; global.message = ''; - }); + global.canThrowClosedMessage = true; } break; case 'm': // message - global.messages.push({ - text: m[1], - status: 2, - alpha: 0, - time: Date.now() + m[0], - }); + global.createMessage(m[1], m[0]); break; case 'u': // uplink // Pull the camera info @@ -976,20 +1021,41 @@ const socketInit = port => { global.finalLifetime = util.Smoothbar(0, 5); global.finalLifetime.set(m[1]); global.finalKills = [util.Smoothbar(0, 3), util.Smoothbar(0, 4.5), util.Smoothbar(0, 2.5), util.Smoothbar(0, 10)]; - global.finalKills[0].set(m[2]); - global.finalKills[1].set(m[3]); - global.finalKills[2].set(m[4]); - global.finalKills[3].set(m[5]); + global.respawnTimeout = m[2]; + if (global.respawnTimeout > 0) { + global.cannotRespawn = true; + let respawnTimeoutloop = setInterval(() => { + if (global.respawnTimeout <= 1) { + global.cannotRespawn = false; + global.respawnTimeout = false; + clearInterval(respawnTimeoutloop); + } else { + global.respawnTimeout--; + } + }, 1000); // One second. + } + global.finalKills[0].set(m[3]); + global.finalKills[1].set(m[4]); + global.finalKills[2].set(m[5]); + global.finalKills[3].set(m[6]); global.finalKillers = []; - for (let i = 0; i < m[6]; i++) { - global.finalKillers.push(m[7 + i]); + for (let i = 0; i < m[7]; i++) { + global.finalKillers.push(m[8 + i]); } window.animations.deathScreen.reset(); window.canvas.reverseDirection = false; global.died = true; global.autoSpin = false; + global.syncingWithTank = false; window.onbeforeunload = () => false; break; + case 'I': // sync with the tank + if (m[0]) { + global.syncingWithTank = true; + } else { + global.syncingWithTank = false; + } + break; case 'K': // kicked window.onbeforeunload = () => false; break; @@ -1023,6 +1089,8 @@ const socketInit = port => { clearInterval(socket.commandCycle); window.onbeforeunload = () => false; console.log('The connection has closed.'); + if (global.canThrowSyncClockError) global.message = "Failed to sync with the server. Please try again." + if (global.canThrowClosedMessage) global.message = "The connection has closed. Refresh to continue playing!" }; // Notify about errors socket.onerror = error => { @@ -1033,4 +1101,4 @@ const socketInit = port => { return socket; }; -export { socketInit, gui, leaderboard, minimap, moveCompensation, lag, getNow }; +export { socketInit, gui, leaderboard, minimap, moveCompensation, lag, getNow }; \ No newline at end of file diff --git a/public/lib/tankdesc.js b/public/lib/tankdesc.js new file mode 100644 index 000000000..63867519f --- /dev/null +++ b/public/lib/tankdesc.js @@ -0,0 +1,775 @@ +//uhhhhhhh hiiiiii!!!!!!!!!! +//this is my server! +//its called nero.io, in development for 5 years now..... +//i mean...you can remix it if you want! just uh...idk...nvm +//type: Assaulter, Spammer, Defender, Controller, Ranger, Basher, Supporter, Catalyst +const tankdescs = { +/* + template: { + type: "", + desc: "", + tier: "", + weapons: "", + abilities: "", + weak: "", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "", + origin: "", + updateadded: "", + } +*/ + basic: { + type: "Catalyst", + desc: "The Starting Tank Of Nero.io, The Beginning Of Nero.io, The Catalyst Of Nero.io, It Starts It All.", + tier: "1", + weapons: "Bullets", + abilities: "N/A", + weak: "N/A", + upgradesto: ["Tier 2: Twin, Sniper, Machine Gun, Flank Guard, Director, Pounder, Trapper, Auto-Basic, Desmos, Basic-Hybrid, Subduer, Inception.", + "Tier 3: Smasher, Cloner.", + "Misc: Daily Tank", + "---"], + upgradesfrom: "N/A", + origin: "diep.io", + updateadded: "1.0", + }, + twin: { + type: "Assaulter", + desc: "Basic With An Extra Front Barrel. Good If You Like More Barrels Without Losing Too Much Penetration. Excels In Mid To Long-ish Range Combat.", + tier: "2", + weapons: "Bullets", + abilities: "N/A", + weak: "N/A", + upgradesto: ["Tier 3: Double Twin, Triple Shot, Gunner, Hexa Tank, Auto Twin, Helix, Twin Hybrid, Binary", + "Tier 4: Bulwark, Musket", + "---", + "---"], + upgradesfrom: "Basic", + origin: "diep.io", + updateadded: "1.0", + }, + sniper: { + type: "Ranger", + desc: "Longer and more Powerful Basic. Good for Long Range, Dont Get Too Close To Your Enemy Though As Snipers Are Meant For Long Range Combat Afterall...", + tier: "2", + weapons: "Bullets", + abilities: "N/A", + weak: "Drones, Close Range", + upgradesto: ["Tier 2: Assassin, Hunter", + "Tier 3: ", + "Tier 4: ", + "Misc: N/A"], + upgradesfrom: "Basic", + origin: "diep.io", + updateadded: "1.0", + }, + machineGun: { + type: "Spammer", + desc: "Easy To Play As, Fun To Use. Good For Spamming, Not The Best Idea To Go Up Against High Penetration Tanks Though!", + tier: "2", + weapons: "Bullets", + abilities: "N/A", + weak: "Drones, Snipers", + upgradesto: ["Tier 2: Gunner", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Basic", + origin: "diep.io", + updateadded: "1.0", + }, + flankGuard: { + type: "Assaulter", + desc: "Guards Your Back From Sneaky People. Great At Getting More Bullet Coverage. Well Balanced And Serves Its Perpose", + tier: "2", + weapons: "Bullets", + abilities: "N/A", + weak: "N/A", + upgradesto: ["Tier 2: Hexa Tank, Tri-Angle", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Basic", + origin: "diep.io", + updateadded: "1.0", + }, + director: { + type: "Controller", + desc: "Instead Of Bullets, Try Drones! Control Them With The Cursor. Beware Though, The Drones May Not Go As Fast As You Want Them To.", + tier: "2", + weapons: "Drones", + abilities: "N/A", + weak: "Assaulters, Fast Tanks", + upgradesto: ["Tier 2: Overseer", + "Tier 3: ", + "Tier 4: ", + "Misc: N/A"], + upgradesfrom: "Basic", + origin: "arras.io", + updateadded: "1.0", + }, + pounder: { + type: "Assaulter", + desc: "Heavier Bullets With More Of A Kick To Them. Great For Close Combat, Just Dont Let The Slower Fire Rate And Bullet Speed Kill You!", + tier: "2", + weapons: "Bullet", + abilities: "N/A", + weak: "N/A", + upgradesto: ["Tier 2: Destroyer", + "Tier 3: ", + "Tier 4: ", + "Misc: N/A"], + upgradesfrom: "Basic", + origin: "arras.io", + updateadded: "1.0", + }, + trapper: { + type: "Defender", + desc: "Deploys Traps Instead Of Bullets, These Act Like Shields To Protect You From Things. They Arent Invincible Though!", + tier: "2", + weapons: "Traps", + abilities: "N/A", + weak: "N/A", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Basic", + origin: "diep.io", + updateadded: "1.6", + }, + desmos: { + type: "Spammer", + desc: "Gives Bullets The Ability To Act Like Waves, Helpful For Getting Around High Bullet Health Coming Straight At You", + tier: "2", + weapons: "Sine-Bullets", + abilities: "N/A", + weak: "N/A", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Basic", + origin: "arras.io", + updateadded: "2.8", + }, + smasher: { + type: "Basher", + desc: "No Guns, Only Melee Damage. For People Who Like Agressive Playstyles Or Just Want Something More In Your Control", + tier: "3", + weapons: "Armour", + abilities: "N/A", + weak: "Anything Faster", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Basic", + origin: "diep.io", + updateadded: "1.0", + }, + healer: { + type: "Supporter", + desc: "", + tier: "3", + weapons: "Healer-Bullets", + abilities: "Healing", + weak: "", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Basic?Siege", + origin: "arras.io", + updateadded: "2.8", + }, + doubleTwin: { + type: "Assaulter", + desc: "", + tier: "3", + weapons: "Bullets", + abilities: "N/A", + weak: "N/A", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Twin, Flank Guard", + origin: "diep.io", + updateadded: "1.0", + }, + tripleShot: { + type: "Assaulter", + desc: "", + tier: "4", + weapons: "Bullets", + abilities: "N/A", + weak: "N/A", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "", + origin: "diep.io", + updateadded: "1.0", + }, + tripleTwin: { + type: "Assaulter", + desc: "", + tier: "4", + weapons: "Bullets", + abilities: "N/A", + weak: "N/A", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "", + origin: "diep.io", + updateadded: "1.0", + }, + hewnDouble: { + type: "Assaulter", + desc: "", + tier: "4", + weapons: "Bullets", + abilities: "N/A", + weak: "N/A", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Double Twin", + origin: "arras.io", + updateadded: "1.0", + }, + pentaShot: { + type: "Assaulter", + desc: "", + tier: "4", + weapons: "Bullets", + abilities: "N/A", + weak: "N/A", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Triple Shot", + origin: "diep.io", + updateadded: "1.0", + }, + spreadshot: { + type: "Assaulter", + desc: "", + tier: "4", + weapons: "Bullets", + abilities: "N/A", + weak: "N/A", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Triple Shot", + origin: "diep.io", + updateadded: "1.0", + }, + bentDouble: { + type: "Assaulter", + desc: "", + tier: "4", + weapons: "Bullets", + abilities: "N/A", + weak: "N/A", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Penta Shot, Double Twin", + origin: "arras.io", + updateadded: "1.0", + }, + triplet: { + type: "Assaulter", + desc: "", + tier: "4", + weapons: "Bullets", + abilities: "N/A", + weak: "N/A", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Triple Shot", + origin: "diep.io", + updateadded: "1.0", + }, + assassin: { + type: "Ranger", + desc: "", + tier: "3", + weapons: "Bullets", + abilities: "N/A", + weak: "N/A", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Sniper", + origin: "diep.io", + updateadded: "1.0", + }, + hunter: { + type: "Ranger", + desc: "", + tier: "3", + weapons: "Bullets", + abilities: "Scope", + weak: "N/A", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Sniper", + origin: "diep.io", + updateadded: "1.0", + }, + rifle: { + type: "Ranger", + desc: "", + tier: "3", + weapons: "Bullets", + abilities: "N/A", + weak: "N/A", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Sniper", + origin: "arras.io", + updateadded: "2.2", + }, + marksman: { + type: "Ranger", + desc: "", + tier: "3", + weapons: "Splitter Bullets", + abilities: "N/A", + weak: "High DPS", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Sniper", + origin: "arras.io", + updateadded: "N/A", + }, + ranger: { + type: "Ranger", + desc: "", + tier: "4", + weapons: "Bullets", + abilities: "N/A", + weak: "N/A", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Assassin", + origin: "diep.io", + updateadded: "1.0", + }, + stalker: { + type: "Ranger", + desc: "", + tier: "3", + weapons: "Bullets", + abilities: "Invisibility", + weak: "N/A", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Assassin", + origin: "diep.io", + updateadded: "2.3", + }, + single: { + type: "Assaulter", + desc: "", + tier: "4", + weapons: "Bullets", + abilities: "N/A", + weak: "N/A", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Assassin", + origin: "arras.io", + updateadded: "1.0", + }, + predator: { + type: "Ranger", + desc: "", + tier: "4", + weapons: "Bullets", + abilities: "Scope", + weak: "N/A", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Hunter", + origin: "diep.io", + updateadded: "1.0", + }, + xHunter: { + type: "Ranger", + desc: "", + tier: "4", + weapons: "Bullets", + abilities: "Heavy Scope", + weak: "N/A", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Hunter", + origin: "arras.io", + updateadded: "2.7", + }, + dual: { + type: "Ranger-Assaulter", + desc: "Hunter With Dual Barrels Similar To Twin", + tier: "4", + weapons: "Bullets", + abilities: "Scope", + weak: "N/A", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Hunter", + origin: "arras.io", + updateadded: "1.2", + }, + musket: { + type: "Ranger-Assaulter", + desc: "Rifle With Dual Barrels Similar To Twin", + tier: "4", + weapons: "Bullets", + abilities: "N/A", + weak: "N/A", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Rifle, Twiper", + origin: "arras.io", + updateadded: "2.2", + }, + crossbow: { + type: "Ranger-Assaulter", + desc: "Rifle With Added Mini Barrels", + tier: "4", + weapons: "Bullets", + abilities: "N/A", + weak: "N/A", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Rifle", + origin: "arras.io", + updateadded: "2.2", + }, + /*deadeye: { + type: "", + desc: "Marksman but same stats as asassin", + tier: "4", + weapons: "Bullets", + abilities: "N/A", + weak: "???", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Asassin, Marksman", + origin: "arras.io", + updateadded: "N/A", + }, + nimrod: { + type: "", + desc: "Marksman but same as Hunter", + tier: "4", + weapons: "Bullets", + abilities: "Scope", + weak: "???", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Hunter, Marksman", + origin: "arras.io", + updateadded: "N/A", + }, + revolver: { + type: "", + desc: "Marksman but same stats as Rifle", + tier: "4", + weapons: "Bullets", + abilities: "N/A", + weak: "???", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Rifle, Marksman", + origin: "arras.io", + updateadded: "N/A", + },*/ + fork: { + type: "", + desc: "Marksman but more split bullets", + tier: "4", + weapons: "Bullets", + abilities: "N/A", + weak: "???", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Marksman", + origin: "arras.io", + updateadded: "N/A", + }, + minigun: { + type: "Spammer", + desc: "3 Stacked Barrels Firing Very Fast", + tier: "3", + weapons: "Bullets", + abilities: "N/A", + weak: "N/A", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Sniper, Machine Gun, Subduer", + origin: "arras.io", + updateadded: "1.0", + }, + gunner: { + type: "Spammer", + desc: "", + tier: "3", + weapons: "Bullets", + abilities: "N/A", + weak: "N/A", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Twin, Machine Gun", + origin: "diep.io", + updateadded: "1.0", + }, + sprayer: { + type: "Spammer", + desc: "", + tier: "3", + weapons: "Bullets", + abilities: "N/A", + weak: "N/A", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Machine Gun, Subduer", + origin: "diep.io", + updateadded: "1.0", + }, + streamliner: { + type: "Spammer", + desc: "Minigun with an extra 2 barrels with increased FOV", + tier: "4", + weapons: "Bullets", + abilities: "N/A", + weak: "N/A", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Minigun", + origin: "diep.io", + updateadded: "1.0", + }, + barricade: { + type: "Defense-Spammer", + desc: "", + tier: "4", + weapons: "Bullets", + abilities: "N/A", + weak: "N/A", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Trapper, Minigun", + origin: "arras.io", + updateadded: "2.6", + }, + nailgun: { + type: "Spammer", + desc: "Small, fast and high pen bullets that can penetrate enemy fire", + tier: "4", + weapons: "Bullets", + abilities: "N/A", + weak: "N/A", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Minigun", + origin: "arras.io", + updateadded: "1.0", + }, + machineGunner: { + type: "Spammer", + desc: "High fire rate spammer", + tier: "4", + weapons: "Bullets", + abilities: "N/A", + weak: "N/A", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Gunner", + origin: "arras.io", + updateadded: "1.0", + }, + machineGunner: { + type: "Spammer", + desc: "High fire rate spammer", + tier: "4", + weapons: "Bullets", + abilities: "N/A", + weak: "N/A", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Gunner", + origin: "arras.io", + updateadded: "1.0", + }, + redistributor: { + type: "Spammer", + desc: "Sprayer with an extra barrel", + tier: "4", + weapons: "Bullets", + abilities: "N/A", + weak: "N/A", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Minigun, Sprayer", + origin: "arras.io", + updateadded: "2.9", + }, + atomizer: { + type: "Spammer", + desc: "Machine gun with an extra smaller machine gun", + tier: "4", + weapons: "Bullets", + abilities: "N/A", + weak: "N/A", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Sprayer", + origin: "arras.io", + updateadded: "2.9", + }, + focal: { + type: "Spammer", + desc: "Machine gun with smaller funnel barrel for more accuracy", + tier: "4", + weapons: "Bullets", + abilities: "N/A", + weak: "N/A", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Sprayer", + origin: "arras.io", + updateadded: "2.9", + }, + hexaTank: { + type: "Assaulter", + desc: "6 Basic barrels on all sides", + tier: "3", + weapons: "Bullets", + abilities: "N/A", + weak: "N/A", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Flank Guard, Twin", + origin: "arras.io", + updateadded: "1.0", + }, + triAngle: { + type: "Assaulter", + desc: "Machine gun with an extra smaller machine gun", + tier: "3", + weapons: "Bullets", + abilities: "N/A", + weak: "N/A", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Flank Guard, Propel", + origin: "diep.io", + updateadded: "1.0", + }, + auto3: { + type: "Assaulter", + desc: "Flank Guard but with Automatic aiming turrets", + tier: "3", + weapons: "Bullets", + abilities: "N/A", + weak: "N/A", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Flank Guard", + origin: "diep.io", + updateadded: "1.0", + }, + octoTank: { + type: "Assaulter", + desc: "has 8 barrels surrounding the tank", + tier: "4", + weapons: "Bullets", + abilities: "N/A", + weak: "N/A", + upgradesto: ["Tier 2: ", + "Tier 3: ", + "Tier 4: ", + "Misc: "], + upgradesfrom: "Flank Guard", + origin: "diep.io", + updateadded: "1.0", + } +}; +export { tankdescs } \ No newline at end of file diff --git a/public/lib/util.js b/public/lib/util.js index d0b93dad3..4423157a5 100644 --- a/public/lib/util.js +++ b/public/lib/util.js @@ -11,6 +11,25 @@ const util = { document.getElementById(name).checked = localStorage.getItem(name + 'Checked') === 'true'; return false; }, + retrieveFromLocalStorageCheckDefault: name => { + if (localStorage.getItem(name + 'Checked') === undefined) { + document.getElementById(name).value = (name + 'Value'); + document.getElementById(name).checked = (name + 'Checked') === 'true'; + return false; + } else { + document.getElementById(name).value = localStorage.getItem(name + 'Value'); + document.getElementById(name).checked = localStorage.getItem(name + 'Checked') === 'true'; + return false; + } + }, + submitAchievementToLocalStorage: achive => { + localStorage.setItem(achive, "YOUDIDIT:D!!!"); + return false; + }, + resetAchievementFromLocalStorage: achive => { + localStorage.setItem(achive, "noachievement"); + return false; + }, handleLargeNumber: (a, cullZeroes = false) => { if (cullZeroes && a == 0) { return ''; @@ -68,7 +87,7 @@ const util = { }, pullJSON: fileName => { return new Promise((resolve, reject) => { - const url = `${location.protocol}//${window.serverAdd}/lib/json/${fileName}.json`; + const url = `${window.connectionAdd}//${window.serverAdd}/lib/json/${fileName}.json`; console.log("Loading JSON from " + url); fetch(url).then(response => response.json()).then(json => { console.log("JSON load from " + url + " complete"); @@ -199,6 +218,7 @@ const util = { facing: mainMockup.facing, shape: mainMockup.shape, name: name.substring(1), + className: mainMockup.className, upgradeTooltip: upgradeTooltip.substring(1), upgradeName: mainMockup.upgradeName, score: 0, @@ -206,6 +226,7 @@ const util = { layer: mainMockup.layer, position: util.sizeMultipleMockups(positionData), rerootUpgradeTree, + trueupgrades: mainMockup.trueupgrades, guns: { length: guns.length, getPositions: () => Array(guns.length).fill(0), @@ -246,9 +267,8 @@ const util = { }), }; }, - sizeMultipleMockups: (positionData) => { + sizeMultipleMockups: (positionData) => { let endPoints = []; - function rounder(val) { if (Math.abs(val) < 0.00001) val = 0; return +val.toPrecision(6); @@ -290,7 +310,6 @@ const util = { // Check point is on the line with a small margin return Math.abs(checkPoint[1] - predictedY) <= 1e-5; } - // Find circumcircle and circumcenter function constructCircumcirle(point1, point2, point3) { // Rounder to avoid floating point nonsense @@ -300,7 +319,6 @@ const util = { let y2 = rounder(point2[1]); let x3 = rounder(point3[0]); let y3 = rounder(point3[1]); - // Invalid math protection if (x3 == x1 || x3 == x2) { x3 += 1e-5; @@ -315,7 +333,6 @@ const util = { let y = (numer1 * factorX1 - numer2 * factorX2) / (factorY1 * factorX2 - factorY2 * factorX1); let x = ((y - y3) ** 2 - (y - y1) ** 2 - x1 ** 2 + x3 ** 2) / factorX2; let r = Math.sqrt(Math.pow(x - x1, 2) + Math.pow(y - y1, 2)); - return {x, y, r}; } @@ -327,7 +344,6 @@ const util = { endPoints.push([middle.x + Math.cos(theta) * axis / 2, middle.y + Math.sin(theta) * axis / 2]); } } - // Convert to useful info endPoints.sort((a, b) => (b[0] ** 2 + b[1] ** 2 - a[0] ** 2 - a[1] ** 2)); let point1 = getFurthestFrom(0, 0), @@ -337,7 +353,6 @@ const util = { while (point1[0] == 0 && point2[0] == 0 || point1[1] == 0 && point2[1] == 0) { point2 = getFurthestFrom(...point1); } - let avgX = (point1[0] + point2[0]) / 2, avgY = (point1[1] + point2[1]) / 2, point3 = getFurthestFrom(avgX, avgY); @@ -348,7 +363,6 @@ const util = { } let {x, y, r} = constructCircumcirle(point1, point2, point3); - return { axis: r * 2, middle: {x, y}, diff --git a/public/main.css b/public/main.css index 43bd90677..5593d0ac3 100644 --- a/public/main.css +++ b/public/main.css @@ -1,6 +1,8 @@ :root { font-family: Ubuntu; font-size: 14px; + --backgroundColor: #DDE6EB; + --menuTextColor: #000000; } .conceal { @@ -8,7 +10,7 @@ } #mainBody { - background-color: #dbdbdb; + background-color: #484848; } ::-webkit-scrollbar { @@ -18,12 +20,12 @@ ::-webkit-scrollbar-track { border-radius: 3px; - background: rgba(0, 0, 0, 0.15); + background: oklch(0% 0 0 / 15%); } ::-webkit-scrollbar-thumb { border-radius: 3px; - background: rgba(0, 0, 0, 0.3); + background: oklch(0% 0 0 / 30%); } html, @@ -36,29 +38,52 @@ body { -moz-user-select: none; user-select: none; } - body { font-family: Ubuntu; font-size: 14px; - background-image: url('./osa_background_tile.png'); + background-image: url("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/nero-logo-text.png?v=1746742162513"); background-repeat: repeat; - background-color: gray; + background-color: #484848; } html, body, -canvas { +canvas[id=gameCanvas] { width: 100%; height: 100%; margin: 0; padding: 0; } -canvas { +canvas[id=gameCanvas] { image-rendering: optimizeSpeed; image-rendering: pixelated; } +#content { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + pointer-events: none; +} + +canvas[id=musiccanvas] { + position: fixed; + left: 0; + top: 0; + width: 100%; + height: 100%; +} + +audio { + position: fixed; + left: 10px; + bottom: 10px; + width: calc(100% - 20px); +} + #gameName { padding: 0; margin-top: 5px; @@ -67,7 +92,15 @@ canvas { font-size: xx-large; font-weight: bolder; } - +#gameName:active { + padding: 0; + margin-top: 5px; + margin-bottom: 10px; + text-align: center; + font-size: xx-large; + font-weight: bolder; + animation:pfpDefault 800ms linear both; +} h2 { font-size: small; color: #000000; @@ -76,19 +109,31 @@ h2 { } options_header { - padding: 0; - padding-bottom: 5px; - margin: 0; - font-size: small; + display: block; + margin: 5px 0 4px; + font: bold 13px/1 Ubuntu; + color: #000000; + text-align: center; +} + +miniupdate { + font-size: medium; color: #000000; font-weight: bold; text-align: center; + font-size: 16px; + animation:pfpDefault 800ms linear both; } h3 { font-size: small; color: #484848; text-align: center; + animation:pfpDefault 800ms linear both; +} + +h3:hover { + animation:pfpDefault 800ms linear both; } h4 { @@ -133,30 +178,53 @@ input { border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px; - margin-top: 5px; - margin-bottom: 5px; + margin-top: 10px; + margin-bottom: -10px; outline: none; } input.checkbox { - width: 13px; - height: 13px; + width: 15px; + height: 15px; padding: 0; margin: 0; vertical-align: bottom; position: relative; - top: -2px; + top: -1px; overflow: hidden; + font-family: Ubuntu; +} +input.checkbox:focus, +input.checkbox.focus { + border: none; + box-shadow: 0 0 0px 0px #DDDDDD; +} + +#optColors { + width: 220px; +} +#optMobile { + display: none; +} +body.mobile #optColors { + width: 346px; + margin-bottom: 4px; + } +body.mobile #optMobile, body.mobile #optBorders { + width: 170px; + margin-bottom: 4px; + display: inline-block; } #playerNameInput { padding: 10px; - font-size: large; + font-size: medium; } #playerKeyInput { padding: 3px; color: gray; + } input:focus, @@ -175,18 +243,25 @@ div { -ms-user-select: none; /* IE10+ */ } +div.optionsHeader { + display: block; + margin: 10px 0 4px; + font: bold 13px/1 Ubuntu; + color: #000000; + text-align: center; +} .serverSelector { - height: 25px; + height: 75px; text-align: center; font-size: 14px; font-weight: bold; - line-height: 13px; + line-height: 14px; padding-left: 10px; overflow-y: scroll; scroll-behavior: smooth; scrollbar-width: thin; - scrollbar-color: rgba(0, 0, 0, 0.3) rgba(0, 0, 0, 0.15); + scrollbar-color: oklch(0% 0 0 / 30%) oklch(0% 0 0 / 15%); } .serverSelector tr { @@ -200,6 +275,15 @@ div { cursor: default; } +.serverSelector tr:hover { + color: #8ABC3F; +} +.serverSelector tr.selected:hover { + color: #1B3353; + cursor: default; +} + + #startMenu { position: relative; margin: auto; @@ -214,6 +298,10 @@ div { box-sizing: border-box; overflow: hidden; } +body.mobile #startMenu { + width: 770px; + bottom: 100px; +} #startMenuHeader { text-align: left; @@ -223,14 +311,122 @@ div { .startMenuHolder { width: 350px; - height: 380px; + height: 365px; padding: 10px; overflow: hidden; display: inline-block; vertical-align: text-top; } +body.mobile .linkHolder { display: none; } +.replace1 { +right: 0; +} +.replace2 { +right: -50; +} +a.menuTab { + float: right; + height: 13px; + font: 13px Ubuntu; + border-radius: 0px 0px 5px 5px; + padding: 6px 10px 7px 10px; + color: #FFFFFF !important; + text-decoration: none; + margin-right: 10px; +} +a.menuTab.discordbutton { + padding: 6px 10px 7px 28px; + border-bottom: 2px solid #6175ba; + box-shadow: inset 0 -2px #6175ba; + -webkit-box-shadow: inset 0 -2px #6175ba; + animation:pfpDefault 800ms linear both; + background: #7289DA url("https://cloud-cube.s3.amazonaws.com/m660o440l0wv/public/svg0.svg") 4px 3px/21px no-repeat; +} +a.menuTab.discordbutton:active, +a.menuTab.discordbutton:hover { + outline: none; + -webkit-box-shadow: none; + box-shadow: none; +} +a.menuTab.catto { + background: #FF0000 url("https://cloud-cube.s3.amazonaws.com/m660o440l0wv/public/coder.png") 8px 6px no-repeat; + padding: 6px 10px 7px 28px; + border-bottom: 2px solid #c91a1a; + box-shadow: inset 0 -2px #c91a1a; + -webkit-box-shadow: inset 0 -2px #c91a1a; + animation:pfpDefault 800ms linear both; +} +a.menuTab.catto:active, +a.menuTab.catto:hover { + outline: none; + -webkit-box-shadow: none; + box-shadow: none; +} + +a.menuTab.ach { + background: #2bab2f url("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Trophy.png?v=1708025693434") 3px 2px/23px no-repeat; + padding: 6px 10px 7px 28px; + border-bottom: 2px solid #2a802d; + box-shadow: inset 0 -2px #2a802d; + -webkit-box-shadow: inset 0 -2px #2a802d; + animation:pfpDefault 800ms linear both; +} +a.menuTab.ach:active, +a.menuTab.ach:hover { + top: 1px; + outline: none; + -webkit-box-shadow: none; + box-shadow: none; +} + +a.menuTab.skin { + background: #9900FF url("https://cdn.glitch.global/9b9522e6-a4f4-4511-8978-4c190b6759bd/stick.png?v=1708440293253") 3px 2px/23px no-repeat; + padding: 6px 10px 7px 28px; + border-bottom: 2px solid #7b11c2; + box-shadow: inset 0 -2px #7b11c2; + -webkit-box-shadow: inset 0 -2px #7b11c2; + animation:pfpDefault 800ms linear both; +} +a.menuTab.skin:active, +a.menuTab.skin:hover { + top: 1px; + outline: none; + -webkit-box-shadow: none; + box-shadow: none; +} + +a.menuTab.stat { + background: #1E8449 url("https://cloud-cube.s3.amazonaws.com/m660o440l0wv/public/play.png") 3px 2px/23px no-repeat; + padding: 6px 10px 7px 28px; + border-bottom: 2px solid #156637; + box-shadow: inset 0 -2px #156637; + -webkit-box-shadow: inset 0 -2px #156637; + animation:pfpDefault 800ms linear both; +} +a.menuTab.stat:active, +a.menuTab.stat:hover { + top: 1px; + outline: none; + -webkit-box-shadow: none; + box-shadow: none; +} +a.menuTab.??? { + background: #FFFFFF url("https://cdn.glitch.global/f80d3eec-1e99-4b8c-b120-79a55addacf9/2022_06_23_11e_Kleki.png?v=1675997243695") 3px 2px/23px no-repeat; + padding: 6px 10px 7px 28px; + animation:pfpDefault 800ms linear both; +} +a.menuTab:link:hover, a.menuTab:visited:hover { + text-decoration: underline; + animation:pfpHoverOn 800ms linear both; +} .sliderHolder { + width: 350px; + height: 323px; + overflow: hidden; +} + +.sliderHolder2 { width: 350px; height: 325px; overflow: hidden; @@ -248,33 +444,136 @@ td { table { width: 100%; + color: black; } .slider { position: relative; top: 0px; width: 100%; + opacity: 1; -webkit-transition: top 500ms; -moz-transition: top 500ms; -o-transition: top 500ms; - transition: top 500ms; + transition: top 500ms, opacity 500ms; + animation:pfpDefault 800ms linear both; + transition-timing-function: cubic-bezier(0.175, 0.585, 0.32, 1.2) +} + +.slider2 { + position: relative; + right: 0px; + width: 100%; + z-index: 0; + display: inline-block; + -webkit-transition: right 1000ms; + -moz-transition: right 1000ms; + -o-transition: right 1000ms; + transition: right 1000ms; + animation:pfpDefault 800ms linear both; + transition-timing-function: cubic-bezier(0.175, 0.585, 0.32, 1) +} +.slider3 { + position: absolute; + z-index: -6; + right: 400px; + width: 100%; + display: inline-block; + -webkit-transition: right 1000ms; + -moz-transition: right 1000ms; + -o-transition: right 1000ms; + transition: right 1000ms; + animation:pfpDefault 800ms linear both; + transition-timing-function: cubic-bezier(0.175, 0.585, 0.32, 1) } +.slided .slider { + top: -290px; +} #startMenuSlidingContent { height: 305px; } +body.mobile .desktopControlTab { + display: none; +} +.mobileOptions { + display: none; +} +body.mobile .mobileOptions { + display: block; +} +.mobileOptionsHeader { + display: none; +} +body.mobile .mobileOptionsHeader { + display: block; + margin: 10px 0 4px; + font: bold 13px/1 Ubuntu; + color: #000000; + text-align: center; +} + +.slidingtrigger3 { + position: relative; + top: 0px; + width: 100%; + -webkit-transition: top 500ms; + -moz-transition: top 500ms; + -o-transition: top 500ms; + transition: top 500ms; +} + +#startMenuSlidingContent { + height: 300px; +} #startMenuSlidingTrigger { cursor: pointer; height: 15px; + margin-top: -15px; } - #startMenuSlidingTrigger:hover { text-shadow: 0 1px 2px rgba(0, 0, 0, 0.25); } +#startMenuSlidingTrigger:active > h3 { + color: #323232; + animation:pfpDefault 800ms linear both; +} + +#startMenuSlidingTrigger:hover > h3 > i.arrow { + border-color: #323232; +} + +#startMenuSlidingTrigger2 { + cursor: pointer; +} +#startMenuSlidingTrigger2:hover { + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.25); +} +#startMenuSlidingTrigger2:active > h3 { + color: #323232; + animation:pfpDefault 800ms linear both; +} +#startMenuSlidingTrigger2:hover > h3 > i.arrow { + border-color: #323232; +} +#startMenuSlidingTrigger3 { + cursor: pointer; + height: 15px; +} + +#startMenuSlidingTrigger3:hover { + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.25); +} +.menuTabs { + height: 26px; + margin: 0 8px; +} update { color: #D83848; + animation:pfpDefault 800ms linear both; + font-weight: bold; } @@ -282,7 +581,27 @@ update { padding-left: 10px; font-size: x-large; font-weight: bold; - text-align: center; + text-align: justify; +} +.horizontalSelector { + padding: 4px 0; + margin-bottom: 4px; + font: bold 12px Ubuntu; + text-align: center; +} +.horizontalSelector span { + padding: 4px 10px; + color: #343434; + cursor: pointer; +} +.horizontalSelector span:hover { + color: #5f5f5f; +} +.horizontalSelector span.active { + background: #335099; + color: #ffffff; + border-radius: 5px; + cursor: default; } .shrinkable { @@ -290,8 +609,65 @@ update { width: 360px; } -#patchNotes { +.dropdown-check-list { + display: inline-block; +} + +.dropdown-check-list .anchor { + position: relative; + cursor: pointer; + display: inline-block; + padding: 5px 50px 5px 10px; + border: 1px solid #cccccc; +} + +.dropdown-check-list .anchor:after { + position: absolute; + content: ""; + border-left: 2px solid black; + border-top: 2px solid black; + padding: 5px; + right: 10px; + top: 20%; + -moz-transform: rotate(-135deg); + -ms-transform: rotate(-135deg); + -o-transform: rotate(-135deg); + -webkit-transform: rotate(-135deg); + transform: rotate(-135deg); +} + +.dropdown-check-list .anchor:active:after { + right: 8px; + top: 21%; +} + +.dropdown-check-list ul.items { + padding: 2px; + display: none; + margin: 10px 10px 10px 10px; + border: 1px solid #cccccc; + border-top: none; + height: 75px; +} + +.dropdown-check-list ul.items li { + padding: 0; + margin-top: 8px; + position: relative; + top: -7px; +} + +.dropdown-check-list.visible .anchor { + color: #0094ff; +} + +.dropdown-check-list.visible .items { + display: block; +} + +#credits { max-width: 330px; + /*animation:pfpDefault 800ms linear both;*/ height: calc(100% - 100px); padding: 5px 20px 10px; overflow: hidden auto; @@ -299,7 +675,7 @@ update { scrollbar-color: rgba(0, 0, 0, 0.3) rgba(0, 0, 0, 0.15); } -#patchNotes div { +#credits div { > .title { margin: 0; font-size: 1.5em; @@ -317,6 +693,47 @@ update { } position: relative; + /*animation:pfpDefault 800ms linear both;*/ + + &::before { + content: ''; + position: absolute; + bottom: 0; + width: 100%; + height: .1em; + background-color: gray; + } +} + +#patchNotes { + max-width: 330px; + /*animation:pfpDefault 800ms linear both;*/ + height: calc(100% - 100px); + padding: 5px 20px 10px; + overflow: hidden auto; + scrollbar-width: thin; + scrollbar-color: rgba(0, 0, 0, 0.3) rgba(0, 0, 0, 0.15); +} + +#patchNotes div { + > .title { + margin: 0; + font-size: 1.5em; + font-weight: bold; + } + + > date { + color: rgba(0, 0, 0, 0.45); + font-style: italic; + } + + > ul li { + margin-left: 1em; + margin-bottom: .5em; + } + + position: relative; + /*animation:pfpDefault 800ms linear both;*/ &::before { content: ''; @@ -328,6 +745,25 @@ update { } } +select { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + font: 13px/1 Ubuntu; + padding: 2px 28px 2px 8px; + height: 21px; + margin-left: 3px; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAAICAYAAAD0g6+qAAAAwklEQVQoU42QMQrCQBBFZxeGgJ7BI1jYa2GzTTY3sRUECy1yA0svEQhhEHIHLdRrqF2a5EuCkbgmmin/zLz5f5QxZsTMK2ZeR1F0p5ay1i7zPD+LiLT1S01Za7dEtCGiY5Zl8zRNH81h3/d3SqkFgFOSJJNOUBAEAwAHIpq6sAbkprWexXF86QSVjTaY53nhy8lfSBWtvuDAKhlAL8gHyHUGAFrr8a84zZhvR7VojBkyc1gUxV5Erl0/cfUvUN9Fd+4JA1JkCdbmVf8AAAAASUVORK5CYII=) 100% no-repeat #eee; + border-radius: 4px; + border: 1px solid #ccc; +} +select:hover { + background-color: #ccc; +} +select:active { + background-color: #eee; +} + .shadowScroll { overflow-y: scroll; background: @@ -351,10 +787,12 @@ update { height: 40px; box-sizing: border-box; font-size: larger; + line-height: 0; color: white; + animation:pfpDefault 800ms linear both; text-align: center; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.25); - background: #336699; + background: #335099; /*background: #A9D86D;*/ border: 0; border-bottom: 2px solid #1B3353; @@ -369,14 +807,79 @@ update { -webkit-border-radius: 5px; } +#hideongamestart { + position: relative; + z-index: 3; + } + +#resetachievementsbutton { + font-family: Ubuntu; + line-height: 0; + top: 30px; + width: 100%; + height: 40px; + max-height: 100px; + top: 443px; + z-index: 3; + color: white; + animation:pfpDefault 800ms linear both; + text-align: center; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.25); + background: #70b5ff; + font-family: Ubuntu; + position: relative; + border: 0; + border-bottom: 2px solid #1B3353; + cursor: pointer; + -webkit-box-shadow: inset 0 -2px #1B3353; + box-shadow: inset 0 -2px #1B3353; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + float: left; +} + +.icon { + animation:pfpDefault 800ms linear both; +} + +.icon:hover { + animation:pfpHoverOn 800ms linear both; +} + +.icon:active { + animation:pfpDefault 400ms linear both; +} + #startButton:active, #startButton:hover { top: 1px; - background: #1B3353; + background: #335099; + /*background: #A9D86D;*/ + border: 0; + border-bottom: 3px solid #1B3353; + /*background: #1B3353;*/ /*background: #8ABC3F;*/ + line-height: 25px; + text-align: center; outline: none; -webkit-box-shadow: none; box-shadow: none; + height: 39px; +} + +#resetachievementsbutton:active, +#resetachievementsbutton:hover { + line-height: 25px; + text-align: center; + outline: none; + -webkit-box-shadow: none; + box-shadow: none; + height: 39px; + border: 0; + border-bottom: 3px solid #1B3353; + top: 444px; + } #bottomHolder { @@ -404,108 +907,132 @@ a.link { } .discord { + top: 2px; + animation:pfpDefault 800ms linear both; background: #7289da; + line-height: 15px; border-bottom: 2px solid #6175ba; box-shadow: inset 0 -2px #6175ba; -webkit-box-shadow: inset 0 -2px #6175ba; } .discord:active, .discord:hover { - top: 1px; - background: #6175ba; - outline: none; - -webkit-box-shadow: none; - box-shadow: none; -} - -.revolt { - background: #fd6671; - border-bottom: 2px solid #ed4245; - box-shadow: inset 0 -2px #ed4245; - -webkit-box-shadow: inset 0 -2px #ed4245; -} -.revolt:active, -.revolt:hover { - top: 1px; - background: #ed4245; + top: 3px; + background: #7289da; outline: none; - -webkit-box-shadow: none; - box-shadow: none; + height: 85%; + line-height: 15px; + border-bottom: 1px solid #6175ba; + box-shadow: inset 0 -2px #6175ba; + -webkit-box-shadow: inset 0 -2px #6175ba; } .reddit { + top: 2px; + animation:pfpDefault 800ms linear both; background: #f75401; + line-height: 15px; border-bottom: 2px solid #d24a01; box-shadow: inset 0 -2px #d24a01; -webkit-box-shadow: inset 0 -2px #d24a01; } + .reddit:active, .reddit:hover { - top: 1px; - background: #d24a01; + top: 3px; + background: #f75401; outline: none; - -webkit-box-shadow: none; - box-shadow: none; + height: 85%; + line-height: 15px; + border-bottom: 1px solid #d24a01; + box-shadow: inset 0 -2px #d24a01; + -webkit-box-shadow: inset 0 -2px #d24a01; } .original { + top: 2px; + animation:pfpDefault 800ms linear both; background: #77bf79; + line-height: 15px; border-bottom: 2px solid #679c68; box-shadow: inset 0 -2px #679c68; -webkit-box-shadow: inset 0 -2px #679c68; } + .original:active, .original:hover { - top: 1px; - background: #679c68; + top: 3px; + background: #77bf79; outline: none; - -webkit-box-shadow: none; - box-shadow: none; + height: 85%; + line-height: 15px; + border-bottom: 1px solid #679c68; + box-shadow: inset 0 -2px #679c68; + -webkit-box-shadow: inset 0 -2px #679c68; } .developer { + top: 2px; + animation:pfpDefault 800ms linear both; background: #454b7f; + line-height: 15px; border-bottom: 2px solid #313454; box-shadow: inset 0 -2px #313454; -webkit-box-shadow: inset 0 -2px #313454; } .developer:active, .developer:hover { - top: 1px; - background: #313454; + top: 3px; + background: #454b7f; outline: none; - -webkit-box-shadow: none; - box-shadow: none; + height: 85%; + line-height: 15px; + border-bottom: 1px solid #313454; + box-shadow: inset 0 -2px #313454; + -webkit-box-shadow: inset 0 -2px #313454; } .youtube { + top: 2px; + animation:pfpDefault 800ms linear both; background: #f71701; + line-height: 15px; border-bottom: 2px solid #d21401; box-shadow: inset 0 -2px #d21401; -webkit-box-shadow: inset 0 -2px #d21401; } + .youtube:active, .youtube:hover { - top: 1px; - background: #d21401; + top: 3px; + background: #f71701; outline: none; - -webkit-box-shadow: none; - box-shadow: none; + height: 85%; + line-height: 15px; + border-bottom: 1px solid #d21401; + box-shadow: inset 0 -2px #d21401; + -webkit-box-shadow: inset 0 -2px #d21401; } .github { + top: 2px; + animation:pfpDefault 800ms linear both; background: #666666; + line-height: 15px; border-bottom: 2px solid #333333; - -webkit-box-shadow: inset 0 -2px #333333; box-shadow: inset 0 -2px #333333; + -webkit-box-shadow: inset 0 -2px #333333; } .github:active, .github:hover { - top: 1px; - background: #333333; + top: 3px; + background: #666666; outline: none; - -webkit-box-shadow: none; - box-shadow: none; + height: 85%; + line-height: 15px; + border-bottom: 1px solid #333333; + box-shadow: inset 0 -2px #333333; + -webkit-box-shadow: inset 0 -2px #333333; } #startMenuWrapper { @@ -515,6 +1042,7 @@ a.link { -o-transition: max-height 1s; transition: max-height 1s; overflow: hidden; + animation: fadezoomin 300ms f; } .nopadding { @@ -565,6 +1093,17 @@ a.link { color: black; background-color: #ffffff88; } +p.vsaucereference { + animation:pfpHoverOn 400ms linear both; + font-size: 13px; +} +p.vsaucereference:hover { + animation:pfpHoverOn 400ms linear both; +} + +p.vsaucereference:active { + animation: pfpDefault 800ms linear both; +} input [type="image"]:focus { border: none; @@ -575,4 +1114,1036 @@ input [type="image"]:focus { *:focus { outline: 1px solid transparent; border-style: none; +} +.popup { + position: absolute; + display: block; + width: auto; + max-width: 42%; + height: auto; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + z-index: 3; + border-radius: 10px; + background: var(--backgroundColor); + padding: 10px; + font-size: larger; + text-align: center; + border-style: solid; + border-color: #c1cfd8; + color: var(--menuTextColor); +} + +.popup button { + margin: 15px; + padding: 10px 50px 10px 50px; + width: auto; + box-sizing: border-box; + color: white; + text-align: center; + text-shadow: 0 0 3px rgba(0, 0, 0, 0.2), 0 1px 2px rgba(0, 0, 0, 0.2); + background: #A9D86D; + border: 0; + border-bottom: 2px solid #8ABC3F; + cursor: pointer; + box-shadow: inset 0 -2px #8ABC3F; + border-radius: 5px; + font: 18px Ubuntu; +} + +.popup button:hover { + border-bottom: 1px solid #8ABC3F; +} + +.popup button:active { + background: #FFFFFF; + border-bottom: 0; + outline: none; + box-shadow: none; +} + +.popup span.small { + font-size: xx-large; + font-weight: bold; + color: black; + white-space: pre-line; +} + +.popup span { + font-size: x-large; + white-space: pre-line; + font-weight: light; + color: black; +} +.achievementsHolder { + position: absolute; + display: block; + width: 700px; + height: 550px; + padding-top: 50px; + top: 47.5%; + left: 50%; + transform: translate(-50%, -50%); + z-index: 3; + background: var(--backgroundColor); + padding: 10px; + font-size: larger; + text-align: center; + border-style: solid; + border-color: #c1cfd8; + color: black; + display: none; +} + +.achievementsHolder span.small { + font-size: xx-large; + font-weight: bold; + color: black; + animation:pfpDefault 800ms linear both; +} + +.achievementsHolder span { + font-size: x-large; + font-weight: lighter; + color: black; + animation:pfpDefault 800ms linear both; +} +body.mobile .achievementsHolder { + top: 50%; + width: calc(100% - 30px); + height: calc(100% - 25px); +} + +#achievementsClose { + height: 45px; + width: 50px; + float: right; + position: relative; + opacity: .8; + background-image: url('data:image/svg+xml,%3Csvg xmlns%3D"http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" fill%3D"%23DD0000" viewBox%3D"0 0 16 16" width%3D"30" height%3D"30"%3E%3Cpath d%3D"M3 0 0 3 6 8 0 13 3 16 8 10 13 16 16 13 10 8 16 3 13 0 8 6 3 0Z"%3E%3C%2Fpath%3E%3C%2Fsvg%3E'); + background-repeat: no-repeat; + background-position: center; +} + +#achievementsClose:hover { + cursor: pointer; + opacity: 1; +} + +#achievementsDisplay { + height: 450px; + margin-top: -20px; + position: absolute; + animation:pfpDefault 800ms linear both; + width: 96.5%; + border-style: solid; + border-color: #c1cfd8; + background-color: rgba(0, 0, 0, 0.2); + background: url("https://cdn.glitch.global/ded4b664-3b74-4a3b-9282-9796baafc60b/41R6Ok5aeKL.jpg?v=1713446403687") 0px -550px/100% repeat; +} +body.mobile #achievementsDisplay { + width: calc(100% - 25px); + height: calc(100% - 78px); +} + +.achievementsItem { + margin: 16px 16px 12px 16px; + border-radius: 14px; + animation:pfpDefault 800ms linear both; + padding: 6px; + +} + +.achievementsItem h1 { + font-size: 22px; + animation:pfpDefault 800ms linear both; + font-weight: bold; + color: #22160b; +} + +.achievementsItem span { + font-size: 17px; + font-weight: bold; + animation:pfpDefault 800ms linear both; + color: #22160b; +} + +.greenachievement { + background-color: rgb(138, 187, 68); +} + +.greyachievement { + background-color: rgb(159, 159, 159); +} + +.bleenachievement { + background-color: rgb(125, 195, 235); +} + +.grueachievement { + background-color: rgb(160, 170, 180); +} + +#achievementsStatsTable td { + animation:pfpDefault 800ms linear both; + font-size: 18px; +} + +#achievementsStatsTable tr b { + animation:pfpDefault 800ms linear both; + font-size: 22px; +} +.autoBorder { + display: block; + border: 3.5px solid rgba(0, 0, 0, 0.35); +} +.metasip { + height: 10px; + width: 10px; + background-image: "https://cloud-cube.s3.amazonaws.com/m660o440l0wv/public/svg0.svg" +} +#wikiTankThing { + display: none; + position: absolute; + top: 58.5vh; + left: 40%; + z-index: 5; + width: 20%; +} +.skinHolder { + position: absolute; + display: block; + width: 650px; + height: 600px; + top: 47.5%; + left: 50%; + transform: translate(-50%, -50%); + z-index: 3; + background: var(--backgroundColor); + padding: 10px; + font-size: larger; + text-align: center; + border-style: solid; + border-color: #c1cfd8; + color: black; + display: none; +} + +.skinHolder span.small { + font-size: xx-large; + font-weight: bold; + color: black; + animation:pfpDefault 800ms linear both; +} + +.skinHolder span { + font-size: x-large; + font-weight: light; + color: black; + animation:pfpDefault 800ms linear both; +} + +#skinClose { + height: 45px; + width: 50px; + float: right; + position: relative; + opacity: .8; + background-image: url('data:image/svg+xml,%3Csvg xmlns%3D"http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg" fill%3D"%23DD0000" viewBox%3D"0 0 16 16" width%3D"30" height%3D"30"%3E%3Cpath d%3D"M3 0 0 3 6 8 0 13 3 16 8 10 13 16 16 13 10 8 16 3 13 0 8 6 3 0Z"%3E%3C%2Fpath%3E%3C%2Fsvg%3E'); + background-repeat: no-repeat; + background-position: center; +} + +#skinClose:hover { + cursor: pointer; + opacity: 1; +} + +#skinDisplay { + height: 448px; + margin-top: -20px; + position: absolute; + animation:pfpDefault 800ms linear both; + width: 96.5%; + border-style: solid; + border-color: #c1cfd8; + background-color: rgba(0, 0, 0, 0.2); +} + +body.mobile .skinHolder { + top: 50%; + width: calc(100% - 30px); + height: calc(100% - 25px); +} +body.mobile #skinDisplay { + width: calc(100% - 25px); + height: calc(100% - 78px); +} + +.skinItem { + margin: 16px 16px 12px 16px; + border-radius: 14px; + animation:pfpDefault 800ms linear both; + padding: 6px; + +} + +.skinItem h1 { + font-size: 22px; + animation:pfpDefault 800ms linear both; + font-weight: light; + color: #22160b; +} + +.skinItem span { + font-size: 17px; + font-weight: bold; + animation:pfpDefault 800ms linear both; + color: #22160b; +} + +#leftarrowbutton { + position: relative; + float: left; + height: 20%; + width: 20%; +} +#rightarrowbutton { + position: relative; + float: right; + height: 20%; + width: 20%; +} +#leftarrowbutton:active { + animation:pfpDefault 800ms linear both; +} +#rightarrowbutton:active { + animation:pfpDefault 800ms linear both; +} +.displaytest { + top: 0; + position: relative; + text-align: center; + margin-left: auto; + margin-right: auto; + margin-top: auto; +} +.displayskinname { + top: -2%; + position: relative; +} +#skinpdiv { + top: -3%; + position: relative; + margin-left: auto; + margin-right: auto; + width: 50%; +} +body.mobile #skinpdiv { + width: 25%; +} +#skinpreview { + vertical-align: bottom; + width: 100%; + height: 100%; + z-index: 3; + +} +#selectskin { + vertical-align: bottom; + float: center; + margin-left: auto; + margin-right: auto; + height: 130px; + width: 260px; + z-index: 3; +} +#lockedskin { + display: none; + width: 100%; + height: 100%; + top: 0; + left: 0; + position: absolute; + z-index: 3; +} +#lockbg { + display: inline-block; + width: 100%; + height: 100%; + top: 0; + left: 0; + position: absolute; + opacity: 0.4; + z-index: -5; +} +#eventtitle { + position: absolute; + float: center; + top: 600px; + width: 70%; + left: 15%; + color: white; + outline: #000000 solid; + z-index: 0; + text-align: center; + cursor: pointer; + text-shadow: -1px -1px 0 #000000, 1px -1px 0 #000000, -1px 1px 0 #000000, 1px 1px 0 #000000; + background: #202020 url("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2024_04_22_0fb_Kleki.png?v=1713786234204") 0px 0px/100px repeat; +} +#controls { + height: 200px; +} +.animpop { + animation:pfpDefault 800ms linear both; +} +.animinvert { + animation:invertation 2s linear both; + -webkit-animation-timing-function: linear; + animation-timing-function: linear; +} +.incog:active { + animation:wack2 2s linear 3; + -webkit-animation-timing-function: linear; + animation-timing-function: linear +} +.popuptaskbar { + display: block; + position: relative; + height: 50px; + width: 102.8%; + left: -10px; + top: -32px; + background: #2bab2f url("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Trophy.png?v=1708025693434") 0px 0px/50px no-repeat; +} +#achievementsHeader { + padding: 5px; + text-align: left; + margin-left: 50px; + color: #FFFFFF +} +.popuptaskbar2 { + display: block; + position: relative; + height: 50px; + width: 102.8%; + left: -10px; + top: -32px; + background: #9900FF url("https://cdn.glitch.global/9b9522e6-a4f4-4511-8978-4c190b6759bd/stick.png?v=1708440293253") 0px 0px/50px no-repeat; +} +#skinHeader { + padding: 5px; + text-align: left; + margin-left: 50px; + color: #FFFFFF +} +.atthebottom { + position: relative; + top: 425px; +} +body.mobile .atthebottom { + top: 60%; +} +#yes { + opacity: 0; + position: absolute; +} + +@keyframes pfpHoverOn { + 0% { transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 3.4% { transform: matrix3d(1.032, 0, 0, 0, 0, 1.041, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 4.7% { transform: matrix3d(1.045, 0, 0, 0, 0, 1.06, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 6.81% { transform: matrix3d(1.066, 0, 0, 0, 0, 1.089, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 9.41% { transform: matrix3d(1.088, 0, 0, 0, 0, 1.117, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 10.21% { transform: matrix3d(1.094, 0, 0, 0, 0, 1.123, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 13.61% { transform: matrix3d(1.112, 0, 0, 0, 0, 1.133, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 14.11% { transform: matrix3d(1.114, 0, 0, 0, 0, 1.133, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 17.52% { transform: matrix3d(1.121, 0, 0, 0, 0, 1.124, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 18.72% { transform: matrix3d(1.121, 0, 0, 0, 0, 1.119, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 21.32% { transform: matrix3d(1.12, 0, 0, 0, 0, 1.107, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 24.32% { transform: matrix3d(1.115, 0, 0, 0, 0, 1.096, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 25.23% { transform: matrix3d(1.113, 0, 0, 0, 0, 1.094, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 29.03% { transform: matrix3d(1.106, 0, 0, 0, 0, 1.09, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 29.93% { transform: matrix3d(1.105, 0, 0, 0, 0, 1.09, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 35.54% { transform: matrix3d(1.098, 0, 0, 0, 0, 1.096, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 36.74% { transform: matrix3d(1.097, 0, 0, 0, 0, 1.098, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 41.04% { transform: matrix3d(1.096, 0, 0, 0, 0, 1.102, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 44.44% { transform: matrix3d(1.097, 0, 0, 0, 0, 1.103, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 52.15% { transform: matrix3d(1.099, 0, 0, 0, 0, 1.101, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 59.86% { transform: matrix3d(1.101, 0, 0, 0, 0, 1.099, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 63.26% { transform: matrix3d(1.101, 0, 0, 0, 0, 1.099, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 75.28% { transform: matrix3d(1.1, 0, 0, 0, 0, 1.1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 85.49% { transform: matrix3d(1.1, 0, 0, 0, 0, 1.1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 90.69% { transform: matrix3d(1.1, 0, 0, 0, 0, 1.1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 100% { transform: matrix3d(1.1, 0, 0, 0, 0, 1.1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } +} + +@keyframes pfpDefault { + 0% { transform: matrix3d(1.1, 0, 0, 0, 0, 1.1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 3.4% { transform: matrix3d(1.068, 0, 0, 0, 0, 1.059, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 4.7% { transform: matrix3d(1.055, 0, 0, 0, 0, 1.04, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 6.81% { transform: matrix3d(1.034, 0, 0, 0, 0, 1.011, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 9.41% { transform: matrix3d(1.012, 0, 0, 0, 0, 0.983, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 10.21% { transform: matrix3d(1.006, 0, 0, 0, 0, 0.977, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 13.61% { transform: matrix3d(0.988, 0, 0, 0, 0, 0.967, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 14.11% { transform: matrix3d(0.986, 0, 0, 0, 0, 0.967, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 17.52% { transform: matrix3d(0.979, 0, 0, 0, 0, 0.976, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 18.72% { transform: matrix3d(0.979, 0, 0, 0, 0, 0.981, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 21.32% { transform: matrix3d(0.98, 0, 0, 0, 0, 0.993, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 24.32% { transform: matrix3d(0.985, 0, 0, 0, 0, 1.004, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 25.23% { transform: matrix3d(0.987, 0, 0, 0, 0, 1.006, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 29.03% { transform: matrix3d(0.994, 0, 0, 0, 0, 1.01, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 29.93% { transform: matrix3d(0.995, 0, 0, 0, 0, 1.01, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 35.54% { transform: matrix3d(1.002, 0, 0, 0, 0, 1.004, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 36.74% { transform: matrix3d(1.003, 0, 0, 0, 0, 1.002, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 41.04% { transform: matrix3d(1.004, 0, 0, 0, 0, 0.998, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 44.44% { transform: matrix3d(1.003, 0, 0, 0, 0, 0.997, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 52.15% { transform: matrix3d(1.001, 0, 0, 0, 0, 0.999, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 59.86% { transform: matrix3d(0.999, 0, 0, 0, 0, 1.001, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 63.26% { transform: matrix3d(0.999, 0, 0, 0, 0, 1.001, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 75.28% { transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 85.49% { transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 90.69% { transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 100% { transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } +} +@keyframes invertation { + 0% { + background-color: black; + color: white; + } + + 50% { + background-color: white; + -webkit-filter: invert(1); + filter: invert(1); + } +} +@keyframes wack { + 25% { + transform: scale(1, 5); + } + 75% { + transform: scale(5, 1) + } +} +@keyframes wack2 { + 20% { + transform: scale(100, 5); + } + 40% { + transform: scale(2, 10) + } + 60% { + transform: scale(0.2, 15); + } + 80% { + transform: scale(-10, 6) + } + 100% { + transform: scale(-3, -1) + } +} +@keyframes flashing { + 0% { + background-color: black; + color: white; + -webkit-filter: invert(0); + filter: invert(0); + } + 5% { + background-color: black; + -webkit-filter: invert(1); + filter: invert(1); + } + 10% { + background-color: red; + color: white; + -webkit-filter: invert(0); + filter: invert(0); + } + 15% { + background-color: red; + -webkit-filter: invert(1); + filter: invert(1); + } + 20% { + background-color: black; + color: white; + -webkit-filter: invert(0); + filter: invert(0); + } + 25% { + background-color: black; + -webkit-filter: invert(1); + filter: invert(1); + } + 30% { + background-color: white; + color: white; + -webkit-filter: invert(0); + filter: invert(0); + } + 35% { + background-color: white; + -webkit-filter: invert(1); + filter: invert(1); + } + 40% { + background-color: red; + color: white; + -webkit-filter: invert(0); + filter: invert(0); + + } + 45% { + background-color: black; + } + 50% { + background-color: orange; + color: white; + } + 55% { + background-color: white; + } + 60% { + background-color: yellow; + } + 65% { + background-color: black; + } + 70% { + background-color: green; + } + + 75% { + background-color: white; + } + 80% { + background-color: blue; + } + 85% { + background-color: black; + } + 90% { + background-color: purple; + } + 95% { + background-color: white; + } +} +@keyframes pop { + 0% { + transform: scale(1, 1); + } + 5% { + transform: scale(0.9, 0.9); + } + 10% { + transform: scale(0.8, 0.8); + } + 15% { + transform: scale(0.7, 0.7); + } + 20% { + transform: scale(0.6, 0.6); + } + 25% { + transform: scale(0.5, 0.5); + } + 30% { + transform: scale(0.4, 0.4); + } + 35% { + transform: scale(0.3, 0.3); + } + 40% { + transform: scale(0.2, 0.2); + } + 45% { + transform: scale(0.1, 0.1); + } + 50% { + transform: scale(0, 0); + } + 55% { + transform: scale(0.1, 0.1); + } + 60% { + transform: scale(0.2, 0.2); + } + 65% { + transform: scale(0.3, 0.3); + } + 70% { + transform: scale(0.4, 0.4); + } + 75% { + transform: scale(0.5, 0.5); + } + 80% { + transform: scale(0.6, 0.6); + } + 85% { + transform: scale(0.7, 0.7); + } + 90% { + transform: scale(0.8, 0.8); + } + 95% { + transform: scale(0.9, 0.9); + } +} +@keyframes movedown { + 0% { + padding: 6px 10px 7px 28px; + } + 100% { + padding: 6px 10px 70px 28px; + } +} +@keyframes moveup { + 0% { + transform: translatey(100px); + } + 100% { + transform: translatey(0px); + } +} +@keyFrames fadezoomin { + 0% { + opacity: 0; + transform: translateY(0px) scale(1.1); + } + 100% { + opacity: 1; + transform: translateY(0px) scale(1); + } +} +@keyFrames fadezoomout { + 0% { + opacity: 1; + transform: translateY(0px) scale(1); + } + 100% { + opacity: 0; + transform: translateY(0px) scale(1.1); + } +} + +#startMenu[closing] { + display: block; + pointer-events: none; + inset: 0; + animation: fade-out 300ms forwards; +} +#optMobile { + display: none; +} +body.mobile #optColors { + width: 346px; + margin-bottom: 4px; + } +body.mobile #optMobile, body.mobile #optBorders { + width: 170px; + margin-bottom: 4px; + display: inline-block; +} +.greyText { + opacity: 0.5; +} +.container { + position: relative; + padding-left: 20px; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.container input { + position: absolute; + visibility: hidden; + width: 0; + height: 0; + cursor: pointer; +} +.checkmark { + position: absolute; + top: 0; + left: 0; + height: 14px; + width: 14px; + border-radius: 4px; + background-color: #eee; + border: 1px solid #ccc; +} +.radio { + position: absolute; + top: 0; + left: 0; + height: 14px; + width: 14px; + border-radius: 50%; + background-color: #eee; + border: 1px solid #ccc; +} +.container:hover input ~ .checkmark, .container:hover input ~ .radio { + background-color: #ccc; +} +.container input:disabled ~ .checkmark, .container input:disabled ~ .radio { + background-color: #ddd; +} +.container input:checked ~ .checkmark, .container input:checked ~ .radio { + background-color: #0074DA; + border: 1px solid #0074DA; +} +.container:hover input:checked ~ .checkmark, .container:hover input:checked ~ .radio { + background-color: #004894; + border: 1px solid #004894; +} +.container input:disabled:checked ~ .checkmark, .container input:disabled:checked ~ .radio { + background-color: #002C5B; + border: 1px solid #002C5B; +} +.container .checkmark:after { + content: ''; + position: absolute; + display: none; + left: 4px; + top: 1px; + width: 4px; + height: 8px; + border: solid white; + border-width: 0 2px 2px 0; + transform: rotate(45deg); +} +.container .radio:after { + content: ''; + display: none; + margin: 4px; + width: 6px; + height: 6px; + border-radius: 50%; + background: #fff; +} +.container input:checked ~ .checkmark:after, .container input:checked ~ .radio:after { + display: block; +} +.resetControls { + opacity: 0; + transform: rotate(0deg); + transition: opacity 1000ms, margin 1000ms; + margin: 0 -6px; +} +.resetControls.spin { + transition: transform 500ms, opacity 1000ms 150ms, margin 1000ms 150ms; + transform: rotate(360deg); +} +.resetControls.active { + opacity: 1; + margin: 0 5px; + cursor: pointer; +} +td b { + display: inline-block; + cursor: pointer; + text-align: right; + vertical-align: bottom; +} +td b:hover { + color: #777; +} +td.editing b { + background: #fff; + color: #333; + border: 1px solid #dcdcdc; + border-radius: 4px; + padding: 1px 4px; + margin: -2px -7px -2px -3px; + text-align: center; + cursor: text; + -webkit-user-select: auto; + -moz-user-select: auto; + -ms-user-select: auto; + user-select: auto; +} +td.editing span { + visibility: hidden; +} +td b { + display: inline-block; + width: 12px; + height: 17px; + cursor: pointer; + text-align: right; + vertical-align: bottom; +} + +.tdLeft { + width: 25%; +} +.tdCenter { + width: 350px; +} + +*:focus { + outline: 1px solid transparent; + border-style: none; +} +i { + transition: transform 500ms; +} +i.arrow { + border: solid #484848; + border-width: 0 2px 2px 0; + display: inline-block; + padding: 3px; +} +i.reset { + display: inline-block; + width: 8px; + height: 8px; + border: #000000 2px solid; + border-right-color: transparent; + border-radius: 50%; + position: relative; + top: 3px; +} +i.reset::after { + content: ''; + display: inline-block; + border: 3px solid; + border-color: transparent #000000 #000000 transparent; + position: relative; + left: 3px; + bottom: 8px; +} +i.cross { + display: inline-block; + width: 2px; + height: 2px; + margin: 0 5px -3px; + padding: 6px; +} +i.cross.x { + transform: rotate(135deg); +} +i.cross::before, i.cross::after { + content: ''; + display: inline-block; + background-color: #000000; + border-radius: 2px; + float: left; +} +i.cross::before { + width: 12px; + height: 2px; + margin-left: -5px; +} +i.cross::after { + width: 2px; + height: 12px; + margin-top: -7px; +} +i.flag { + display: inline-block; + width: 2px; + height: 12px; + background: #000000; + margin: 0 15px 0 5px; +} +i.flag::before { + content: ''; + display: inline-block; + width: 9px; + height: 7px; + background-color: #000000; + margin: 0 0 5px 3px; + transition: margin-bottom 500ms; +} +i.flag.down::before { + margin-bottom: 2px; +} +.resetControls { + opacity: 0; + transform: rotate(0deg); + transition: opacity 1000ms, margin 1000ms; + margin: 0 -6px; +} +.resetControls.spin { + transition: transform 500ms, opacity 1000ms 150ms, margin 1000ms 150ms; + transform: rotate(360deg); +} +.resetControls.active { + opacity: 1; + margin: 0 5px; + cursor: pointer; +} +body.mobile .controlTable { + display: none; +} +.moreControls { + cursor: pointer; +} +.controlTable { + border-collapse: collapse; + margin: 0 2px; +} +.controlTable tr { + border: 0; + transition: opacity 500ms; +} +.controlTable tr.hidden { + opacity: 0; + pointer-events: none; +} +.controlTable td { + transition: padding 500ms; + width: 0%; +} + +.controlTable div { + position: relative; + top: 0px; + height: 18px; + transition: height 500ms, top 500ms; +} +.controlTable tr.hidden td { + padding: 0 1px; +} +.controlTable tr.hidden div { + top: -20px; + height: 0; +} +.controlTable td b { + display: inline-block; + width: 12px; + height: 16px; + cursor: pointer; + text-align: right; + vertical-align: bottom; +} +.controlTable td b:hover { + color: #777; +} +.controlTable td.editing b { + background: #fff; + color: #333; + border: 1px solid #dcdcdc; + border-radius: 4px; + padding: 1px 4px; + margin: -2px -7px -2px -3px; + text-align: center; + cursor: text; + -webkit-user-select: auto; + -moz-user-select: auto; + -ms-user-select: auto; + user-select: auto; +} +.controlTable td.editing span { + visibility: hidden; +} +.asdfasfsfaf { + width: 40%; } \ No newline at end of file diff --git a/public/osa_background_tile.png b/public/osa_background_tile.png deleted file mode 100644 index 1266bc53d..000000000 Binary files a/public/osa_background_tile.png and /dev/null differ diff --git a/public/round.png b/public/round.png deleted file mode 100644 index b26c469a0..000000000 Binary files a/public/round.png and /dev/null differ diff --git a/run.bat b/run.bat index d43f21b4d..bf09668f0 100644 --- a/run.bat +++ b/run.bat @@ -1,2 +1,2 @@ -"C:\Program Files\nodejs\node.exe" ".\server\index.js" +"C:\Program Files\nodejs\node.exe" --trace-warnings ".\server\index.js" pause \ No newline at end of file diff --git a/runLoop.bat b/runLoop.bat new file mode 100644 index 000000000..42689d54c --- /dev/null +++ b/runLoop.bat @@ -0,0 +1,4 @@ +:loop +"C:\Program Files\nodejs\node.exe" --trace-warnings ".\server\index.js" +timeout /T 5 +goto loop \ No newline at end of file diff --git a/server/config.js b/server/config.js index 893ebd919..08bb738d2 100644 --- a/server/config.js +++ b/server/config.js @@ -3,11 +3,21 @@ module.exports = { // Game server domain. // If 'localhost:NUMBER', the port must equal the port setting. - host: "localhost:26301", + host: "neroio2.glitch.me", - // Which port to run the web server on. - port: 26301, + // Behind https proxy + https: true, + + // World-wide location + // Leave empty to show host name instead + location: "USA", + // Which port to run the web server on. + port: 3000, + + // name of the server ex. main server, beta server, etc + serverName: "Main", + // How often to update the list of the entities that players can see. // Has effects of when entities are activated. visibleListInterval: 250, @@ -17,25 +27,26 @@ module.exports = { // Flatten entity definition, which gets rid of PARENT attributes and applies the parents' attributes to the entity definition, if they're not set in the entity already. flattenDefintions: false, - + // Log speed loop warnings - LOGS: true, + LOGS: false, + + // If there's only one server + COMBINED: true, // The \modules\setup\gamemodeconfigs\ files to load. // To change specific things about specific gamemodes (such as team count for tdm), edit their config file in \modules\setup\gamemodeconfigs\. - GAME_MODES: ['tdm', 'domination'], + GAME_MODES: ['sandbox'], // The room files to load in the setup/rooms folder. // NOTE: If a /gamemodeconfig/ file "replaces" the value of ROOM_SETUP, it just adds its own ROOM_SETUP's content to this array. // NOTE: Files starting with `map_` are maps. files starting with `overlay_` are overlays that get added on. // NOTE: These prefixes are only for categorisation, a room file would work the same regardless of its prefix. APS++ does nothing based on file name prefixes. - ROOM_SETUP: ['map_apspp_default'], + ROOM_SETUP: ['map_neroio_mazearena2'], // The dimensions of a single tile on the map. - TILE_WIDTH: 400, - TILE_HEIGHT: 400, - - + TILE_WIDTH: 200, //400 + TILE_HEIGHT: 200, //400 // Miscellaneous @@ -45,43 +56,49 @@ module.exports = { // If you don't want your players to color their messages. // They get sanitized after addons interpret them, but before they're added to the chat message dictionary. - SANITIZE_CHAT_MESSAGE_COLORS: true, + SANITIZE_CHAT_MESSAGE_COLORS: false, // If someone tries to get a file that does not exist, send them this instead. DEFAULT_FILE: 'index.html', // Window name of the server terminal. - WINDOW_NAME: 'OSA Game Server Instance', + WINDOW_NAME: 'Nero Game Server Instance', // Allows you to type and run javascript code in the terminal. REPL_WINDOW: false, // Welcome message once a player spawns. - WELCOME_MESSAGE: "You have spawned! Welcome to the game.\n" - +"You will be invulnerable until you move or shoot.\n" - +"Please report any bugs you encounter!", + WELCOME_MESSAGE: "You have spawned! Welcome to the game, Hold N To Level Up.\n" + +"You will be invulnerable until you move or shoot OR ACCIDENTALLY PRESS THE FUCKING SPACE BAR.\n" + +"Please report any bugs you encounter on our discord! :)", + // How long a popup message lasts before fading out in milliseconds. MESSAGE_DISPLAY_TIME: 10_000, - + // How long you have to wait to respawn in seconds. + RESPAWN_TIMEOUT: 3, + // Physics // General multiplier for acceleration and max speeds. - runSpeed: 1.5, + runSpeed: 1.5, //1.5 + + // Where the bullet spawns, where 1 is fully outside the barrel and -1 is fully inside the barrel, and 0 is halfway between. + bulletSpawnOffset: -1, // General damage multiplier everytime damage is dealt. - DAMAGE_CONSTANT: 0.5, + DAMAGE_CONSTANT: 0.5, // 0.5 // General knockback multiplier everytime knockback is applied. - KNOCKBACK_CONSTANT: 1.5, + KNOCKBACK_CONSTANT: 1.5, //1.5 // TODO: Figure out how the math behind this works. GLASS_HEALTH_FACTOR: 2, // How strong the force is that confines entities to the map and portals apply to entities. - ROOM_BOUND_FORCE: 0.01, + ROOM_BOUND_FORCE: 0.01, //0.01 @@ -96,7 +113,7 @@ module.exports = { }, // Default skill caps. - MAX_SKILL: 9, + MAX_SKILL: 9, //9 // Amount of tank tiers. MAX_UPGRADE_TIER: 9, @@ -115,40 +132,52 @@ module.exports = { // How much XP player-bots get per second until they reach LEVEL_CAP. BOT_XP: 125, - + // How much XP player-bots will receive when first created. - BOT_START_XP: 0, + BOT_START_XP: 26302, // The chances of a player-bot upgrading a specific skill when skill upgrades are available. BOT_SKILL_UPGRADE_CHANCES: [ 1, 1, 3, 4, 4, 4, 4, 2, 1, 1], // The chances of a player-bot upgrading a specific amount of times before it stops upgrading. BOT_CLASS_UPGRADE_CHANCES: [ 1, 5, 20, 37, 37], - + // The prefix of the bot's name. BOT_NAME_PREFIX: "[AI] ", // The class that players and player-bots spawn as. SPAWN_CLASS: "basic", + // How every entity regenerates their health. + REGENERATE_TICK: 300, + // How many members a team can have in comparison to an unweighed team. + // Example: Lets say we have team A and B. If the weigh of A is 2 and B is 1, then the game will try to give A twice as many members as B. + TEAM_WEIGHTS: {}, - // Natural Spawns - FOOD_CAP: 3, // Max normal food per normal tile. - FOOD_SPAWN_CHANCE: 0.875, // Likeliness of normal food spawn attempts succeeding. - FOOD_SPAWN_COOLDOWN: 30, // Cooldown (in game ticks) of food spawn attempts being made. + // Natural Spawns - FOOD_CAP_NEST: 3, // Max nest food per nest tile. - FOOD_SPAWN_CHANCE_NEST: 0.25, // Likeliness of nest food spawn attempts succeeding. - FOOD_SPAWN_COOLDOWN_NEST: 45, // Cooldown (in game ticks) of nest food spawn attempts being made. + // Allow foods to be spawned or not. + FOOD_SPAWN_CHANCE: 0.05, // Likeliness of normal food spawn attempts succeedingg. 0.875 + // NOTE: Disabling it decreases lagness, also very useful if you don't need foods to be spawned. + FOOD_SPAWN_COOLDOWN: 100, // Cooldown (in game ticks) of food spawn attempts being made. 30 + ENABLE_FOOD: true, - ENEMY_CAP_NEST: 1, // Max nest enemies per nest tile. - ENEMY_SPAWN_CHANCE_NEST: 0.9, // Likeliness of nest enemies spawn attempts succeeding. + FOOD_CAP: 1, // Max normal food per normal tile. 3 + FOOD_SPAWN_CHANCE: 0.05, // Likeliness of normal food spawn attempts succeedingg. 0.875 + FOOD_SPAWN_COOLDOWN: 100, // Cooldown (in game ticks) of food spawn attempts being made. 30 + + FOOD_CAP_NEST: 1, // Max nest food per nest tile. 3 + FOOD_SPAWN_CHANCE_NEST: 0.05, // Likeliness of nest food spawn attempts succeeding. 0.25 + FOOD_SPAWN_COOLDOWN_NEST: 150, // Cooldown (in game ticks) of nest food spawn attempts being made. 45 + + ENEMY_CAP_NEST: 0, // Max nest enemies per nest tile. 1 + ENEMY_SPAWN_CHANCE_NEST: 0.9, // Likeliness of nest enemies spawn attempts succeeding. 0.9 ENEMY_SPAWN_COOLDOWN_NEST: 60, // Cooldown (in game ticks) of nest enemies spawn attempts being made. // Cooldown (in seconds) of boss spawns being announced. - BOSS_SPAWN_COOLDOWN: 60, + BOSS_SPAWN_COOLDOWN: 360, //120 // The delay (in seconds) between the boss spawns being announced and the bosses actually spawning. // NOTE: The spawn message (ex. "A strange trembling...") takes half as long to appear than the boss. BOSS_SPAWN_DURATION: 5, @@ -209,7 +238,7 @@ module.exports = { message: "A strange trembling...", },{ bosses: ["paladin", "freyja", "zaphkiel", "nyx", "theia"], - amount: [1], chance: 0.1, + amount: [1], chance: 0.01, message: "The world tremors as the celestials are reborn anew!", },{ bosses: ["julius", "genghis", "napoleon"], @@ -234,5 +263,7 @@ module.exports = { MAZE: false, HUNT: false, MODE: "ffa", - TAG: false -} + TAG: false, + GOVERNMENTAL: false, + SPAWN_CONFINEMENT: {}, +} \ No newline at end of file diff --git a/server/index.js b/server/index.js index 6358130c4..23214f61c 100644 --- a/server/index.js +++ b/server/index.js @@ -20,7 +20,7 @@ Array.prototype.remove = function (index) { //console window title // https://stackoverflow.com/questions/29548477/how-do-you-set-the-terminal-tab-title-from-node-js -process.stdout.write(String.fromCharCode(27) + "]0;" + c.WINDOW_NAME + String.fromCharCode(7)); +process.stdout.write(String.fromCharCode(27) + "]0;" + Config.WINDOW_NAME + String.fromCharCode(7)); util.log(room.width + " x " + room.height + " room initalized."); @@ -30,7 +30,11 @@ function collide(collision) { // Pull the two objects from the collision grid let instance = collision[0], other = collision[1]; + if (instance.noclip || other.noclip) { + return 0; + } instance.emit('collide', { body: instance, instance, other }); + other.emit('collide', { body: other, instance: other, other: instance }); // Check for ghosts... if (other.isGhost) { util.error("GHOST FOUND"); @@ -38,8 +42,8 @@ function collide(collision) { util.error("x: " + other.x + " y: " + other.y); util.error(other.collisionArray); util.error("health: " + other.health.amount); - util.warn("Ghost removed."); if (grid.checkIfInHSHG(other)) { + other.kill(); util.warn("Ghost removed."); grid.removeObject(other); } @@ -52,30 +56,31 @@ function collide(collision) { util.error(instance.collisionArray); util.error("health: " + instance.health.amount); if (grid.checkIfInHSHG(instance)) { + other.kill(); util.warn("Ghost removed."); grid.removeObject(instance); } return 0; } if ( - (!instance.activation.check() && !other.activation.check()) || - (instance.ac && !instance.alpha) || - (other.ac && !other.alpha) + (!instance.activation.active && !other.activation.active) || + (instance.isArenaCloser && !instance.alpha) || + (other.isArenaCloser && !other.alpha) ) return 0; switch (true) { case instance.type === "wall" || other.type === "wall": if (instance.type === "wall" && other.type === "wall") return; if (instance.type === "aura" || other.type === "aura") return; if (instance.type === "satellite" || other.type === "satellite") return; + if (instance.type === "shield" || other.type === "shield" || instance.type === "brella" || other.type === "brella") return; let wall = instance.type === "wall" ? instance : other; let entity = instance.type === "wall" ? other : instance; - if (entity.ac || entity.master.ac) return; - switch (true) { - case (wall.shape == 4): - case (wall.shapeData == "M 1 1 L -1 1 L -1 -1 L 1 -1 Z"): + if (entity.isArenaCloser || entity.master.isArenaCloser) return; + switch (wall.shape) { + case 4: mazewallcollide(wall, entity); break; - case (wall.shape == 0): + case 0: mooncollide(wall, entity); break; default: @@ -84,6 +89,35 @@ function collide(collision) { break; } break; + case instance.type === "shield" || other.type === "shield": + if (instance.type === "aura" || other.type === "aura" || instance.type === "satellite" || other.type === "satellite" || instance.type === "satellite" || other.type === "satellite" || instance.team === other.team) return; + let shield = instance.type === "shield" ? instance : other; + let nonshield = instance.type === "shield" ? other : instance; + switch (true) { + case (shield.shapeData == "m -0.7020 -0.8099 c 0.2987 0.4922 0.4276 1.0098 0 1.6105 c 0.4606 -0.1615 0.9233 -0.3735 1.3947 -0.8052 C 0.2005 -0.4442 -0.2526 -0.6387 -0.702 -0.8099"): + mirrorcollide(shield, nonshield); + break; + default: + reflectcollide(shield, nonshield); + break; + } + break; + case instance.type === "brella" || other.type === "brella": + if (instance.type === "aura" || other.type === "aura" || instance.type === "satellite" || other.type === "satellite" || instance.type === "satellite" || other.type === "satellite" || instance.team === other.team) return; + let brella = instance.type === "brella" ? instance : other; + let nonbrella = instance.type === "brella" ? other : instance; + switch (true) { + default: + reflectcollide(brella, nonbrella); + break; + } + break; + case instance.type === "hookpoint" || other.type === "hookpoint": + + let hookpoint = instance.type === "hookpoint" ? instance : other; + let hook = instance.type === "hookpoint" ? other : instance; + simplecollide(hookpoint, hook) + break; case instance.team === other.team && (instance.settings.hitsOwnType === "pushOnlyTeam" || other.settings.hitsOwnType === "pushOnlyTeam"): @@ -191,14 +225,14 @@ function collide(collision) { } // The most important loop. Lots of looping. -let time, ticks = 0; +let ticks = 0; const gameloop = () => { logs.loops.tally(); - logs.master.set(); - logs.activation.set(); - logs.activation.mark(); + logs.master.startTracking(); + logs.activation.startTracking(); + logs.activation.endTracking(); // Do collisions - logs.collide.set(); + logs.collide.startTracking(); if (entities.length > 1) { // Load the grid grid.update(); @@ -208,48 +242,48 @@ const gameloop = () => { collide(pairs[i]); } } - logs.collide.mark(); + logs.collide.endTracking(); // Do entities life - logs.entities.set(); + logs.entities.startTracking(); for (let my of entities) { // Consider death. if (my.contemplationOfMortality()) { my.destroy(); } else { - if (my.bond == null) { - // Resolve the physical behavior from the last collision cycle. - logs.physics.set(); - my.physics(); - logs.physics.mark(); - } - if (my.activation.check() || my.isPlayer) { + if (my.activation.active || my.isPlayer) { + if (my.bond == null) { + // Resolve the physical behavior from the last collision cycle. + logs.physics.startTracking(); + my.physics(); + logs.physics.endTracking(); + } logs.entities.tally(); // Think about my actions. - logs.life.set(); + logs.life.startTracking(); my.life(); - logs.life.mark(); + logs.life.endTracking(); // Apply friction. my.friction(); my.confinementToTheseEarthlyShackles(); - logs.selfie.set(); + logs.selfie.startTracking(); my.takeSelfie(); - logs.selfie.mark(); + logs.selfie.endTracking(); } // Update collisions. my.collisionArray = []; // Activation my.activation.update(); - my.updateAABB(my.activation.check()); + my.updateAABB(my.activation.active); } // Update collisions. my.collisionArray = []; my.emit('tick', { body: my }); } - logs.entities.mark(); - logs.master.mark(); + logs.entities.endTracking(); + logs.master.endTracking(); // Remove dead entities purgeEntities(); - room.lastCycle = util.time(); + room.lastCycle = performance.now(); ticks++; if (ticks & 1) { for (let i = 0; i < sockets.players.length; i++) { @@ -259,36 +293,37 @@ const gameloop = () => { } }; -setTimeout(closeArena, 60000 * 120); // Restart every 2 hours +setTimeout(closeArena, 24 * 60 * 60 * 1000); // Restart every 2 hours global.naturallySpawnedBosses = []; global.bots = []; let bossTimer = 0; -// A less important loop. -let maintainloop = () => { - // Regen health and update the grid +let regenerateHealthAndShield = () => { for (let i = 0; i < entities.length; i++) { let instance = entities[i]; if (instance.shield.max) { instance.shield.regenerate(); } - if (instance.health.amount) { + if (instance.health.max) { instance.health.regenerate(instance.shield.max && instance.shield.max === instance.shield.amount); } } - if (!naturallySpawnedBosses.length && bossTimer++ > c.BOSS_SPAWN_COOLDOWN) { - bossTimer = -c.BOSS_SPAWN_DURATION; - let selection = c.BOSS_TYPES[ran.chooseChance(...c.BOSS_TYPES.map((selection) => selection.chance))], +} +const maintainloop = () => { + // Update the grid + if (!naturallySpawnedBosses.length && bossTimer++ > Config.BOSS_SPAWN_COOLDOWN) { + bossTimer = -Config.BOSS_SPAWN_DURATION; + let selection = Config.BOSS_TYPES[ran.chooseChance(...Config.BOSS_TYPES.map((selection) => selection.chance))], amount = ran.chooseChance(...selection.amount) + 1; if (selection.message) { sockets.broadcast(selection.message); } sockets.broadcast(amount > 1 ? "Visitors are coming." : "A visitor is coming."); setSyncedTimeout(() => { - let names = []; + let names = ran.chooseBossName(selection.nameType, amount); for (let i = 0; i < amount; i++) { - let spot, attempts = 30, name = ran.chooseBossName(selection.nameType); + let spot, attempts = 30, name = names[i]; do { spot = getSpawnableArea(TEAM_ENEMIES); } while (attempts-- && dirtyCheck(spot, 500)); let boss = new Entity(spot); @@ -298,54 +333,65 @@ let maintainloop = () => { boss.name = name; } - names.push(boss.name); naturallySpawnedBosses.push(boss); boss.on('dead', () => util.remove(naturallySpawnedBosses, naturallySpawnedBosses.indexOf(boss))); } sockets.broadcast(`${util.listify(names)} ${names.length == 1 ? 'has' : 'have'} arrived!`); - }, c.BOSS_SPAWN_DURATION * 30); + }, Config.BOSS_SPAWN_DURATION * 30); } // upgrade existing ones for (let i = 0; i < bots.length; i++) { let o = bots[i]; - if (o.skill.level < c.LEVEL_CAP) { - o.skill.score += c.BOT_XP; + if (o.skill.level < Config.LEVEL_CAP) { + o.skill.score += Config.BOT_XP; } o.skill.maintain(); - o.skillUp([ "atk", "hlt", "spd", "str", "pen", "dam", "rld", "mob", "rgn", "shi" ][ran.chooseChance(...c.BOT_SKILL_UPGRADE_CHANCES)]); + o.skillUp([ "atk", "hlt", "spd", "str", "pen", "dam", "rld", "mob", "rgn", "shi" ][ran.chooseChance(...Config.BOT_SKILL_UPGRADE_CHANCES)]); if (o.leftoverUpgrades && o.upgrade(ran.irandomRange(0, o.upgrades.length))) { o.leftoverUpgrades--; } } // then add new bots if arena is open - if (!global.arenaClosed && bots.length < c.BOTS) { - let team = c.MODE === "tdm" ? getWeakestTeam() : undefined, + if (!global.arenaClosed && bots.length < Config.BOTS) { + let botName = Config.BOT_NAME_PREFIX + ran.chooseBotName(), + team = Config.MODE === "tdm" ? getWeakestTeam() : undefined, limit = 20, // give up after 20 attempts and just pick whatever is currently chosen loc; do { loc = getSpawnableArea(team); } while (limit-- && dirtyCheck(loc, 50)) let o = new Entity(loc); - o.define('bot'); - o.define(c.SPAWN_CLASS); + o.define(Config.SPAWN_CLASS); + o.define({ CONTROLLERS: ["nearestDifferentMaster"] }); o.refreshBodyAttributes(); - o.skill.score = c.BOT_START_XP; + o.skill.score = Config.BOT_START_XP; o.isBot = true; - o.name = Config.BOT_NAME_PREFIX + ran.chooseBotName(); - o.leftoverUpgrades = ran.chooseChance(...c.BOT_CLASS_UPGRADE_CHANCES); - let color = c.RANDOM_COLORS ? Math.floor(Math.random() * 20) : team ? getTeamColor(team) : "darkGrey"; + o.name = botName; + o.invuln = true; + o.nameColor = "#ffffff"; + o.leftoverUpgrades = ran.chooseChance(...Config.BOT_CLASS_UPGRADE_CHANCES); + let color = Config.RANDOM_COLORS ? Math.floor(Math.random() * 20) : team ? getTeamColor(team) : "darkGrey"; o.color.base = color; if (team) o.team = team; bots.push(o); + setTimeout(() => { + // allow them to move + // Save index so it isn't overwritten by the bot Class's index + let index = o.index; + o.define('bot'); + o.index = index; + o.refreshBodyAttributes(); + o.invuln = false; + }, 3000 + Math.floor(Math.random() * 7000)); o.on('dead', () => util.remove(bots, bots.indexOf(o))); } }; //evaluating js with a seperate console window if enabled -if (c.REPL_WINDOW) { +if (Config.REPL_WINDOW) { util.log('Starting REPL Terminal.'); //TODO: figure out how to spawn a seperate window and put the REPL stdio in there instead //let { stdin, stdout, stderr } = (require('child_process').spawn("cmd.exe", ["/c", "node", "blank.js"], { detached: true })); @@ -355,11 +401,14 @@ if (c.REPL_WINDOW) { // Bring it to life let counter = 0; setInterval(() => { - gameloop() + regenerateHealthAndShield(); +}, room.regenerateTick); +setInterval(() => { + gameloop(); gamemodeLoop(); roomLoop(); - if (counter++ / c.runSpeed > 30) { + if (counter++ / Config.runSpeed > 30) { chatLoop(); maintainloop(); speedcheckloop(); @@ -367,4 +416,4 @@ setInterval(() => { } syncedDelaysLoop(); -}, room.cycleSpeed); +}, room.cycleSpeed); \ No newline at end of file diff --git a/server/lib/hshg.js b/server/lib/hshg.js index 9374fdf4c..eea710469 100644 --- a/server/lib/hshg.js +++ b/server/lib/hshg.js @@ -1,630 +1,618 @@ -/*** -Can't be bothered to touch this shit yet. - -- damocles -***/ - -/*** -you never will because we fired you lol - -- zephi -***/ - // Hierarchical Spatial Hash Grid: HSHG // https://gist.github.com/kirbysayshi/1760774 (function (root, undefined) { - //--------------------------------------------------------------------- - // GLOBAL FUNCTIONS - //--------------------------------------------------------------------- - - /** - * Updates every object's position in the grid, but only if - * the hash value for that object has changed. - * This method DOES NOT take into account object expansion or - * contraction, just position, and does not attempt to change - * the grid the object is currently in; it only (possibly) changes - * the cell. - * - * If the object has significantly changed in size, the best bet is to - * call removeObject() and addObject() sequentially, outside of the - * normal update cycle of HSHG. - * - * @return void desc - */ - function update_RECOMPUTE() { - var i, obj, grid, meta, objAABB, newObjHash; - - // for each object - for (i = 0; i < this._globalObjects.length; i++) { - obj = this._globalObjects[i]; - meta = obj.HSHG; - grid = meta.grid; - - // recompute hash - objAABB = obj.getAABB(); - newObjHash = grid.toHash(objAABB.min[0], objAABB.min[1]); - - if (newObjHash !== meta.hash) { - // grid position has changed, update! - grid.removeObject(obj); - grid.addObject(obj, newObjHash); - } + //--------------------------------------------------------------------- + // GLOBAL FUNCTIONS + //--------------------------------------------------------------------- + + /** + * Updates every object's position in the grid, but only if + * the hash value for that object has changed. + * This method DOES NOT take into account object expansion or + * contraction, just position, and does not attempt to change + * the grid the object is currently in; it only (possibly) changes + * the cell. + * + * If the object has significantly changed in size, the best bet is to + * call removeObject() and addObject() sequentially, outside of the + * normal update cycle of HSHG. + * + * @return void desc + */ + function update_RECOMPUTE() { + var i, obj, grid, meta, objAABB, newObjHash; + + // for each object + for (i = 0; i < this._globalObjects.length; i++) { + obj = this._globalObjects[i]; + meta = obj.HSHG; + grid = meta.grid; + + // recompute hash + objAABB = obj.getAABB(); + newObjHash = grid.toHash(objAABB.min[0], objAABB.min[1]); + + if (newObjHash !== meta.hash) { + // grid position has changed, update! + grid.removeObject(obj); + grid.addObject(obj, newObjHash); + } + } } - } - - // not implemented yet :) - function update_REMOVEALL() {} - - function testAABBOverlap(objA, objB) { - var a = objA.getAABB(), - b = objB.getAABB(); - - //if(a.min[0] > b.max[0] || a.min[1] > b.max[1] || a.min[2] > b.max[2] - //|| a.max[0] < b.min[0] || a.max[1] < b.min[1] || a.max[2] < b.min[2]){ - if (!a.active && !b.active) return false; - - if ( - a.min[0] > b.max[0] || - a.min[1] > b.max[1] || - a.max[0] < b.min[0] || - a.max[1] < b.min[1] - ) { - return false; - } else { - return true; + + // not implemented yet :) + function update_REMOVEALL() { } + + function testAABBOverlap(objA, objB) { + var a = objA.getAABB(), + b = objB.getAABB(); + + //if(a.min[0] > b.max[0] || a.min[1] > b.max[1] || a.min[2] > b.max[2] + //|| a.max[0] < b.min[0] || a.max[1] < b.min[1] || a.max[2] < b.min[2]){ + if (!a.active && !b.active) return false; + + if ( + a.min[0] > b.max[0] || + a.min[1] > b.max[1] || + a.max[0] < b.min[0] || + a.max[1] < b.min[1] + ) { + return false; + } else { + return true; + } } - } - - function getLongestAABBEdge(min, max) { - return Math.max( - Math.abs(max[0] - min[0]), - Math.abs(max[1] - min[1]) - //,Math.abs(max[2] - min[2]) - ); - } - - //--------------------------------------------------------------------- - // ENTITIES - //--------------------------------------------------------------------- - - function HSHG() { - this.MAX_OBJECT_CELL_DENSITY = 1 / 8; // objects / cells - this.INITIAL_GRID_LENGTH = 256; // 16x16 - this.HIERARCHY_FACTOR = 2; - this.HIERARCHY_FACTOR_SQRT = Math.SQRT2; - this.UPDATE_METHOD = update_RECOMPUTE; // or update_REMOVEALL - - this._grids = []; - this._globalObjects = []; - } - - //HSHG.prototype.init = function(){ - // this._grids = []; - // this._globalObjects = []; - //} - - HSHG.prototype.addObject = function (obj) { - var x, - i, - cellSize, - objAABB = obj.getAABB(), - objSize = getLongestAABBEdge(objAABB.min, objAABB.max), - oneGrid, - newGrid; - - // for HSHG metadata - obj.HSHG = { - globalObjectsIndex: this._globalObjects.length, - }; - // add to global object array - this._globalObjects.push(obj); - - if (this._grids.length == 0) { - // no grids exist yet - cellSize = objSize * this.HIERARCHY_FACTOR_SQRT; - newGrid = new Grid(cellSize, this.INITIAL_GRID_LENGTH, this); - newGrid.initCells(); - newGrid.addObject(obj); - - this._grids.push(newGrid); - } else { - x = 0; - - // grids are sorted by cellSize, smallest to largest - for (i = 0; i < this._grids.length; i++) { - oneGrid = this._grids[i]; - x = oneGrid.cellSize; - if (objSize < x) { - x = x / this.HIERARCHY_FACTOR; - if (objSize < x) { - // find appropriate size - while (objSize < x) { - x = x / this.HIERARCHY_FACTOR; + function getLongestAABBEdge(min, max) { + return Math.max( + Math.abs(max[0] - min[0]), + Math.abs(max[1] - min[1]) + //,Math.abs(max[2] - min[2]) + ); + } + + //--------------------------------------------------------------------- + // ENTITIES + //--------------------------------------------------------------------- + + function HSHG() { + this.MAX_OBJECT_CELL_DENSITY = 1 / 8; // objects / cells + this.INITIAL_GRID_LENGTH = 256; // 16x16 + this.HIERARCHY_FACTOR = 2; + this.HIERARCHY_FACTOR_SQRT = Math.SQRT2; + this.UPDATE_METHOD = update_RECOMPUTE; // or update_REMOVEALL + + this._grids = []; + this._globalObjects = []; + } + + //HSHG.prototype.init = function(){ + // this._grids = []; + // this._globalObjects = []; + //} + + HSHG.prototype.addObject = function (obj) { + var x, + i, + cellSize, + objAABB = obj.getAABB(), + objSize = getLongestAABBEdge(objAABB.min, objAABB.max), + oneGrid, + newGrid; + + // for HSHG metadata + obj.HSHG = { + globalObjectsIndex: this._globalObjects.length, + }; + + // add to global object array + this._globalObjects.push(obj); + + if (this._grids.length == 0) { + // no grids exist yet + cellSize = objSize * this.HIERARCHY_FACTOR_SQRT; + newGrid = new Grid(cellSize, this.INITIAL_GRID_LENGTH, this); + newGrid.initCells(); + newGrid.addObject(obj); + + this._grids.push(newGrid); + } else { + x = 0; + + // grids are sorted by cellSize, smallest to largest + for (i = 0; i < this._grids.length; i++) { + oneGrid = this._grids[i]; + x = oneGrid.cellSize; + if (objSize < x) { + x = x / this.HIERARCHY_FACTOR; + if (objSize < x) { + // find appropriate size + while (objSize < x) { + x = x / this.HIERARCHY_FACTOR; + } + newGrid = new Grid( + x * this.HIERARCHY_FACTOR, + this.INITIAL_GRID_LENGTH, + this + ); + newGrid.initCells(); + // assign obj to grid + newGrid.addObject(obj); + // insert grid into list of grids directly before oneGrid + this._grids.splice(i, 0, newGrid); + } else { + // insert obj into grid oneGrid + oneGrid.addObject(obj); + } + return; + } + } + + while (objSize >= x) { + x = x * this.HIERARCHY_FACTOR; } - newGrid = new Grid( - x * this.HIERARCHY_FACTOR, - this.INITIAL_GRID_LENGTH, - this - ); + + newGrid = new Grid(x, this.INITIAL_GRID_LENGTH, this); newGrid.initCells(); - // assign obj to grid + // insert obj into grid newGrid.addObject(obj); - // insert grid into list of grids directly before oneGrid - this._grids.splice(i, 0, newGrid); - } else { - // insert obj into grid oneGrid - oneGrid.addObject(obj); - } - return; + // add newGrid as last element in grid list + this._grids.push(newGrid); } - } - - while (objSize >= x) { - x = x * this.HIERARCHY_FACTOR; - } - - newGrid = new Grid(x, this.INITIAL_GRID_LENGTH, this); - newGrid.initCells(); - // insert obj into grid - newGrid.addObject(obj); - // add newGrid as last element in grid list - this._grids.push(newGrid); - } - }; + }; - HSHG.prototype.checkIfInHSHG = function (obj) { - var meta = obj.HSHG, - globalObjectsIndex, - replacementObj; + HSHG.prototype.checkIfInHSHG = function (obj) { + var meta = obj.HSHG, + globalObjectsIndex, + replacementObj; - if (meta === undefined) return false; - return true; - }; + if (meta === undefined) return false; + return true; + }; - HSHG.prototype.removeObject = function (obj) { - var meta = obj.HSHG, - globalObjectsIndex, - replacementObj; + HSHG.prototype.removeObject = function (obj) { + var meta = obj.HSHG, + globalObjectsIndex, + replacementObj; - if (meta === undefined) { - throw Error(obj + " was not in the HSHG."); - return; - } + if (meta === undefined) { + throw Error(obj + " was not in the HSHG."); + return; + } - // remove object from global object list - globalObjectsIndex = meta.globalObjectsIndex; - if (globalObjectsIndex === this._globalObjects.length - 1) { - this._globalObjects.pop(); - } else { - replacementObj = this._globalObjects.pop(); - replacementObj.HSHG.globalObjectsIndex = globalObjectsIndex; - this._globalObjects[globalObjectsIndex] = replacementObj; - } + // remove object from global object list + globalObjectsIndex = meta.globalObjectsIndex; + if (globalObjectsIndex === this._globalObjects.length - 1) { + this._globalObjects.pop(); + } else { + replacementObj = this._globalObjects.pop(); + replacementObj.HSHG.globalObjectsIndex = globalObjectsIndex; + this._globalObjects[globalObjectsIndex] = replacementObj; + } + + meta.grid.removeObject(obj); - meta.grid.removeObject(obj); - - // remove meta data - delete obj.HSHG; - }; - - HSHG.prototype.update = function () { - this.UPDATE_METHOD.call(this); - }; - - HSHG.prototype.queryForCollisionPairs = function (broadOverlapTestCallback) { - var i, - j, - k, - l, - c, - grid, - cell, - objA, - objB, - offset, - adjacentCell, - biggerGrid, - objAAABB, - objAHashInBiggerGrid, - possibleCollisions = [], - broadOverlapTest; - - // default broad test to internal aabb overlap test - broadOverlapTest = broadOverlapTestCallback || testAABBOverlap; - - // for all grids ordered by cell size ASC - for (i = 0; i < this._grids.length; i++) { - grid = this._grids[i]; - - // for each cell of the grid that is occupied - for (j = 0; j < grid.occupiedCells.length; j++) { - cell = grid.occupiedCells[j]; - - // collide all objects within the occupied cell - for (k = 0; k < cell.objectContainer.length; k++) { - objA = cell.objectContainer[k]; - if (!objA.getAABB().active) continue; - for (l = k + 1; l < cell.objectContainer.length; l++) { - objB = cell.objectContainer[l]; - if (!objB.getAABB().active) continue; - if (broadOverlapTest(objA, objB) === true) { - possibleCollisions.push([objA, objB]); + // remove meta data + delete obj.HSHG; + }; + + HSHG.prototype.update = function () { + this.UPDATE_METHOD.call(this); + }; + + HSHG.prototype.queryForCollisionPairs = function (broadOverlapTestCallback) { + var i, + j, + k, + l, + c, + grid, + cell, + objA, + objB, + offset, + adjacentCell, + biggerGrid, + objAAABB, + objAHashInBiggerGrid, + possibleCollisions = [], + broadOverlapTest; + + // default broad test to internal aabb overlap test + broadOverlapTest = broadOverlapTestCallback || testAABBOverlap; + + // for all grids ordered by cell size ASC + for (i = 0; i < this._grids.length; i++) { + grid = this._grids[i]; + + // for each cell of the grid that is occupied + for (j = 0; j < grid.occupiedCells.length; j++) { + cell = grid.occupiedCells[j]; + + // collide all objects within the occupied cell + for (k = 0; k < cell.objectContainer.length; k++) { + objA = cell.objectContainer[k]; + if (!objA.getAABB().active) continue; + for (l = k + 1; l < cell.objectContainer.length; l++) { + objB = cell.objectContainer[l]; + if (!objB.getAABB().active) continue; + if (broadOverlapTest(objA, objB) === true) { + possibleCollisions.push([objA, objB]); + } + } + } + + // for the first half of all adjacent cells (offset 4 is the current cell) + for (c = 0; c < 4; c++) { + offset = cell.neighborOffsetArray[c]; + + //if(offset === null) { continue; } + + adjacentCell = grid.allCells[cell.allCellsIndex + offset]; + + // collide all objects in cell with adjacent cell + for (k = 0; k < cell.objectContainer.length; k++) { + objA = cell.objectContainer[k]; + if (!objA.getAABB().active) continue; + for (l = 0; l < adjacentCell.objectContainer.length; l++) { + objB = adjacentCell.objectContainer[l]; + if (!objB.getAABB().active) continue; + if (broadOverlapTest(objA, objB) === true) { + possibleCollisions.push([objA, objB]); + } + } + } + } + } + + // forall objects that are stored in this grid + for (j = 0; j < grid.allObjects.length; j++) { + objA = grid.allObjects[j]; + objAAABB = objA.getAABB(); + if (!objAAABB.active) continue; + // for all grids with cellsize larger than grid + for (k = i + 1; k < this._grids.length; k++) { + biggerGrid = this._grids[k]; + objAHashInBiggerGrid = biggerGrid.toHash( + objAAABB.min[0], + objAAABB.min[1] + ); + cell = biggerGrid.allCells[objAHashInBiggerGrid]; + + // check objA against every object in all cells in offset array of cell + // for all adjacent cells... + for (c = 0; c < cell.neighborOffsetArray.length; c++) { + offset = cell.neighborOffsetArray[c]; + + //if(offset === null) { continue; } + + adjacentCell = biggerGrid.allCells[cell.allCellsIndex + offset]; + + // for all objects in the adjacent cell... + for (l = 0; l < adjacentCell.objectContainer.length; l++) { + objB = adjacentCell.objectContainer[l]; + if (!objB.getAABB().active) continue; + // test against object A + if (broadOverlapTest(objA, objB) === true) { + possibleCollisions.push([objA, objB]); + } + } + } + } } - } } - // for the first half of all adjacent cells (offset 4 is the current cell) - for (c = 0; c < 4; c++) { - offset = cell.neighborOffsetArray[c]; + // return list of object pairs + return possibleCollisions; + }; + + HSHG.update_RECOMPUTE = update_RECOMPUTE; + HSHG.update_REMOVEALL = update_REMOVEALL; + + /** + * Grid + * + * @constructor + * @param int cellSize the pixel size of each cell of the grid + * @param int cellCount the total number of cells for the grid (width x height) + * @param HSHG parentHierarchy the HSHG to which this grid belongs + * @return void + */ + function Grid(cellSize, cellCount, parentHierarchy) { + this.cellSize = cellSize; + this.inverseCellSize = 1 / cellSize; + this.rowColumnCount = ~~Math.sqrt(cellCount); + this.xyHashMask = this.rowColumnCount - 1; + this.occupiedCells = []; + this.allCells = Array(this.rowColumnCount * this.rowColumnCount); + this.allObjects = []; + this.sharedInnerOffsets = []; + + this._parentHierarchy = parentHierarchy || null; + } - //if(offset === null) { continue; } + Grid.prototype.initCells = function () { + // TODO: inner/unique offset rows 0 and 2 may need to be + // swapped due to +y being "down" vs "up" + + var i, + gridLength = this.allCells.length, + x, + y, + wh = this.rowColumnCount, + isOnRightEdge, + isOnLeftEdge, + isOnTopEdge, + isOnBottomEdge, + innerOffsets = [ + // y+ down offsets + //-1 + -wh, -wh, -wh + 1, + //-1, 0, 1, + //wh - 1, wh, wh + 1 + + // y+ up offsets + wh - 1, + wh, + wh + 1, + -1, + 0, + 1, + -1 + -wh, + -wh, + -wh + 1, + ], + leftOffset, + rightOffset, + topOffset, + bottomOffset, + uniqueOffsets = [], + cell; + + this.sharedInnerOffsets = innerOffsets; + + // init all cells, creating offset arrays as needed + + for (i = 0; i < gridLength; i++) { + cell = new Cell(); + // compute row (y) and column (x) for an index + y = ~~(i / this.rowColumnCount); + x = ~~(i - y * this.rowColumnCount); + + // reset / init + isOnRightEdge = false; + isOnLeftEdge = false; + isOnTopEdge = false; + isOnBottomEdge = false; + + // right or left edge cell + if ((x + 1) % this.rowColumnCount == 0) { + isOnRightEdge = true; + } else if (x % this.rowColumnCount == 0) { + isOnLeftEdge = true; + } - adjacentCell = grid.allCells[cell.allCellsIndex + offset]; + // top or bottom edge cell + if ((y + 1) % this.rowColumnCount == 0) { + isOnTopEdge = true; + } else if (y % this.rowColumnCount == 0) { + isOnBottomEdge = true; + } - // collide all objects in cell with adjacent cell - for (k = 0; k < cell.objectContainer.length; k++) { - objA = cell.objectContainer[k]; - if (!objA.getAABB().active) continue; - for (l = 0; l < adjacentCell.objectContainer.length; l++) { - objB = adjacentCell.objectContainer[l]; - if (!objB.getAABB().active) continue; - if (broadOverlapTest(objA, objB) === true) { - possibleCollisions.push([objA, objB]); - } + // if cell is edge cell, use unique offsets, otherwise use inner offsets + if (isOnRightEdge || isOnLeftEdge || isOnTopEdge || isOnBottomEdge) { + // figure out cardinal offsets first + rightOffset = isOnRightEdge === true ? -wh + 1 : 1; + leftOffset = isOnLeftEdge === true ? wh - 1 : -1; + topOffset = isOnTopEdge === true ? -gridLength + wh : wh; + bottomOffset = isOnBottomEdge === true ? gridLength - wh : -wh; + + // diagonals are composites of the cardinals + uniqueOffsets = [ + // y+ down offset + //leftOffset + bottomOffset, bottomOffset, rightOffset + bottomOffset, + //leftOffset, 0, rightOffset, + //leftOffset + topOffset, topOffset, rightOffset + topOffset + + // y+ up offset + leftOffset + topOffset, + topOffset, + rightOffset + topOffset, + leftOffset, + 0, + rightOffset, + leftOffset + bottomOffset, + bottomOffset, + rightOffset + bottomOffset, + ]; + + cell.neighborOffsetArray = uniqueOffsets; + } else { + cell.neighborOffsetArray = this.sharedInnerOffsets; } - } + + cell.allCellsIndex = i; + this.allCells[i] = cell; } - } - - // forall objects that are stored in this grid - for (j = 0; j < grid.allObjects.length; j++) { - objA = grid.allObjects[j]; - objAAABB = objA.getAABB(); - if (!objAAABB.active) continue; - // for all grids with cellsize larger than grid - for (k = i + 1; k < this._grids.length; k++) { - biggerGrid = this._grids[k]; - objAHashInBiggerGrid = biggerGrid.toHash( - objAAABB.min[0], - objAAABB.min[1] - ); - cell = biggerGrid.allCells[objAHashInBiggerGrid]; - - // check objA against every object in all cells in offset array of cell - // for all adjacent cells... - for (c = 0; c < cell.neighborOffsetArray.length; c++) { - offset = cell.neighborOffsetArray[c]; - - //if(offset === null) { continue; } - - adjacentCell = biggerGrid.allCells[cell.allCellsIndex + offset]; - - // for all objects in the adjacent cell... - for (l = 0; l < adjacentCell.objectContainer.length; l++) { - objB = adjacentCell.objectContainer[l]; - if (!objB.getAABB().active) continue; - // test against object A - if (broadOverlapTest(objA, objB) === true) { - possibleCollisions.push([objA, objB]); - } - } - } + }; + + Grid.prototype.toHash = function (x, y, z) { + var i, xHash, yHash, zHash; + + if (x < 0) { + i = -x * this.inverseCellSize; + xHash = this.rowColumnCount - 1 - (~~i & this.xyHashMask); + } else { + i = x * this.inverseCellSize; + xHash = ~~i & this.xyHashMask; } - } - } - // return list of object pairs - return possibleCollisions; - }; - - HSHG.update_RECOMPUTE = update_RECOMPUTE; - HSHG.update_REMOVEALL = update_REMOVEALL; - - /** - * Grid - * - * @constructor - * @param int cellSize the pixel size of each cell of the grid - * @param int cellCount the total number of cells for the grid (width x height) - * @param HSHG parentHierarchy the HSHG to which this grid belongs - * @return void - */ - function Grid(cellSize, cellCount, parentHierarchy) { - this.cellSize = cellSize; - this.inverseCellSize = 1 / cellSize; - this.rowColumnCount = ~~Math.sqrt(cellCount); - this.xyHashMask = this.rowColumnCount - 1; - this.occupiedCells = []; - this.allCells = Array(this.rowColumnCount * this.rowColumnCount); - this.allObjects = []; - this.sharedInnerOffsets = []; - - this._parentHierarchy = parentHierarchy || null; - } - - Grid.prototype.initCells = function () { - // TODO: inner/unique offset rows 0 and 2 may need to be - // swapped due to +y being "down" vs "up" - - var i, - gridLength = this.allCells.length, - x, - y, - wh = this.rowColumnCount, - isOnRightEdge, - isOnLeftEdge, - isOnTopEdge, - isOnBottomEdge, - innerOffsets = [ - // y+ down offsets - //-1 + -wh, -wh, -wh + 1, - //-1, 0, 1, - //wh - 1, wh, wh + 1 - - // y+ up offsets - wh - 1, - wh, - wh + 1, - -1, - 0, - 1, - -1 + -wh, - -wh, - -wh + 1, - ], - leftOffset, - rightOffset, - topOffset, - bottomOffset, - uniqueOffsets = [], - cell; - - this.sharedInnerOffsets = innerOffsets; - - // init all cells, creating offset arrays as needed - - for (i = 0; i < gridLength; i++) { - cell = new Cell(); - // compute row (y) and column (x) for an index - y = ~~(i / this.rowColumnCount); - x = ~~(i - y * this.rowColumnCount); - - // reset / init - isOnRightEdge = false; - isOnLeftEdge = false; - isOnTopEdge = false; - isOnBottomEdge = false; - - // right or left edge cell - if ((x + 1) % this.rowColumnCount == 0) { - isOnRightEdge = true; - } else if (x % this.rowColumnCount == 0) { - isOnLeftEdge = true; - } - - // top or bottom edge cell - if ((y + 1) % this.rowColumnCount == 0) { - isOnTopEdge = true; - } else if (y % this.rowColumnCount == 0) { - isOnBottomEdge = true; - } - - // if cell is edge cell, use unique offsets, otherwise use inner offsets - if (isOnRightEdge || isOnLeftEdge || isOnTopEdge || isOnBottomEdge) { - // figure out cardinal offsets first - rightOffset = isOnRightEdge === true ? -wh + 1 : 1; - leftOffset = isOnLeftEdge === true ? wh - 1 : -1; - topOffset = isOnTopEdge === true ? -gridLength + wh : wh; - bottomOffset = isOnBottomEdge === true ? gridLength - wh : -wh; - - // diagonals are composites of the cardinals - uniqueOffsets = [ - // y+ down offset - //leftOffset + bottomOffset, bottomOffset, rightOffset + bottomOffset, - //leftOffset, 0, rightOffset, - //leftOffset + topOffset, topOffset, rightOffset + topOffset - - // y+ up offset - leftOffset + topOffset, - topOffset, - rightOffset + topOffset, - leftOffset, - 0, - rightOffset, - leftOffset + bottomOffset, - bottomOffset, - rightOffset + bottomOffset, - ]; - - cell.neighborOffsetArray = uniqueOffsets; - } else { - cell.neighborOffsetArray = this.sharedInnerOffsets; - } - - cell.allCellsIndex = i; - this.allCells[i] = cell; - } - }; + if (y < 0) { + i = -y * this.inverseCellSize; + yHash = this.rowColumnCount - 1 - (~~i & this.xyHashMask); + } else { + i = y * this.inverseCellSize; + yHash = ~~i & this.xyHashMask; + } - Grid.prototype.toHash = function (x, y, z) { - var i, xHash, yHash, zHash; + //if(z < 0){ + // i = (-z) * this.inverseCellSize; + // zHash = this.rowColumnCount - 1 - ( ~~i & this.xyHashMask ); + //} else { + // i = z * this.inverseCellSize; + // zHash = ~~i & this.xyHashMask; + //} - if (x < 0) { - i = -x * this.inverseCellSize; - xHash = this.rowColumnCount - 1 - (~~i & this.xyHashMask); - } else { - i = x * this.inverseCellSize; - xHash = ~~i & this.xyHashMask; - } + return xHash + yHash * this.rowColumnCount; + //+ zHash * this.rowColumnCount * this.rowColumnCount; + }; - if (y < 0) { - i = -y * this.inverseCellSize; - yHash = this.rowColumnCount - 1 - (~~i & this.xyHashMask); - } else { - i = y * this.inverseCellSize; - yHash = ~~i & this.xyHashMask; - } + Grid.prototype.addObject = function (obj, hash) { + var objAABB, objHash, targetCell; - //if(z < 0){ - // i = (-z) * this.inverseCellSize; - // zHash = this.rowColumnCount - 1 - ( ~~i & this.xyHashMask ); - //} else { - // i = z * this.inverseCellSize; - // zHash = ~~i & this.xyHashMask; - //} + // technically, passing this in this should save some computational effort when updating objects + if (hash !== undefined) { + objHash = hash; + } else { + objAABB = obj.getAABB(); + objHash = this.toHash(objAABB.min[0], objAABB.min[1]); + } + targetCell = this.allCells[objHash]; + + if (targetCell.objectContainer.length === 0) { + // insert this cell into occupied cells list + targetCell.occupiedCellsIndex = this.occupiedCells.length; + this.occupiedCells.push(targetCell); + } - return xHash + yHash * this.rowColumnCount; - //+ zHash * this.rowColumnCount * this.rowColumnCount; - }; + // add meta data to obj, for fast update/removal + obj.HSHG.objectContainerIndex = targetCell.objectContainer.length; + obj.HSHG.hash = objHash; + obj.HSHG.grid = this; + obj.HSHG.allGridObjectsIndex = this.allObjects.length; + // add obj to cell + targetCell.objectContainer.push(obj); + + // we can assume that the targetCell is already a member of the occupied list + + // add to grid-global object list + this.allObjects.push(obj); + + // do test for grid density + if ( + this.allObjects.length / this.allCells.length > + this._parentHierarchy.MAX_OBJECT_CELL_DENSITY + ) { + // grid must be increased in size + this.expandGrid(); + } + }; - Grid.prototype.addObject = function (obj, hash) { - var objAABB, objHash, targetCell; + Grid.prototype.removeObject = function (obj) { + var meta = obj.HSHG, + hash, + containerIndex, + allGridObjectsIndex, + cell, + replacementCell, + replacementObj; + + hash = meta.hash; + containerIndex = meta.objectContainerIndex; + allGridObjectsIndex = meta.allGridObjectsIndex; + cell = this.allCells[hash]; + + // remove object from cell object container + if (cell.objectContainer.length === 1) { + // this is the last object in the cell, so reset it + cell.objectContainer.length = 0; + + // remove cell from occupied list + if (cell.occupiedCellsIndex === this.occupiedCells.length - 1) { + // special case if the cell is the newest in the list + this.occupiedCells.pop(); + } else { + replacementCell = this.occupiedCells.pop(); + replacementCell.occupiedCellsIndex = cell.occupiedCellsIndex; + this.occupiedCells[cell.occupiedCellsIndex] = replacementCell; + } - // technically, passing this in this should save some computational effort when updating objects - if (hash !== undefined) { - objHash = hash; - } else { - objAABB = obj.getAABB(); - objHash = this.toHash(objAABB.min[0], objAABB.min[1]); - } - targetCell = this.allCells[objHash]; + cell.occupiedCellsIndex = null; + } else { + // there is more than one object in the container + if (containerIndex === cell.objectContainer.length - 1) { + // special case if the obj is the newest in the container + cell.objectContainer.pop(); + } else { + replacementObj = cell.objectContainer.pop(); + replacementObj.HSHG.objectContainerIndex = containerIndex; + cell.objectContainer[containerIndex] = replacementObj; + } + } - if (targetCell.objectContainer.length === 0) { - // insert this cell into occupied cells list - targetCell.occupiedCellsIndex = this.occupiedCells.length; - this.occupiedCells.push(targetCell); - } + // remove object from grid object list + if (allGridObjectsIndex === this.allObjects.length - 1) { + this.allObjects.pop(); + } else { + replacementObj = this.allObjects.pop(); + replacementObj.HSHG.allGridObjectsIndex = allGridObjectsIndex; + this.allObjects[allGridObjectsIndex] = replacementObj; + } + }; - // add meta data to obj, for fast update/removal - obj.HSHG.objectContainerIndex = targetCell.objectContainer.length; - obj.HSHG.hash = objHash; - obj.HSHG.grid = this; - obj.HSHG.allGridObjectsIndex = this.allObjects.length; - // add obj to cell - targetCell.objectContainer.push(obj); - - // we can assume that the targetCell is already a member of the occupied list - - // add to grid-global object list - this.allObjects.push(obj); - - // do test for grid density - if ( - this.allObjects.length / this.allCells.length > - this._parentHierarchy.MAX_OBJECT_CELL_DENSITY - ) { - // grid must be increased in size - this.expandGrid(); - } - }; - - Grid.prototype.removeObject = function (obj) { - var meta = obj.HSHG, - hash, - containerIndex, - allGridObjectsIndex, - cell, - replacementCell, - replacementObj; - - hash = meta.hash; - containerIndex = meta.objectContainerIndex; - allGridObjectsIndex = meta.allGridObjectsIndex; - cell = this.allCells[hash]; - - // remove object from cell object container - if (cell.objectContainer.length === 1) { - // this is the last object in the cell, so reset it - cell.objectContainer.length = 0; - - // remove cell from occupied list - if (cell.occupiedCellsIndex === this.occupiedCells.length - 1) { - // special case if the cell is the newest in the list - this.occupiedCells.pop(); - } else { - replacementCell = this.occupiedCells.pop(); - replacementCell.occupiedCellsIndex = cell.occupiedCellsIndex; - this.occupiedCells[cell.occupiedCellsIndex] = replacementCell; - } - - cell.occupiedCellsIndex = null; - } else { - // there is more than one object in the container - if (containerIndex === cell.objectContainer.length - 1) { - // special case if the obj is the newest in the container - cell.objectContainer.pop(); - } else { - replacementObj = cell.objectContainer.pop(); - replacementObj.HSHG.objectContainerIndex = containerIndex; - cell.objectContainer[containerIndex] = replacementObj; - } - } + Grid.prototype.expandGrid = function () { + var i, + j, + currentCellCount = this.allCells.length, + currentRowColumnCount = this.rowColumnCount, + currentXYHashMask = this.xyHashMask, + newCellCount = currentCellCount * 4, // double each dimension + newRowColumnCount = ~~Math.sqrt(newCellCount), + newXYHashMask = newRowColumnCount - 1, + allObjects = this.allObjects.slice(0), // duplicate array, not objects contained + aCell, + push = Array.prototype.push; + + // remove all objects + for (i = 0; i < allObjects.length; i++) { + this.removeObject(allObjects[i]); + } - // remove object from grid object list - if (allGridObjectsIndex === this.allObjects.length - 1) { - this.allObjects.pop(); - } else { - replacementObj = this.allObjects.pop(); - replacementObj.HSHG.allGridObjectsIndex = allGridObjectsIndex; - this.allObjects[allGridObjectsIndex] = replacementObj; - } - }; - - Grid.prototype.expandGrid = function () { - var i, - j, - currentCellCount = this.allCells.length, - currentRowColumnCount = this.rowColumnCount, - currentXYHashMask = this.xyHashMask, - newCellCount = currentCellCount * 4, // double each dimension - newRowColumnCount = ~~Math.sqrt(newCellCount), - newXYHashMask = newRowColumnCount - 1, - allObjects = this.allObjects.slice(0), // duplicate array, not objects contained - aCell, - push = Array.prototype.push; - - // remove all objects - for (i = 0; i < allObjects.length; i++) { - this.removeObject(allObjects[i]); - } + // reset grid values, set new grid to be 4x larger than last + this.rowColumnCount = newRowColumnCount; + this.allCells = Array(this.rowColumnCount * this.rowColumnCount); + this.xyHashMask = newXYHashMask; - // reset grid values, set new grid to be 4x larger than last - this.rowColumnCount = newRowColumnCount; - this.allCells = Array(this.rowColumnCount * this.rowColumnCount); - this.xyHashMask = newXYHashMask; + // initialize new cells + this.initCells(); - // initialize new cells - this.initCells(); + // re-add all objects to grid + for (i = 0; i < allObjects.length; i++) { + this.addObject(allObjects[i]); + } + }; - // re-add all objects to grid - for (i = 0; i < allObjects.length; i++) { - this.addObject(allObjects[i]); + /** + * A cell of the grid + * + * @constructor + * @return void desc + */ + function Cell() { + this.objectContainer = []; + this.neighborOffsetArray; + this.occupiedCellsIndex = null; + this.allCellsIndex = null; } - }; - - /** - * A cell of the grid - * - * @constructor - * @return void desc - */ - function Cell() { - this.objectContainer = []; - this.neighborOffsetArray; - this.occupiedCellsIndex = null; - this.allCellsIndex = null; - } - - //--------------------------------------------------------------------- - // EXPORTS - //--------------------------------------------------------------------- - - root["HSHG"] = HSHG; - HSHG._private = { - Grid: Grid, - Cell: Cell, - testAABBOverlap: testAABBOverlap, - getLongestAABBEdge: getLongestAABBEdge, - }; -})(this); + + //--------------------------------------------------------------------- + // EXPORTS + //--------------------------------------------------------------------- + + root["HSHG"] = HSHG; + HSHG._private = { + Grid: Grid, + Cell: Cell, + testAABBOverlap: testAABBOverlap, + getLongestAABBEdge: getLongestAABBEdge, + }; +})(this); \ No newline at end of file diff --git a/server/lib/random.js b/server/lib/random.js index f8f61c765..f0556a927 100644 --- a/server/lib/random.js +++ b/server/lib/random.js @@ -100,4 +100,4 @@ exports.nameLists = { exports.chooseBotName = () => exports.choose(exports.nameLists.bots); -exports.chooseBossName = code => code in exports.nameLists ? exports.choose(exports.nameLists[code]) : undefined; \ No newline at end of file +exports.chooseBossName = (code, amount) => code in exports.nameLists ? exports.chooseN(exports.nameLists[code], amount) : []; \ No newline at end of file diff --git a/server/lib/util.js b/server/lib/util.js index 2a0a8d0ee..7c2e46d15 100644 --- a/server/lib/util.js +++ b/server/lib/util.js @@ -16,6 +16,8 @@ exports.getDirection = (p1, p2) => Math.atan2(p2.y - p1.y, p2.x - p1.x) exports.clamp = (value, min, max) => Math.min(Math.max(value, min), max) +exports.lerp = (value, target, scale) => value + scale * (target - value) + exports.listify = list => { if (list.length === 0) return '' if (list.length === 1) return list[0] @@ -49,10 +51,15 @@ exports.signedSqrt = x => Math.sign(x) * Math.sqrt(Math.abs(x)) exports.getJackpot = x => x > 39450 ? Math.pow(x - 26300, 0.85) + 26300 : x / 1.5 -exports.serverStartTime = Date.now() +exports.serverStartTime = Date.now(); + +exports.rounder = (val, precision = 6) => { + if (Math.abs(val) < 0.00001) val = 0; + return +val.toPrecision(precision); +} -// Get a better logging function -exports.time = () => Date.now() - exports.serverStartTime +// backwards compatability +exports.time = performance.now.bind(performance); // create a custom timestamp format for log statements exports.log = text => console.log("[" + (exports.time() / 1000).toFixed(3) + "]: " + text) @@ -78,4 +85,37 @@ exports.forcePush = (object, property, ...items) => { } else { object[property] = [...items]; } -} \ No newline at end of file +} + +// Performance savings for define() +exports.flattenDefinition = (output, definition) => { + definition = ensureIsClass(definition); + + if (definition.PARENT) { + if (!Array.isArray(definition.PARENT)) { + exports.flattenDefinition(output, definition.PARENT); + } else for (let parent of definition.PARENT) { + exports.flattenDefinition(output, parent); + } + } + + for (let key in definition) { + // Skip parents + if (key === "PARENT") { + continue; + } + // Handle body stats (prevent overwriting of undefined stats) + if (key === "BODY") { + let body = definition.BODY; + if (!output.BODY) output.BODY = {}; + for (let stat in body) { + output.BODY[stat] = body[stat]; + } + continue; + } + // Handle other properties + output[key] = definition[key]; + } + + return output; +}; \ No newline at end of file diff --git a/server/modules/debug/logs.js b/server/modules/debug/logs.js index 3923156ab..10d0344bd 100644 --- a/server/modules/debug/logs.js +++ b/server/modules/debug/logs.js @@ -1,90 +1,49 @@ -// The two basic functions -function set(obj) { - obj.time = util.time(); -} - -function mark(obj) { - obj.data.push(util.time() - obj.time); -} - -function record(obj) { - let o = util.averageArray(obj.data); - obj.data = []; - return o; -} - -function sum(obj) { - let o = util.sumArray(obj.data); - obj.data = []; - return o; -} - -function tally(obj) { - obj.count++; -} - -function count(obj) { - let o = obj.count; - obj.count = 0; - return o; -} - -let logger = function() { - let internal = { - data: [], - time: util.time(), - count: 0, - }; - // Return the new logger - return { - set: () => set(internal), - mark: () => mark(internal), - record: () => record(internal), - sum: () => sum(internal), - count: () => count(internal), - tally: () => tally(internal), - }; -}; -let logs = { - entities: logger(), - collide: logger(), - network: logger(), - minimap: logger(), - misc2: logger(), - misc3: logger(), - physics: logger(), - life: logger(), - selfie: logger(), - master: logger(), - activation: logger(), - loops: logger(), -}; - -class LagLogger { +class Logger { constructor() { - this.startTime = 0; - this.endTime = 0; - this.totalTime = 0; - this.history = []; + this.logTimes = []; + this.trackingStart = performance.now(); + this.tallyCount = 0; + } + startTracking() { + this.trackingStart = performance.now(); } - set() { - this.startTime = Date.now(); + endTracking() { + this.logTimes.push(performance.now() - this.trackingStart); } - mark() { - this.endTime = Date.now(); - this.totalTime = this.endTime - this.startTime; - this.history.push({ - at: new Date(), - time: this.totalTime - }); - if (this.history.length > 10) this.history.shift(); + averageLogTimes() { + let average = util.averageArray(this.logTimes); + this.logTimes = []; + return average; } - get sum() { - return this.history; + sumLogTimes() { + let sum = util.sumArray(this.logTimes); + this.logTimes = []; + return sum; + } + tally() { + this.tallyCount++; + } + getTallyCount() { + let tally = this.tallyCount; + this.tallyCount = 0; + return tally; } } -module.exports = { - logs, - LagLogger -}; \ No newline at end of file +let logs = { + entities: new Logger(), + collide: new Logger(), + network: new Logger(), + minimap: new Logger(), + misc2: new Logger(), + misc3: new Logger(), + physics: new Logger(), + life: new Logger(), + selfie: new Logger(), + master: new Logger(), + activation: new Logger(), + loops: new Logger(), + gamemodeLoop: new Logger(), +}; + +module.exports = { logs }; \ No newline at end of file diff --git a/server/modules/debug/speedLoop.js b/server/modules/debug/speedLoop.js index c24120637..03fc68046 100644 --- a/server/modules/debug/speedLoop.js +++ b/server/modules/debug/speedLoop.js @@ -1,22 +1,27 @@ let fails = 0; const speedcheckloop = () => { - let activationtime = logs.activation.sum(), - collidetime = logs.collide.sum(), - movetime = logs.entities.sum(), - playertime = logs.network.sum(), - maptime = logs.minimap.sum(), - physicstime = logs.physics.sum(), - lifetime = logs.life.sum(), - selfietime = logs.selfie.sum(); - let sum = logs.master.record(); - let loops = logs.loops.count(), - active = logs.entities.count(); + let activationtime = logs.activation.sumLogTimes(), + collidetime = logs.collide.sumLogTimes(), + movetime = logs.entities.sumLogTimes(), + playertime = logs.network.sumLogTimes(), + maptime = logs.minimap.sumLogTimes(), + physicstime = logs.physics.sumLogTimes(), + lifetime = logs.life.sumLogTimes(), + selfietime = logs.selfie.sumLogTimes(); + let sum = logs.master.averageLogTimes(); + let loops = logs.loops.getTallyCount(), + active = logs.entities.getTallyCount(); global.fps = (1000 / sum).toFixed(2); - if (sum > 1000 / c.runSpeed / 30) { + for (let e of entities) { + if (e.isPlayer && e.socket) { // give the debug info i guess. + e.socket.talk("svInfo", Config.gameModeName, (sum).toFixed(1)); + } + } + if (sum > 1000 / Config.runSpeed / 30) { //fails++; - if (c.LOGS) { + if (Config.LOGS) { util.warn('~~ LAST SERVER TICK TOOK TOO LONG TO CALCULATE ~~'); - util.warn('~~ LOOPS: ' + loops + '. ENTITIES: ' + entities.length + '//' + Math.round(active / loops) + '. VIEWS: ' + views.length + '. BACKLOGGED :: ' + (sum * c.runSpeed * 3).toFixed(3) + '%! ~~'); + util.warn('~~ LOOPS: ' + loops + '. ENTITIES: ' + entities.length + '//' + Math.round(active / loops) + '. VIEWS: ' + views.length + '. BACKLOGGED :: ' + (sum * Config.runSpeed * 3).toFixed(3) + '%! ~~'); util.warn('Total activation time: ' + activationtime); util.warn('Total collision time: ' + collidetime); util.warn('Total cycle time: ' + movetime); diff --git a/server/modules/definitions/addons/amongus.js b/server/modules/definitions/addons/amongus.js new file mode 100644 index 000000000..7f675df15 --- /dev/null +++ b/server/modules/definitions/addons/amongus.js @@ -0,0 +1,108 @@ + //UNCOMMENT LINE 11 TO DISABLE + //return + console.log('[AMONG US CREWMATE] Addon running'); + + Class.OSAmongus_basebody = { + PARENT: ["genericTank"], + LABEL: "", + SHAPE: "M -0.731 1.979 Q -1.279 -2.215 -0.005 -2.244 Q 1.635 -2.31 1.485 0 Q 1.415 1.801 0.992 1.822 Q 0.599 1.847 0.591 1.342 Q 0.888 1.29 1.078 1.056 Q 0.551 1.132 0.03 1.073 L -0.008 1.871 Q -0.304 2.162 -0.727 1.982", + } + Class.OSAmongus_basebodyshadow = { + PARENT: ["genericTank"], + LABEL: "", + BORDERLESS: true, + SHAPE: "M 0.431 0.765 C -0.809 0.861 -0.8 -0.981 -0.573 -1.968 C -0.451 -2.449 1.348 -2.396 1.331 -1.051 C 1.829 0.495 0.85 0.826 0.423 0.774", + } + Class.OSAmongus_backpack= { + PARENT: ["genericTank"], + LABEL: "", + SHAPE: "M-.6.9-1 1Q-1.615 1.258-1.567-.014-1.581-1.214-1.094-1.014L-1.095-1.009-.7-.9", + } + Class.OSAmongus_backpackshadow= { + PARENT: ["genericTank"], + BORDERLESS: true, + LABEL: "", + SHAPE: "M -1.11 -0.781 C -1.125 -0.812 -1.481 -0.806 -1.532 -0.734 C -1.507 -0.874 -1.517 -1.033 -1.316 -1.033 C -1.073 -1.069 -1.053 -1.028 -1.11 -0.791", + } + Class.OSAmongus_visor= { + PARENT: ["genericTank"], + LABEL: "", + SHAPE: "M 0.004 -1.131 C -0.007 -0.231 1.655 -0.524 1.649 -1.097 C 1.741 -1.807 0.027 -1.962 -0.001 -1.131", + } + Class.OSAmongus_visorshadow= { + PARENT: ["genericTank"], + BORDERLESS: true, + LABEL: "", + SHAPE: "M 0.178 -1.402 C 0.05 -0.851 1.667 -0.668 1.642 -1.374 C 1.654 -1.609 0.251 -1.785 0.175 -1.411", + } + Class.OSAmongus_visorhighlight= { + PARENT: ["genericTank"], + BORDERLESS: true, + LABEL: "", + SHAPE: "M 0.178 -1.402 C 0.05 -0.851 1.667 -0.668 1.642 -1.374 C 1.654 -1.609 0.251 -1.785 0.175 -1.411", + } + Class.OSAmongus_crewmatebase= { + PARENT: ["genericTank"], + LABEL: "AMONG US", + SHAPE: "M 0.178", + COLOR: 12, + TURRETS:[ + { + POSITION: [10, 0, 0, 0, 0, 1], + TYPE: ["OSAmongus_backpack", {MIRROR_MASTER_ANGLE: true, COLOR: {BASE: -1, BRIGHTNESS_SHIFT: -15,}}], + }, + { + POSITION: [10, 0, 0, 0, 0, 1], + TYPE: ["OSAmongus_backpackshadow", {MIRROR_MASTER_ANGLE: true, COLOR: {BASE: -1, BRIGHTNESS_SHIFT: 0,}}], + }, + { + POSITION: [10, 0, 0, 0, 0, 1], + TYPE: ["OSAmongus_basebody", {MIRROR_MASTER_ANGLE: true, COLOR: {BASE: -1, BRIGHTNESS_SHIFT: -15,}}], + }, + { + POSITION: [10, 0, 0, 0, 0, 1], + TYPE: ["OSAmongus_basebodyshadow", {MIRROR_MASTER_ANGLE: true, COLOR:{BASE: -1, BRIGHTNESS_SHIFT: 0,}}], + }, + { + POSITION: [10, 0, 0, 0, 0, 1], + TYPE: ["OSAmongus_visor", {MIRROR_MASTER_ANGLE: true, COLOR:{BASE: 10, BRIGHTNESS_SHIFT: -15,}}], + }, + { + POSITION: [10, 0, 0, 0, 0, 1], + TYPE: ["OSAmongus_visorshadow", {MIRROR_MASTER_ANGLE: true, COLOR:{BASE: 10, BRIGHTNESS_SHIFT: 0,}}], + }, + { + POSITION: [5, 2.75, -4, 0, 0, 1], + TYPE: ["OSAmongus_visorhighlight", {MIRROR_MASTER_ANGLE: true, COLOR:{BASE: 8, BRIGHTNESS_SHIFT: 0,}}], + }, + ], + } + Class.addons.UPGRADES_TIER_0.push("OSAmongus_crewmatebase"); + Class.OSAmongus_crewmatebase.UPGRADES_TIER_0 = []; + const colors = [ + "red", + "orange", + "gold", + "brown", + "green", + "blue", + "cyan", + "teal", + "pink", + "purple", + "magenta", + "veryLightGray", + "darkGray", + "animatedLesbian", + "animatedTrans", + "rainbow", + ] + for (let i = 0; i < colors.length; i++) { + Class["OSAmongus_" + colors[i] + "crewmate"] = { + PARENT: ["OSAmongus_crewmatebase"], + COLOR: colors[i] + + }; + + Class.OSAmongus_crewmatebase.UPGRADES_TIER_0.push("OSAmongus_" + colors[i] + "crewmate"); +} \ No newline at end of file diff --git a/server/modules/definitions/addons/basicChatModeration.js b/server/modules/definitions/addons/basicChatModeration.js index 5f2c04fe1..3214ada1a 100644 --- a/server/modules/definitions/addons/basicChatModeration.js +++ b/server/modules/definitions/addons/basicChatModeration.js @@ -6,46 +6,46 @@ let recent = {}, ratelimit = 3, decay = 10_000; -module.exports = ({ Events }) => { - Events.on('chatMessage', ({ message, socket, preventDefault }) => { - let perms = socket.permissions, - id = socket.player.body.id; - - // They are allowed to spam ANYTHING they want INFINITELY. - if (perms && perms.allowSpam) return; - - - // If they're talking too much, they can take a break. - // Fortunately, this returns false if 'recent[id] is 'undefined'. - if (recent[id] >= ratelimit) { - preventDefault(); // 'preventDefault()' prevents the message from being sent. - socket.talk('m', c.MESSAGE_DISPLAY_TIME, 'Please slow down!'); - return; - } - - // The more messages they send, the higher this counts up. +Events.on('chatMessage', ({ message, socket, preventDefault, setMessage }) => { + let perms = socket.permissions, + id = socket.player.body.id; + + // Here we block out some very bad and banned word by replacing it with asterisks, + // then we set the message that will be seen by others to that filtered message. + setMessage(message.replaceAll('someverybadandbannedword', '************************')); + + // They are allowed to spam ANYTHING they want INFINITELY. + if (perms && perms.allowSpam) return; + + // If they're talking too much, they can take a break. + // Fortunately, this returns false if 'recent[id] is 'undefined'. + if (recent[id] >= ratelimit) { + preventDefault(); // 'preventDefault()' prevents the message from being sent. + socket.talk('m', Config.MESSAGE_DISPLAY_TIME, 'Please slow down!'); + return; + } + + // The more messages they send, the higher this counts up. + if (!recent[id]) { + recent[id] = 0; + } + recent[id]++; + + // Let it decay so they can talk later. + setTimeout(() => { + recent[id]--; + + // memoree leak NOes! if (!recent[id]) { - recent[id] = 0; - } - recent[id]++; - - // Let it decay so they can talk later. - setTimeout(() => { - recent[id]--; - - // memoree leak NOes! - if (!recent[id]) { - delete recent[id]; - } - }, decay); - - // If message above the character limit, lets stop that from getting through - if (message.length > 256) { - preventDefault(); - socket.talk('m', c.MESSAGE_DISPLAY_TIME, 'Too long!') + delete recent[id]; } - }); + }, decay); - console.log('[basicChatModeration] Loaded spam prevention!'); -}; + // If message above the character limit, lets stop that from getting through + if (message.length > 256) { + preventDefault(); + socket.talk('m', Config.MESSAGE_DISPLAY_TIME, 'Too long!') + } +}); +console.log('[basicChatModeration] Loaded spam prevention!'); \ No newline at end of file diff --git a/server/modules/definitions/addons/cooper.js b/server/modules/definitions/addons/cooper.js new file mode 100644 index 000000000..1a2a5c161 --- /dev/null +++ b/server/modules/definitions/addons/cooper.js @@ -0,0 +1,30 @@ +const { combineStats, makeAuto, makeOver, makeDeco, makeGuard, makeBird, makeCeption } = require('../facilitators.js'); +const { base, statnames, dfltskl, smshskl } = require('../constants.js'); +require('../groups/generics.js'); +const g = require('../gunvals.js'); + +Class.sandwichdeco = makeDeco("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Untitled%20Project%20(22).jpg?v=1708356424097"); + +Class.A = { + PARENT: "genericTank", + LABEL: "ChickenSandwichTank", + DANGER: 7, + GUNS: [ + { + POSITION: [19, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.single, g.op]), + TYPE: "bullet" + } + }, + { + POSITION: [5.5, 8, -1.8, 6.5, 0, 0, 0] + } + ], + TURRETS: [{ + POSITION: [11, 0, 0, 0, 0, 99], + TYPE: "sandwichdeco" + }] +}; + +Class.addons.UPGRADES_TIER_0.push("A") \ No newline at end of file diff --git a/server/modules/definitions/addons/defsReloadCommand.js b/server/modules/definitions/addons/defsReloadCommand.js new file mode 100644 index 000000000..4ae7f60a2 --- /dev/null +++ b/server/modules/definitions/addons/defsReloadCommand.js @@ -0,0 +1,73 @@ +let lastReloadTime = 1; +const validCommands = ['**reload definitions', '**reload defs', '**redefs']; + +Events.on('chatMessage', ({ message, socket, preventDefault }) => { + let perms = socket.permissions; + // No perms restriction + if (!perms || !perms.administrator) return; + + // Valid command checker + if (!validCommands.includes(message)) return; + + // Prevent message from sending + preventDefault(); + + // Rate limiter for anti-lag + let time = performance.now(); + let sinceLastReload = time - lastReloadTime; + if (sinceLastReload < 5000) { + socket.talk('m', Config.MESSAGE_DISPLAY_TIME, `Wait ${Math.floor((5000 - sinceLastReload) / 100) / 10} seconds and try again.`); + return; + } + + // Reload the definitions folder --- + lastReloadTime = time; + + // Remove function so all for(let x in arr) loops work + delete Array.prototype.remove; + + // Purge Class + Class = {}; + + // Purge all cache entries of every file in ../definitions + for (let file in require.cache) { + if (!file.includes('definitions') || file.includes(__filename)) continue; + delete require.cache[file]; + } + + // Load all definitions + require('../combined.js'); + + // Put the removal function back + Array.prototype.remove = function (index) { + if (index === this.length - 1) return this.pop(); + let r = this[index]; + this[index] = this.pop(); + return r; + }; + + // Redefine all tanks and bosses + for (let entity of entities) { + // If it's a valid type and it's not a turret + if (!['tank', 'miniboss', 'food'].includes(entity.type)) continue; + if (entity.bond) continue; + + let entityDefs = JSON.parse(JSON.stringify(entity.defs)); + // Save color to put it back later + let entityColor = entity.color.compiled; + + // Redefine all properties and update values to match + entity.upgrades = []; + entity.define(entityDefs); + entity.destroyAllChildren(); + entity.skill.update(); + entity.syncTurrets(); + entity.refreshBodyAttributes(); + entity.color.interpret(entityColor); + } + + // Tell the command sender + socket.talk('m', Config.MESSAGE_DISPLAY_TIME, "Successfully reloaded all definitions.") +}); + +console.log('[defsReloadCommand.js] Loaded hot definitions reloader.'); \ No newline at end of file diff --git a/server/modules/definitions/addons/dreadv1.js b/server/modules/definitions/addons/dreadv1.js index 1d59d6a96..54e0d8af5 100644 --- a/server/modules/definitions/addons/dreadv1.js +++ b/server/modules/definitions/addons/dreadv1.js @@ -1,109 +1,285 @@ -const { combineStats, makeAuto, weaponArray } = require('../facilitators.js'); -const { gunCalcNames, smshskl, base } = require('../constants.js'); +const { combineStats, makeAuto, weaponArray, makeTurret } = require('../facilitators.js'); +const { smshskl, base, basePolygonDamage, basePolygonHealth } = require('../constants.js'); const g = require('../gunvals.js'); const dreadnoughtBody = { - SPEED: base.SPEED * 0.5, - HEALTH: base.HEALTH * 5, + SPEED: base.SPEED * 0.6, + HEALTH: base.HEALTH * 4, DAMAGE: base.DAMAGE * 2.5, - PENETRATION: base.PENETRATION * 2, SHIELD: base.SHIELD * 2.5, - FOV: base.FOV * 1.4, + FOV: base.FOV * 1.25, DENSITY: base.DENSITY * 6, + REGEN: base.REGEN, }; g.dreadv1Generic = { - health: 1.4, + damage: 1.35, range: 0.8, recoil: 0, } +g.dreadv1Sniper = { + speed: 1.07, + maxSpeed: 1.07, + health: 1.2, + damage: 1.1, + reload: 1.13, + density: 1.8, + pen: 1.05, + resist: 1.2, + range: 0.8, +} g.dreadv1Slow = { - health: 1.5, + health: 1.3, + damage: 1.25, + resist: 1.1, speed: 0.65, maxSpeed: 0.65, -}; +} g.dreadv1Drone = { - health: 1.3, - speed: 0.9, - maxSpeed: 0.9, - reload: 1.4, - size: 1.2 + health: 1.1, + speed: 0.77, + maxSpeed: 0.77, + reload: 1.65, + size: 1.2, + recoil: 0, } g.dreadv1Trap = { - range: 0.9, + range: 1.3, shudder: 0.2, - reload: 1.75 + speed: 0.95, + reload: 2.8, + damage: 1.45, + health: 1.35, + resist: 1.1, + size: 1.25, } // Comment out the line below to enable this addon, uncomment it to disable this addon. -//return console.log('--- Dreadnoughts v1 addon [dreadv1.js] is disabled. See lines 32-33 to enable it. ---'); +// return console.log('--- Dreadnoughts v1 addon [dreadv1.js] is disabled. See lines 32-33 to enable it. ---'); // Set the below variable to true to enable the Medicare and Medicaid healing bodies. const enableHealers = true; -// Misc -Class.genericDreadnought1 = { - PARENT: "genericTank", - BODY: dreadnoughtBody, +// Food +Class.hexagonOfficialV1 = { + PARENT: 'food', + COLOR: 'magenta', + LABEL: "Hexagon", + BODY: { + DAMAGE: 2 * basePolygonDamage, + DENSITY: 80, + HEALTH: 600 * basePolygonHealth, + RESIST: Math.pow(1.25, 3), + PENETRATION: 1.1, + SHIELD: 40 * basePolygonHealth, + ACCELERATION: 0.0025 + }, + VALUE: 21000, SHAPE: 6, + SIZE: 70, + DRAW_HEALTH: true, + GIVE_KILL_MESSAGE: true, +} +Class.heptagonOfficialV1 = { + PARENT: 'food', + COLOR: 'green', + LABEL: "Heptagon", + BODY: { + DAMAGE: 2 * basePolygonDamage, + DENSITY: 80, + HEALTH: 750 * basePolygonHealth, + RESIST: Math.pow(1.25, 3), + PENETRATION: 1.1, + SHIELD: 50 * basePolygonHealth, + ACCELERATION: 0.0025 + }, + VALUE: 28000, + SHAPE: 7, + SIZE: 80, + DRAW_HEALTH: true, + GIVE_KILL_MESSAGE: true, +} +Class.octagonOfficialV1 = { + PARENT: 'food', COLOR: 'hexagon', - SIZE: 22.5, - SKILL_CAP: Array(10).fill(smshskl+3), - REROOT_UPGRADE_TREE: "dreadOfficialV1", -} -Class.mechanismMainTurret = { - PARENT: "genericTank", - LABEL: "Turret", - CONTROLLERS: ["nearestDifferentMaster"], - INDEPENDENT: true, + LABEL: "Octagon", BODY: { - FOV: 0.8, - }, - COLOR: 16, - GUNS: [{ - POSITION: [22, 10, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.power, { recoil: 1.4 }, g.turret, { health: 1.8, speed: 0.4, maxSpeed: 0.4, reload: 0.5 }]), - TYPE: "bullet" + DAMAGE: 2 * basePolygonDamage, + DENSITY: 80, + HEALTH: 900 * basePolygonHealth, + RESIST: Math.pow(1.25, 3), + PENETRATION: 1.1, + SHIELD: 60 * basePolygonHealth, + ACCELERATION: 0.0025 + }, + VALUE: 35000, + SHAPE: 8, + SIZE: 90, + DRAW_HEALTH: true, + GIVE_KILL_MESSAGE: true, +} +Class.nonagonOfficialV1 = { + PARENT: 'food', + COLOR: 'white', + LABEL: "Nonagon", + BODY: { + DAMAGE: 2 * basePolygonDamage, + DENSITY: 80, + HEALTH: 1050 * basePolygonHealth, + RESIST: Math.pow(1.25, 3), + PENETRATION: 1.1, + SHIELD: 70 * basePolygonHealth, + ACCELERATION: 0.0025 + }, + VALUE: 42000, + SHAPE: 9, + SIZE: 100, + DRAW_HEALTH: true, + GIVE_KILL_MESSAGE: true, +} + +// Map elements +function portalRings(color = '#1c3766') { + return [ + { + POSITION: [22, 0, 0, 0, 1], + TYPE: ['portalRing1OfficialV1', {COLOR: color}] + }, { + POSITION: [20.5, 0, 0, -45, 1], + TYPE: ['portalRing2OfficialV1', {COLOR: color}] + }, { + POSITION: [20.5, 0, 0, 135, 1], + TYPE: ['portalRing3OfficialV1', {COLOR: color}] + }, { + POSITION: [21.2, 0, 0, 0, 1], + TYPE: ['portalRing4OfficialV1', {COLOR: color}] } - }] + ] } -Class.automationMainTurret = { - PARENT: "genericTank", - LABEL: "Turret", - CONTROLLERS: ["onlyAcceptInArc", "nearestDifferentMaster"], - INDEPENDENT: true, +Class.portalRing1OfficialV1 = { + SHAPE: "M -1 0 A 1 1 90 0 0 1 0 L 0.7 0 A 0.7 0.7 90 0 1 -0.7 0 Z M -1 0 A 1 1 90 0 1 1 0 L 0.7 0 A 0.7 0.7 90 0 0 -0.7 0 Z", + COLOR: "#1c3766", + BORDERLESS: true, +} +Class.portalRing2OfficialV1 = { + SHAPE: "M -0.707 0.707 A 1 1 0 0 1 -0.707 -0.707 A 1 1.225 0 0 0 -0.707 0.707 Z", + COLOR: {BASE: "#1c3766", BRIGHTNESS_SHIFT: 16, SATURATION_SHIFT: 0.7}, + BORDERLESS: true, +} +Class.portalRing3OfficialV1 = { + SHAPE: "M -0.5 0.866 A 1 1 0 0 1 -0.5 -0.866 A 1 1.1 0 0 0 -0.5 0.866 Z", + COLOR: {BASE: "#1c3766", BRIGHTNESS_SHIFT: -6, SATURATION_SHIFT: 1.1}, + BORDERLESS: true, +} +Class.portalRing4OfficialV1 = { + SHAPE: "M -0.92 0 A 0.92 0.92 90 0 0 0.92 0 L 0.84 0 A 0.84 0.84 90 0 1 -0.84 0 Z M -0.92 0 A 0.92 0.92 90 0 1 0.92 0 L 0.84 0 A 0.84 0.84 90 0 0 -0.84 0 Z", + COLOR: {BASE: "#1c3766", BRIGHTNESS_SHIFT: 7, SATURATION_SHIFT: 0.9}, + BORDERLESS: true, +} +Class.portalOfficialV1 = { + LABEL: "", + TYPE: 'portal', BODY: { - FOV: 0.8, + HEALTH: 1e10, + SHIELD: 1e10, + REGEN: 1e10, + DAMAGE: 0, + PENETRATION: 1e10, + DENSITY: 1e10, + RANGE: 2000, }, - COLOR: 16, - GUNS: [{ - POSITION: [22, 10, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.power, { recoil: 1.4 }, g.turret, { health: 1.55, speed: 0.4, maxSpeed: 0.4, reload: 0.5 }]), - TYPE: "bullet" + ALWAYS_ACTIVE: true, + HITS_OWN_TYPE: 'never', + GIVE_KILL_MESSAGE: false, + DRAW_HEALTH: false, + TEAM: TEAM_ROOM, + COLOR: 'pureBlack', + FACING_TYPE: 'noFacing', + SIZE: 33, + DIE_AT_RANGE: true, + INTANGIBLE: true +} +Class.spikyPortalSpikesOfficialV1 = { + SHAPE: "", + INDEPENDENT: true, + FACING_TYPE: ["spin", {speed: 0.07}], + GUNS: weaponArray({ + POSITION: [30, 8, 0.001, 0, 0, 0, 0], + PROPERTIES: {COLOR: 'egg'} + }, 5), +} +Class.spikyPortalBumpsOfficialV1 = { + SHAPE: "M 1 0 L 0.666 0.216 L 0.566 0.41 L 0.41 0.566 L 0.309 0.951 L 0 0.7 L -0.215 0.665 L -0.412 0.565 L -0.809 0.588 L -0.666 0.217 L -0.699 0.001 L -0.664 -0.217 L -0.809 -0.588 L -0.412 -0.566 L -0.217 -0.664 L 0.001 -0.699 L 0.309 -0.951 L 0.411 -0.567 L 0.565 -0.412 L 0.665 -0.215 Z", + COLOR: 'egg', + INDEPENDENT: true, + FACING_TYPE: ["spin", {speed: 0.12}], +} +Class.spikyPortalOfficialV1 = { + PARENT: 'portalOfficialV1', + TURRETS: [ + { + POSITION: [26, 0, 0, 0, 0, 0], + TYPE: "spikyPortalSpikesOfficialV1" + }, { + POSITION: [35, 0, 0, 0, 0, 0], + TYPE: "spikyPortalBumpsOfficialV1" } - }] + ], + PROPS: [ + { + POSITION: [20, 0, 0, 0, 1], + TYPE: ['egg', {COLOR: '#212121'}] + }, + ...portalRings('#1c1c1c') + ] +} +Class.bluePortalOfficialV1 = { + PARENT: 'portalOfficialV1', + PROPS: [ + { + POSITION: [20, 0, 0, 0, 1], + TYPE: ['egg', {COLOR: 'black'}] + }, + ...portalRings() + ] +} +Class.greenPortalOfficialV1 = { + PARENT: 'portalOfficialV1', + PROPS: [ + { + POSITION: [20, 0, 0, 0, 1], + TYPE: ['egg', {COLOR: 'black'}] + }, + ...portalRings('#1c6620') + ] } -Class.automationSecondaryTurret = { + +// Misc +Class.genericDreadnought1 = { PARENT: "genericTank", - LABEL: "Turret", - CONTROLLERS: ["onlyAcceptInArc", "nearestDifferentMaster"], - INDEPENDENT: true, - BODY: { - FOV: 0.8, - }, - COLOR: 16, + BODY: dreadnoughtBody, + SHAPE: 6, + COLOR: 'hexagon', + SIZE: 22.5, + SKILL_CAP: Array(10).fill(smshskl+3), + REROOT_UPGRADE_TREE: "dreadOfficialV1", +} +// Turret damage modifiers: +// Automation secondary: 1x +// Automation main: 1.6x +// Mechanism secondary: 1.12x +// Mechanism main: 1.8x +Class.dreadv1BodyTurret = makeTurret({ GUNS: [{ POSITION: [22, 10, 1, 0, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.power, { recoil: 1.4 }, g.turret, { health: 1.4, speed: 0.4, maxSpeed: 0.4, reload: 0.5 }]), + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.power, { recoil: 0.7 }, g.turret, { size: 0.8, damage: 1.05, speed: 0.4, maxSpeed: 0.4, reload: 0.7 }]), TYPE: "bullet" } }] -} +}, {limitFov: true, fov: 0.8, independent: true, label: "Turret", extraStats: []}) Class.medicareTurret = { PARENT: "genericTank", LABEL: "Turret", - CONTROLLERS: [ ["spin", {speed: 0.04}] ], + FACING_TYPE: ["spin", {speed: 0.04}], INDEPENDENT: true, COLOR: 16, GUNS: weaponArray([ @@ -126,7 +302,7 @@ Class.medicareTurret = { Class.medicaidTurret = { PARENT: "genericTank", LABEL: "Turret", - CONTROLLERS: [ ["spin", {speed: 0.04}] ], + FACING_TYPE: ["spin", {speed: 0.04}], INDEPENDENT: true, COLOR: 16, GUNS: weaponArray([ @@ -148,27 +324,13 @@ Class.medicaidTurret = { } Class.turretedTrap = makeAuto("trap", "Auto-Trap", {size: 7.5, type: 'droneAutoTurret'}); Class.turretedTrap.BODY.RECOIL_MULTIPLIER = 0; -Class.weakMinion = { - PARENT: "minion", - GUNS: [ - { - POSITION: [17, 9, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.minionGun, {health: 0.4, speed: 0.8, maxSpeed: 0.8}]), - WAIT_TO_CYCLE: true, - TYPE: "bullet", - }, - }, - ] -} // T0 Class.dreadOfficialV1 = { PARENT: "genericDreadnought1", LABEL: "Dreadnought", UPGRADE_LABEL: "Dreads V1", - LEVEL: 150, - EXTRA_SKILL: 47, + EXTRA_SKILL: 18, } // T1 @@ -177,9 +339,9 @@ Class.swordOfficialV1 = { LABEL: "Sword", UPGRADE_TOOLTIP: "Snipers", GUNS: weaponArray({ - POSITION: [19, 7, 1, 0, 0, 0, 0], + POSITION: [20, 7, 1, 0, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.dreadv1Generic]), + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.dreadv1Generic, g.dreadv1Sniper]), TYPE: "bullet" } }, 3) @@ -190,7 +352,7 @@ Class.pacifierOfficialV1 = { LABEL: "Pacifier", UPGRADE_TOOLTIP: "Bullet Spam", GUNS: weaponArray({ - POSITION: [15, 7, 1, 0, 0, 0, 0], + POSITION: [15.5, 7.25, 1, 0, 0, 0, 0], PROPERTIES: { SHOOT_SETTINGS: combineStats([g.basic, g.dreadv1Generic, g.dreadv1Slow]), TYPE: "bullet" @@ -209,7 +371,7 @@ Class.invaderOfficialV1 = { TYPE: "drone", AUTOFIRE: true, SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.drone, + STAT_CALCULATOR: "drone", WAIT_TO_CYCLE: true, MAX_CHILDREN: 4, } @@ -222,13 +384,13 @@ Class.centaurOfficialV1 = { UPGRADE_TOOLTIP: "Traps", GUNS: weaponArray([ { - POSITION: [12.5, 7, 1, 0, 0, 0, 0], + POSITION: [13, 7, 1, 0, 0, 0, 0], }, { - POSITION: [2.5, 7, 1.6, 12.5, 0, 0, 0], + POSITION: [3, 7, 1.5, 13, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.dreadv1Generic, g.dreadv1Slow, g.dreadv1Trap, {reload: 0.55}]), + SHOOT_SETTINGS: combineStats([g.trap, g.dreadv1Generic, g.dreadv1Slow, g.dreadv1Trap]), TYPE: ["trap", {HITS_OWN_TYPE: "never"} ], - STAT_CALCULATOR: gunCalcNames.trap, + STAT_CALCULATOR: "trap", }, } ], 3) @@ -241,11 +403,11 @@ Class.automationOfficialV1 = { TURRETS: [ ...weaponArray({ POSITION: [3.5, 8.25, 0, 30, 180, 1], - TYPE: "automationSecondaryTurret", + TYPE: "dreadv1BodyTurret", }, 6), { POSITION: [9, 0, 0, 0, 360, 1], - TYPE: "automationMainTurret", + TYPE: ["dreadv1BodyTurret", {GUN_STAT_SCALE: {damage: 1.6}}], } ] } @@ -258,7 +420,7 @@ Class.juggernautOfficialV1 = { HEALTH: 1.7, SHIELD: 2.2, REGEN: 1.5, - SPEED: 1.25, + SPEED: 1.1, }, TURRETS: [{ POSITION: [22, 0, 0, 0, 0, 0], @@ -282,13 +444,13 @@ Class.sabreOfficialV1 = { UPGRADE_TOOLTIP: "Assassins", GUNS: weaponArray([ { - POSITION: [26, 7, 1, 0, 0, 0, 0], + POSITION: [27, 7, 1, 0, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.assassin, g.dreadv1Generic]), + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.assassin, g.dreadv1Generic, g.dreadv1Sniper]), TYPE: "bullet" } }, { - POSITION: [4, 7, -1.4, 9, 0, 0, 0] + POSITION: [3.5, 7, -1.4, 9, 0, 0, 0] } ], 3) } @@ -298,11 +460,11 @@ Class.gladiusOfficialV1 = { UPGRADE_TOOLTIP: "Rifles", GUNS: weaponArray([ { - POSITION: [20, 9, 1, 0, 0, 0, 0] + POSITION: [17, 9, 1, 0, 0, 0, 0] }, { - POSITION: [23, 6, 1, 0, 0, 0, 0], + POSITION: [20, 6, 1, 0, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.rifle, g.dreadv1Generic]), + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.rifle, g.dreadv1Generic, g.dreadv1Sniper, {damage: 1.05}]), TYPE: "bullet" } } @@ -315,15 +477,15 @@ Class.appeaserOfficialV1 = { UPGRADE_TOOLTIP: "Machine Guns", GUNS: weaponArray([ { - POSITION: [6, 8, 1.3, 7, 0, 0, 0], + POSITION: [8.5, 8.875, 1.25, 7, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.twin, g.dreadv1Generic, g.dreadv1Slow, {speed: 0.8, maxSpeed: 0.8, range: 0.75, size: 0.55}]), + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.twin, g.dreadv1Generic, g.dreadv1Slow, {health: 1.13, shudder: 1.2, speed: 0.9, maxSpeed: 0.7, range: 0.7, size: 0.6}]), TYPE: "bullet" } }, { - POSITION: [6, 7.5, 1.2, 9, 0, 0, 0], + POSITION: [8.5, 7.875, 1.2, 9, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.twin, g.dreadv1Generic, g.dreadv1Slow, {speed: 0.8, maxSpeed: 0.8, range: 0.75, size: 0.55 * 8 / 7.5}]), + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.twin, g.dreadv1Generic, g.dreadv1Slow, {health: 1.13, shudder: 1.2, speed: 0.9, maxSpeed: 0.7, range: 0.7, size: 0.6 * 8.5 / 7.5}]), TYPE: "bullet" } } @@ -334,9 +496,9 @@ Class.peacekeeperOfficialV1 = { LABEL: "Peacekeeper", UPGRADE_TOOLTIP: "Heavy Bullets", GUNS: weaponArray({ - POSITION: [16.5, 10, 1, 0, 0, 0, 0], + POSITION: [17.5, 9, 1, 0, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.destroyer, g.dreadv1Generic, g.dreadv1Slow, {reload: 1.3, health: 1.3}]), + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.destroyer, g.dreadv1Generic, g.dreadv1Slow, {reload: 1.3, health: 1.2, range: 1.1}]), TYPE: "bullet", } }, 3) @@ -347,21 +509,21 @@ Class.diplomatOfficialV1 = { UPGRADE_TOOLTIP: "Triplets", GUNS: weaponArray([ { - POSITION: [14, 4.5, 1, 0, 2.75, 0, 0.5], + POSITION: [15.25, 4.75, 1, 0, 3, 0, 0.5], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.twin, g.triplet, g.dreadv1Generic, g.dreadv1Slow]), + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.triplet, g.dreadv1Generic, g.dreadv1Slow, {range: 0.9}]), TYPE: "bullet" } }, { - POSITION: [14, 4.5, 1, 0, -2.75, 0, 0.5], + POSITION: [15.25, 4.75, 1, 0, -3, 0, 0.5], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.twin, g.triplet, g.dreadv1Generic, g.dreadv1Slow]), + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.triplet, g.dreadv1Generic, g.dreadv1Slow, {range: 0.9}]), TYPE: "bullet" } }, { - POSITION: [15, 4.5, 1, 0, 0, 0, 0], + POSITION: [16.25, 4.75, 1, 0, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.twin, g.triplet, g.dreadv1Generic, g.dreadv1Slow]), + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.triplet, g.dreadv1Generic, g.dreadv1Slow, {range: 0.9}]), TYPE: "bullet" } } @@ -375,11 +537,11 @@ Class.inquisitorOfficialV1 = { GUNS: weaponArray({ POSITION: [7, 7.5, 1.3, 7.5, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.overseer, g.dreadv1Drone, {health: 0.95}]), + SHOOT_SETTINGS: combineStats([g.drone, g.overseer, g.dreadv1Drone, {speed: 0.95, maxSpeed: 0.95, damage: 0.93, health: 0.92}]), TYPE: "drone", AUTOFIRE: true, SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.drone, + STAT_CALCULATOR: "drone", WAIT_TO_CYCLE: true, MAX_CHILDREN: 5, } @@ -391,16 +553,17 @@ Class.assailantOfficialV1 = { UPGRADE_TOOLTIP: "Minions", GUNS: weaponArray([ { - POSITION: [13.5, 8, 1, 0, 0, 0, 0], + POSITION: [14.25, 9, 1, 0, 0, 0, 0], }, { - POSITION: [1.5, 10, 1, 13.5, 0, 0, 0], + POSITION: [1.5, 10, 1, 14.25, 0, 0, 0], PROPERTIES: { - MAX_CHILDREN: 4, - SHOOT_SETTINGS: combineStats([g.factory, g.overseer, g.dreadv1Drone, {health: 0.65, reload: 0.7}]), - TYPE: "weakMinion", - STAT_CALCULATOR: gunCalcNames.drone, + SHOOT_SETTINGS: combineStats([g.factory, g.overseer, g.dreadv1Drone, {damage: 0.45}]), + TYPE: ["minion", {GUN_STAT_SCALE: {reload: 1.5, health: 0.75, speed: 0.8, maxSpeed: 0.8}}], + STAT_CALCULATOR: "drone", AUTOFIRE: true, - SYNCS_SKILLS: true + SYNCS_SKILLS: true, + WAIT_TO_CYCLE: true, + MAX_CHILDREN: 4, } }, { POSITION: [11.5, 10, 1, 0, 0, 0, 0] @@ -417,21 +580,21 @@ Class.infiltratorOfficialV1 = { PROPERTIES: { SHOOT_SETTINGS: combineStats([g.swarm, g.carrier, { reload: 2, speed: 0.5, range: 0.9, health: 0.85}]), TYPE: "swarm", - STAT_CALCULATOR: gunCalcNames.swarm + STAT_CALCULATOR: "swarm" } }, { POSITION: [7, 6, 0.6, 5.5, -2.8, 0, 0.5], PROPERTIES: { SHOOT_SETTINGS: combineStats([g.swarm, g.carrier, { reload: 2, speed: 0.5, range: 0.9, health: 0.85}]), TYPE: "swarm", - STAT_CALCULATOR: gunCalcNames.swarm + STAT_CALCULATOR: "swarm" } }, { POSITION: [7, 6, 0.6, 8, 0, 0, 0], PROPERTIES: { SHOOT_SETTINGS: combineStats([g.swarm, g.carrier, { reload: 2, speed: 0.5, range: 0.9, health: 0.85}]), TYPE: "swarm", - STAT_CALCULATOR: gunCalcNames.swarm + STAT_CALCULATOR: "swarm" } } ], 3) @@ -443,31 +606,31 @@ Class.cerberusOfficialV1 = { UPGRADE_TOOLTIP: "Trap Spam", GUNS: weaponArray([ { - POSITION: [13.5, 2.25, 1, 0, 4, 0, 0] + POSITION: [13.25, 2.25, 1, 0, 4, 0, 0] }, { - POSITION: [1.75, 2.25, 1.7, 13.5, 4, 0, 0], + POSITION: [1.75, 2.25, 1.7, 13.25, 4, 0, 2/3], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.flankGuard, g.dreadv1Generic, g.dreadv1Slow, g.dreadv1Trap, { size: 1.3 }]), + SHOOT_SETTINGS: combineStats([g.trap, g.dreadv1Generic, g.dreadv1Slow, g.dreadv1Trap, { reload: 1.22, health: 0.67, damage: 0.7 }]), TYPE: ["trap", {HITS_OWN_TYPE: "never"} ], - STAT_CALCULATOR: gunCalcNames.trap, + STAT_CALCULATOR: "trap", }, }, { - POSITION: [13.5, 2.25, 1, 0, -4, 0, 0] + POSITION: [13.25, 2.25, 1, 0, -4, 0, 0] }, { - POSITION: [1.75, 2.25, 1.7, 13.5, -4, 0, 1/3], + POSITION: [1.75, 2.25, 1.7, 13.25, -4, 0, 1/3], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.flankGuard, g.dreadv1Generic, g.dreadv1Slow, g.dreadv1Trap, { size: 1.3 }]), + SHOOT_SETTINGS: combineStats([g.trap, g.dreadv1Generic, g.dreadv1Slow, g.dreadv1Trap, { reload: 1.22, health: 0.67, damage: 0.7 }]), TYPE: ["trap", {HITS_OWN_TYPE: "never"} ], - STAT_CALCULATOR: gunCalcNames.trap + STAT_CALCULATOR: "trap" } }, { - POSITION: [15, 3, 1, 0, 0, 0, 0] + POSITION: [14.75, 3, 1, 0, 0, 0, 0] }, { - POSITION: [2, 3, 1.7, 15, 0, 0, 2/3], + POSITION: [2, 3, 1.7, 14.75, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.flankGuard, g.dreadv1Generic, g.dreadv1Slow, g.dreadv1Trap, { size: 1.3 }]), + SHOOT_SETTINGS: combineStats([g.trap, g.dreadv1Generic, g.dreadv1Slow, g.dreadv1Trap, { reload: 1.22, health: 0.67, damage: 0.7 }]), TYPE: ["trap", {HITS_OWN_TYPE: "never"} ], - STAT_CALCULATOR: gunCalcNames.trap + STAT_CALCULATOR: "trap" } } ], 3) @@ -478,13 +641,13 @@ Class.minotaurOfficialV1 = { UPGRADE_TOOLTIP: "Blocks", GUNS: weaponArray([ { - POSITION: [13, 9, 1, 0, 0, 0, 0], + POSITION: [13, 9.5, 1, 0, 0, 0, 0], }, { - POSITION: [3, 9, 1.6, 13, 0, 0, 0], + POSITION: [3, 9.5, 1.6, 13, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.setTrap, g.dreadv1Generic, g.dreadv1Slow, g.dreadv1Trap, { reload: 1.5, health: 1.4, size: 1.3 }]), + SHOOT_SETTINGS: combineStats([g.trap, g.setTrap, g.dreadv1Generic, g.dreadv1Slow, g.dreadv1Trap, { damage: 0.9, reload: 1.55, range: 0.93, health: 1.55 }]), TYPE: ["unsetTrap", {HITS_OWN_TYPE: "never"} ], - STAT_CALCULATOR: gunCalcNames.block + STAT_CALCULATOR: "block" } } ], 3) @@ -492,15 +655,16 @@ Class.minotaurOfficialV1 = { Class.sirenOfficialV1 = { PARENT: "genericDreadnought1", LABEL: "Siren", + UPGRADE_TOOLTIP: "Auto-Traps", GUNS: weaponArray([ { - POSITION: [13, 7, -1.5, 0, 0, 0, 0], + POSITION: [6, 7, -1.5, 7, 0, 0, 0], }, { - POSITION: [2.5, 7, 1.6, 13, 0, 0, 0], + POSITION: [3, 7, 1.5, 13, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.hexaTrapper, g.dreadv1Generic, g.dreadv1Slow, g.dreadv1Trap, { size: 1.3 }]), + SHOOT_SETTINGS: combineStats([g.trap, g.dreadv1Generic, g.dreadv1Slow, g.dreadv1Trap]), TYPE: ["turretedTrap", {HITS_OWN_TYPE: "never"} ], - STAT_CALCULATOR: gunCalcNames.trap, + STAT_CALCULATOR: "trap", } } ], 3) @@ -513,11 +677,11 @@ Class.mechanismOfficialV1 = { TURRETS: [ ...weaponArray({ POSITION: [4, 8.25, 0, 30, 180, 1], - TYPE: "automationMainTurret", + TYPE: ["dreadv1BodyTurret", {GUN_STAT_SCALE: {damage: 1.12}}], }, 6), { POSITION: [9.5, 0, 0, 0, 360, 1], - TYPE: "mechanismMainTurret", + TYPE: ["dreadv1BodyTurret", {GUN_STAT_SCALE: {damage: 1.8}}], } ] } @@ -527,10 +691,10 @@ Class.behemothOfficialV1 = { LABEL: "Behemoth", UPGRADE_TOOLTIP: "Health Buff", BODY: { - HEALTH: 2.8, - SHIELD: 3.3, - REGEN: 2.1, - SPEED: 1.35, + HEALTH: 2.3, + SHIELD: 2.8, + REGEN: 1.7, + SPEED: 1.15, }, TURRETS: [{ POSITION: [23.5, 0, 0, 0, 0, 0], @@ -547,8 +711,16 @@ Class.medicaidOfficialV1 = { }] } +// Account for lower level cap +let tier1 = 10; +let tier2 = 12; +if (Config.MAX_UPGRADE_TIER < 10) { + tier1 = 0; + tier2 = 0; +} + Class.addons.UPGRADES_TIER_0.push("dreadOfficialV1"); - Class.dreadOfficialV1.UPGRADES_TIER_1 = ["swordOfficialV1", "pacifierOfficialV1", "invaderOfficialV1", "centaurOfficialV1"]; + Class.dreadOfficialV1[`UPGRADES_TIER_${tier1}`] = ["swordOfficialV1", "pacifierOfficialV1", "invaderOfficialV1", "centaurOfficialV1"]; Class.swordOfficialV1.UPGRADES_TIER_M1 = ["sabreOfficialV1", "gladiusOfficialV1"]; Class.pacifierOfficialV1.UPGRADES_TIER_M1 = ["appeaserOfficialV1", "peacekeeperOfficialV1", "diplomatOfficialV1"]; Class.invaderOfficialV1.UPGRADES_TIER_M1 = ["inquisitorOfficialV1", "assailantOfficialV1", "infiltratorOfficialV1"]; @@ -562,100 +734,74 @@ if (!enableHealers) { t1Bodies.splice(4, 1); // Remove Medicare if healers are disabled } -// Build both tiers of dreads -for (let primary of Class.dreadOfficialV1.UPGRADES_TIER_1) { - let primaryName = primary; - primary = ensureIsClass(primary); - primary.UPGRADES_TIER_1 = []; - - for (let secondary of t1Bodies) { - let secondaryName = secondary; - secondary = ensureIsClass(secondary); - - let GUNS = [], - TURRETS = [], - LABEL = primary.LABEL + "-" + secondary.LABEL, - BODY = JSON.parse(JSON.stringify(dreadnoughtBody)), - UPGRADE_TOOLTIP = (primary.UPGRADE_TOOLTIP ?? "") + " + " + (secondary.UPGRADE_TOOLTIP ?? ""); - - // Label it - if (primary.LABEL == secondary.LABEL) LABEL = primary.LABEL; - if (primary.UPGRADE_TOOLTIP == secondary.UPGRADE_TOOLTIP) UPGRADE_TOOLTIP = primary.UPGRADE_TOOLTIP; - - // Guns - if (primary.GUNS) GUNS.push(...primary.GUNS); - for (let g in secondary.GUNS) { - let POSITION = JSON.parse(JSON.stringify(secondary.GUNS[g].POSITION)), - PROPERTIES = secondary.GUNS[g].PROPERTIES; - POSITION[5] += 60; - GUNS.push({ POSITION, PROPERTIES }); +function mergeDreads(dread1, dread2, sourceDread, tier) { + let dread1Name = dread1; + let dread2Name = dread2; + + dread1 = ensureIsClass(dread1); + dread2 = ensureIsClass(dread2); + + let GUNS = [], + TURRETS = [], + LABEL = `${dread1.LABEL}-${dread2.LABEL}`, + BODY = JSON.parse(JSON.stringify(dreadnoughtBody)), + UPGRADE_TOOLTIP = `${dread1.UPGRADE_TOOLTIP ?? ""}+${dread2.UPGRADE_TOOLTIP ?? ""}`; + + // Label it + if (dread1.LABEL == dread2.LABEL) LABEL = dread1.LABEL; + if (dread1.UPGRADE_TOOLTIP == dread2.UPGRADE_TOOLTIP) UPGRADE_TOOLTIP = dread1.UPGRADE_TOOLTIP; + + // Guns + if (dread1.GUNS) GUNS.push(...dread1.GUNS); + for (let g in dread2.GUNS) { + let POSITION = JSON.parse(JSON.stringify(dread2.GUNS[g].POSITION)), + PROPERTIES = dread2.GUNS[g].PROPERTIES; + POSITION[5] += 60; + GUNS.push({ POSITION, PROPERTIES }); + } + + // Turrets + if (dread1.TURRETS) TURRETS.push(...dread1.TURRETS); + if (dread2.TURRETS) TURRETS.push(...dread2.TURRETS); + + // Body + if (dread1.BODY) { + for (let m in dread1.BODY) { + BODY[m] += (dread1.BODY[m] - dreadnoughtBody[m]) / 2; + } + } + if (dread2.BODY) { + for (let m in dread2.BODY) { + BODY[m] += (dread2.BODY[m] - dreadnoughtBody[m]) / 2; } + } - // Turrets - if (primary.TURRETS) TURRETS.push(...primary.TURRETS); - if (secondary.TURRETS) TURRETS.push(...secondary.TURRETS); - - // Body - if (primary.BODY) for (let m in primary.BODY) BODY *= primary.BODY[m]; - if (secondary.BODY) for (let m in secondary.BODY) BODY *= secondary.BODY[m]; - - // Definition name - let definitionName = primaryName + secondaryName; - - // Actually make that guy - Class[definitionName] = { - PARENT: "genericDreadnought1", - UPGRADES_TIER_2: [], - BODY, LABEL, UPGRADE_TOOLTIP, GUNS, TURRETS, - }; - Class[primaryName].UPGRADES_TIER_1.push(definitionName); - - // Compile T2 - for (let primary2 of primary.UPGRADES_TIER_M1) { - let primaryName2 = primary2; - primary2 = ensureIsClass(primary2); - - for (let secondary2 of secondary.UPGRADES_TIER_M1) { - let secondaryName = secondary2; - secondary2 = ensureIsClass(secondary2); - - let GUNS = [], - TURRETS = [], - LABEL = primary2.LABEL + "-" + secondary2.LABEL, - BODY = JSON.parse(JSON.stringify(dreadnoughtBody)), - UPGRADE_TOOLTIP = (primary2.UPGRADE_TOOLTIP ?? "") + " + " + (secondary2.UPGRADE_TOOLTIP ?? ""); - - // Label it - if (primary2.LABEL == secondary2.LABEL) LABEL = primary2.LABEL; - if (primary2.UPGRADE_TOOLTIP == secondary2.UPGRADE_TOOLTIP) UPGRADE_TOOLTIP = primary2.UPGRADE_TOOLTIP; - - // Guns - if (primary2.GUNS) GUNS.push(...primary2.GUNS); - for (let g in secondary2.GUNS) { - let POSITION = JSON.parse(JSON.stringify(secondary2.GUNS[g].POSITION)), - PROPERTIES = secondary2.GUNS[g].PROPERTIES; - POSITION[5] += 60; - GUNS.push({ POSITION, PROPERTIES }); - } - - // Turrets - if (primary2.TURRETS) TURRETS.push(...primary2.TURRETS); - if (secondary2.TURRETS) TURRETS.push(...secondary2.TURRETS); - - // Body - if (primary2.BODY) for (let m in primary2.BODY) BODY[m] *= primary2.BODY[m]; - if (secondary2.BODY) for (let m in secondary2.BODY) BODY[m] *= secondary2.BODY[m]; - - // Definition name - let definitionName2 = primaryName2 + secondaryName; - - // Actually make that guy - Class[definitionName2] = { - PARENT: "genericDreadnought1", - BODY, LABEL, UPGRADE_TOOLTIP, GUNS, TURRETS - }; - Class[definitionName].UPGRADES_TIER_2.push(definitionName2); - } + // Definition name + let definitionName = dread1Name + dread2Name; + + // Save definition to Class + Class[definitionName] = { + PARENT: "genericDreadnought1", + BODY, LABEL, UPGRADE_TOOLTIP, GUNS, TURRETS, + } + + // Save upgrade to previous dread + let upgradeLevel = `UPGRADES_TIER_${eval(`tier${tier}`)}`; + util.forcePush(Class[sourceDread], upgradeLevel, definitionName); + + // Generate new dreads recursively + if (!dread1.UPGRADES_TIER_M1 || !dread2.UPGRADES_TIER_M1) return; + + for (let upgrade1 of dread1.UPGRADES_TIER_M1) { + for (let upgrade2 of dread2.UPGRADES_TIER_M1) { + mergeDreads(upgrade1, upgrade2, definitionName, tier + 1); } } } + +// Initiate dread merge +for (let branch1 of Class.dreadOfficialV1[`UPGRADES_TIER_${tier1}`]) { + for (let branch2 of t1Bodies) { + mergeDreads(branch1, branch2, branch1, 1); + } +} \ No newline at end of file diff --git a/server/modules/definitions/addons/dreadv2.js b/server/modules/definitions/addons/dreadv2.js index 3cc2dcda4..b1446dd9d 100644 --- a/server/modules/definitions/addons/dreadv2.js +++ b/server/modules/definitions/addons/dreadv2.js @@ -1,52 +1,88 @@ -const { combineStats, addAura, makeAuto } = require('../facilitators.js'); -const { gunCalcNames, smshskl, base } = require('../constants.js'); +const { combineStats, addAura, makeAuto, weaponArray, dereference } = require('../facilitators.js'); +const { smshskl, base } = require('../constants.js'); const g = require('../gunvals.js'); const eggnoughtBody = { - SPEED: base.SPEED * 0.8, - HEALTH: base.HEALTH * 1.75, - SHIELD: base.SHIELD * 1.5, - REGEN: base.REGEN * 1.5, - FOV: base.FOV, + SPEED: base.SPEED * 0.65, + HEALTH: base.HEALTH * 1.75, + SHIELD: base.SHIELD * 2.5, + REGEN: base.REGEN * 1.25, + FOV: base.FOV, RESIST: base.RESIST, - DENSITY: base.DENSITY * 1.5, + DENSITY: base.DENSITY * 2.5, + ACCELERATION: base.ACCEL * 0.8, }; const squarenoughtBody = { - SPEED: base.SPEED * 0.675, - HEALTH: base.HEALTH * 2.5, - SHIELD: base.SHIELD * 2, - REGEN: base.REGEN * 2, - FOV: base.FOV * 0.95, + SPEED: base.SPEED * 0.6, + HEALTH: base.HEALTH * 2.5, + SHIELD: base.SHIELD * 2.7, + REGEN: base.REGEN * 1.4, + FOV: base.FOV * 0.95, RESIST: base.RESIST, - DENSITY: base.DENSITY * 2, + DENSITY: base.DENSITY * 2.75, + ACCELERATION: base.ACCEL * 0.65, }; const trinoughtBody = { - SPEED: base.SPEED * 0.55, - HEALTH: base.HEALTH * 3.5, - SHIELD: base.SHIELD * 2.5, - REGEN: base.REGEN * 2.5, - FOV: base.FOV * 0.95, + SPEED: base.SPEED * 0.55, + HEALTH: base.HEALTH * 3.5, + SHIELD: base.SHIELD * 2.9, + REGEN: base.REGEN * 1.5, + FOV: base.FOV * 0.95, RESIST: base.RESIST, - DENSITY: base.DENSITY * 2.5, + DENSITY: base.DENSITY * 3, + ACCELERATION: base.ACCEL * 0.55, }; const pentanoughtBody = { - SPEED: base.SPEED * 0.425, - HEALTH: base.HEALTH * 4.25, - SHIELD: base.SHIELD * 3, - REGEN: base.REGEN * 3, - FOV: base.FOV * 0.95, + SPEED: base.SPEED * 0.5, + HEALTH: base.HEALTH * 4.25, + SHIELD: base.SHIELD * 3.1, + REGEN: base.REGEN * 1.55, + FOV: base.FOV * 0.95, RESIST: base.RESIST, - DENSITY: base.DENSITY * 3, + DENSITY: base.DENSITY * 3.25, + ACCELERATION: base.ACCEL * 0.45, }; const hexnoughtBody = { - SPEED: base.SPEED * 0.3, - HEALTH: base.HEALTH * 5, - SHIELD: base.SHIELD * 3.5, - REGEN: base.REGEN * 3.5, - FOV: base.FOV * 0.95, + SPEED: base.SPEED * 0.45, + HEALTH: base.HEALTH * 5, + SHIELD: base.SHIELD * 3.3, + REGEN: base.REGEN * 1.6, + FOV: base.FOV * 0.95, RESIST: base.RESIST, DENSITY: base.DENSITY * 3.5, + ACCELERATION: base.ACCEL * 0.4, }; +const hpBuffBodyStats = [ + { HEALTH: 1.4, SPEED: 1.25, SHIELD: 1.4, REGEN: 1.3 }, + { HEALTH: 1.7, SPEED: 1.1, SHIELD: 1.65, REGEN: 1.45 }, + { HEALTH: 1.8, SPEED: 1.17, SHIELD: 1.9, REGEN: 1.6 }, + { HEALTH: 1.9, SPEED: 1.17, SHIELD: 2.15, REGEN: 1.7 }, +]; +const speedBuffBodyStats = [ + { HEALTH: 0.85, SPEED: 1.4, SHIELD: 0.9, REGEN: 1 }, + { HEALTH: 0.8, SPEED: 1.5, SHIELD: 0.83, REGEN: 0.9 }, + { HEALTH: 0.75, SPEED: 1.6, SHIELD: 0.75, REGEN: 0.8 }, +]; +const healerBodyStats = [ + { HEALTH: 1.1, SPEED: 1.04, SHIELD: 1.2, REGEN: 1.15 }, + { HEALTH: 1, SPEED: 0.98, SHIELD: 1.28, REGEN: 1.2 }, + { HEALTH: 0.92, SPEED: 0.94, SHIELD: 1.35, REGEN: 1.25 }, +]; + +function combineBodyStats(...bodies) { + let output = { + HEALTH: 1, + SPEED: 1, + SHIELD: 1, + REGEN: 1, + } + for (let body of bodies) { + for (let k in body) { + output[k] *= body[k]; + } + } + return output; +} // Comment out the line below to enable this addon, uncomment it to disable this addon. // return console.log('--- Dreadnoughts v2 addon [dreadv2.js] is disabled. See lines 60-61 to enable it. ---'); @@ -114,7 +150,7 @@ Class.spamAutoTurret = { { POSITION: [22, 10, 1, 0, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.flankGuard, g.autoTurret, {recoil: 0.2}]), + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.flankGuard, g.flankGuard, g.autoTurret, {recoil: 0.125}]), TYPE: "bullet", }, }, @@ -132,25 +168,23 @@ Class.supermissile = { POSITION: [14, 6, 1, 0, -2, 130, 0], PROPERTIES: { AUTOFIRE: true, - SHOOT_SETTINGS: combineStats([g.basic, g.skimmer, { reload: 0.5 }, g.lowPower, { recoil: 1.35 }, { speed: 1.3, maxSpeed: 1.3 }, { speed: 1.3, maxSpeed: 1.3 }]), + SHOOT_SETTINGS: combineStats([g.basic, g.lowPower, {reload: 1.15, speed: 1.3, maxSpeed: 1.3, recoil: 0.75}]), TYPE: ["bullet", {PERSISTS_AFTER_DEATH: true}], - STAT_CALCULATOR: gunCalcNames.thruster, + STAT_CALCULATOR: "thruster", }, - }, - { + }, { POSITION: [14, 6, 1, 0, 2, 230, 0], PROPERTIES: { AUTOFIRE: true, - SHOOT_SETTINGS: combineStats([g.basic, g.skimmer, { reload: 0.5 }, g.lowPower, { recoil: 1.35 }, { speed: 1.3, maxSpeed: 1.3 }, { speed: 1.3, maxSpeed: 1.3 }]), + SHOOT_SETTINGS: combineStats([g.basic, g.lowPower, {reload: 1.15, speed: 1.3, maxSpeed: 1.3, recoil: 0.75}]), TYPE: ["bullet", {PERSISTS_AFTER_DEATH: true}], - STAT_CALCULATOR: gunCalcNames.thruster, + STAT_CALCULATOR: "thruster", }, - }, - { + }, { POSITION: [14, 6, 1, 0, 0, 0, 0.2], PROPERTIES: { AUTOFIRE: true, - SHOOT_SETTINGS: combineStats([g.basic, g.skimmer, { reload: 0.5 }, { speed: 1.3, maxSpeed: 1.3 }, { speed: 1.3, maxSpeed: 1.3 }]), + SHOOT_SETTINGS: combineStats([g.basic, g.lowPower, g.skimmer, {reload: 1.15, speed: 1.15, maxSpeed: 1.15, recoil: 0.75}]), TYPE: ["bullet", {PERSISTS_AFTER_DEATH: true}], }, }, @@ -158,14 +192,40 @@ Class.supermissile = { }; Class.betadrone = { PARENT: "drone", - TURRETS: [ + PROPS: [ { - POSITION: [10, 0, 0, 180, 0, 1], + POSITION: [10, 0, 0, 180, 1], TYPE: ["triangle", {COLOR: -1}], }, ] } +// Auras +Class.atmosphereAuraOfficialV2 = addAura(1, 1, 0.15); +Class.coronaAuraOfficialV2 = addAura(1.15, 0.8, 0.15); +Class.trinoughtBigAura = addAura(0.7, 1.5); +Class.trinoughtSmallAura = addAura(0.7, 2.1, 0.15); +Class.pentanoughtBigAura = addAura(1.2, 1.45); +Class.pentanoughtSmallAura = addAura(1.2, 1.6, 0.15); +if (useOldPhotosphere) { + Class.photosphereSmallAuraOfficialV2 = addAura(1.25, 1.85, 0.15); + Class.photosphereBigAuraOfficialV2 = addAura(0.25, 4); +} +Class.gladiatorAuraMinionAuraOfficialV2 = addAura(0.333, 1.2); + +Class.thermosphereAuraOfficialV2 = addAura(-1, 1.5); +Class.trinoughtBigHealAura = addAura(-0.7, 1.5); +Class.trinoughtSmallHealAura = addAura(-0.7, 2.1, 0.15); +Class.pentanoughtBigHealAura = addAura(-0.8, 1.45); +Class.pentanoughtSmallHealAura = addAura(-0.8, 1.6, 0.15); +Class.gladiatorHealAuraMinionAuraOfficialV2 = addAura(-0.333, 1.2); + +// gStat turret modifiers +g.triSecondaryAuto = {reload: 1.1, health: 0.83}; +g.pentaSecondaryAuto = {reload: 1.1, health: 0.88} +g.triKilobyte = {reload: 1.05, health: 0.9, speed: 0.95, maxSpeed: 0.95}; +g.pentaMegabyte = {reload: 1.05, health: 0.95, speed: 0.9, maxSpeed: 0.9}; + // T0 Class.dreadOfficialV2 = { PARENT: "genericEggnought", @@ -176,12 +236,12 @@ Class.dreadOfficialV2 = { } Class.dreadWeaponOfficialV2 = { LABEL: "", - COLOR: 6, + COLOR: 'egg', REROOT_UPGRADE_TREE: "dreadWeaponOfficialV2", } Class.dreadBodyOfficialV2 = { LABEL: "", - COLOR: 6, + COLOR: 'egg', REROOT_UPGRADE_TREE: "dreadBodyOfficialV2", } @@ -189,111 +249,74 @@ Class.dreadBodyOfficialV2 = { Class.swordOfficialV2 = { PARENT: "genericEggnought", LABEL: "Sword", - GUNS: [], -} -for (let i = 0; i < 2; i++) { - Class.swordOfficialV2.GUNS.push( - { - POSITION: [20, 7, 1, 0, 0, 180*i, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.assassin, {reload: 0.85}]), - TYPE: "bullet", - }, + BODY: { + FOV: eggnoughtBody.FOV * 1.2 + }, + GUNS: weaponArray({ + POSITION: [20, 7, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.assassin, {reload: 1.1, health: 1.2, range: 0.65}]), + TYPE: "bullet", }, - ) -} -Class.sword2OfficialV2 = { - PARENT: "swordOfficialV2", - BATCH_UPGRADES: true, + }, 2), } Class.pacifierOfficialV2 = { PARENT: "genericEggnought", LABEL: "Pacifier", - GUNS: [], -} -for (let i = 0; i < 2; i++) { - Class.pacifierOfficialV2.GUNS.push( - { - POSITION: [15, 7, 1, 0, 0, 180*i, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, {reload: 0.8}]), - TYPE: "bullet", - }, + GUNS: weaponArray({ + POSITION: [15, 7, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, {speed: 0.9, maxSpeed: 0.9, health: 1.15}]), + TYPE: "bullet", }, - ) -} -Class.pacifier2OfficialV2 = { - PARENT: "pacifierOfficialV2", - BATCH_UPGRADES: true, + }, 2), } Class.peacekeeperOfficialV2 = { PARENT: "genericEggnought", LABEL: "Peacekeeper", - GUNS: [], -} -for (let i = 0; i < 2; i++) { - Class.peacekeeperOfficialV2.GUNS.push( - { - POSITION: [17, 9, 1, 0, 0, 180*i, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, {reload: 1.2, damage: 1.5}]), - TYPE: "bullet", - }, + GUNS: weaponArray({ + POSITION: [17, 9, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, {reload: 0.9, damage: 0.96, range: 0.9}]), + TYPE: "bullet", }, - ) -} -Class.peacekeeper2OfficialV2 = { - PARENT: "peacekeeperOfficialV2", - BATCH_UPGRADES: true, + }, 2), } Class.invaderOfficialV2 = { PARENT: "genericEggnought", LABEL: "Invader", - GUNS: [], -} -for (let i = 0; i < 2; i++) { - Class.invaderOfficialV2.GUNS.push( - { - POSITION: [5, 9, 1.2, 8, 0, 180*i, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.overseer, {reload: 0.85}]), - TYPE: "drone", - MAX_CHILDREN: 4, - AUTOFIRE: true, - SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.drone, - WAIT_TO_CYCLE: true, - }, - }, - ) -} -Class.invader2OfficialV2 = { - PARENT: "invaderOfficialV2", - BATCH_UPGRADES: true, + BODY: { + FOV: eggnoughtBody.FOV * 1.1, + SPEED: eggnoughtBody.SPEED * 0.9, + }, + GUNS: weaponArray({ + POSITION: [5, 9, 1.2, 8, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, g.overseer, {reload: 0.85, health: 1.08, maxSpeed: 0.95}]), + TYPE: "drone", + MAX_CHILDREN: 4, + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "drone", + WAIT_TO_CYCLE: true, + }, + }, 2), } Class.centaurOfficialV2 = { PARENT: "genericEggnought", LABEL: "Centaur", - GUNS: [], -} -for (let i = 0; i < 2; i++) { - Class.centaurOfficialV2.GUNS.push( + GUNS: weaponArray([ { - POSITION: [13, 7, 1, 0, 0, 180*i, 0], - }, - { - POSITION: [3, 7, 1.5, 13, 0, 180*i, 0], + POSITION: [13, 7, 1, 0, 0, 0, 0], + }, { + POSITION: [3, 7, 1.5, 13, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, {health: 2}]), + SHOOT_SETTINGS: combineStats([g.trap, g.pounder, {health: 1.15, shudder: 0.4, speed: 0.85, range: 0.85}]), TYPE: "trap", - STAT_CALCULATOR: gunCalcNames.trap, + STAT_CALCULATOR: "trap", }, }, - ) -} -Class.centaur2OfficialV2 = { - PARENT: "centaurOfficialV2", - BATCH_UPGRADES: true, + ], 2), } // T1 Bodies @@ -304,7 +327,7 @@ Class.byteTurretOfficialV2 = { { POSITION: [22, 10, 1, 0, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.autoTurret, {health: 1.2, speed: 0.8}]), + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.power, g.turret, {size: 0.9, health: 1.3, speed: 0.85, recoil: 0.8, range: 0.45}]), TYPE: "bullet", }, }, @@ -315,304 +338,259 @@ Class.byteOfficialV2 = { LABEL: "Byte", TURRETS: [ { - POSITION: [15, 0, 0, 0, 0, 1], - TYPE: 'egg', - }, - { - POSITION: [9, 0, 0, 0, 360, 1], + POSITION: [9, 0, 0, 0, 360, 2], TYPE: 'byteTurretOfficialV2', - }, + } ], + PROPS: [ + { + POSITION: [15, 0, 0, 0, 1], + TYPE: 'egg', + } + ] } -Class.atmosphereAuraOfficialV2 = addAura(1, 1, 0.15); Class.atmosphereOfficialV2 = { PARENT: "genericEggnought", LABEL: "Atmosphere", TURRETS: [ { - POSITION: [14, 0, 0, 0, 0, 1], - TYPE: 'egg', - }, - { - POSITION: [11, 0, 0, 0, 360, 1], + POSITION: [11, 0, 0, 0, 360, 2], TYPE: 'atmosphereAuraOfficialV2', }, ], + PROPS: [ + { + POSITION: [14, 0, 0, 0, 1], + TYPE: 'egg', + } + ] } Class.juggernautOfficialV2 = { PARENT: "genericEggnought", LABEL: "Juggernaut", - BODY: { - HEALTH: 1.6, - SHIELD: 1.6, - REGEN: 1.5, - SPEED: 0.8, - }, - TURRETS: [ + BODY: hpBuffBodyStats[0], + PROPS: [ { - POSITION: [15, 0, 0, 0, 0, 1], + POSITION: [15, 0, 0, 0, 1], TYPE: 'egg', - }, - { - POSITION: [24, 0, 0, 0, 0, 0], + }, { + POSITION: [24, 0, 0, 0, 0], TYPE: ['egg', {COLOR: 9}] }, ], } // T2 Weapons -Class.sabreOfficialV2 = { +Class.gladiusOfficialV2 = { PARENT: "genericSquarenought", - LABEL: "Sabre", - GUNS: [], -} -for (let i = 0; i < 4; i++) { - Class.sabreOfficialV2.GUNS.push( + LABEL: "Gladius", + BODY: { + FOV: squarenoughtBody.FOV * 1.225, + }, + GUNS: weaponArray([ { - POSITION: [24, 7, 1, 0, 0, 90*i, 0], + POSITION: [17, 8, 1, 0, 0, 0, 0], + }, { + POSITION: [19.5, 5, 1, 0, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.assassin, g.assassin, {reload: 0.85, density: 1/2}]), + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.rifle, {speed: 1.05, maxSpeed: 1.05, damage: 1.12, range: 0.65}]), TYPE: "bullet", }, }, - { - POSITION: [5, 7, -1.7, 7, 0, 90*i, 0], - }, - ) + ], 4), } -Class.gladiusOfficialV2 = { +Class.sabreOfficialV2 = { PARENT: "genericSquarenought", - LABEL: "Gladius", - GUNS: [], -} -for (let i = 0; i < 4; i++) { - Class.gladiusOfficialV2.GUNS.push( - { - POSITION: [17, 8, 1, 0, 0, 90*i, 0], - }, + LABEL: "Sabre", + BODY: { + FOV: squarenoughtBody.FOV * 1.4, + SPEED: squarenoughtBody.SPEED * 0.9, + }, + GUNS: weaponArray([ { - POSITION: [19.5, 5, 1, 0, 0, 90*i, 0], + POSITION: [24, 7, 1, 0, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.rifle, {health: 1.3}]), + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.assassin, {reload: 1.23, health: 1.33, speed: 1.1, maxSpeed: 1.1, density: 1.2, range: 0.65}]), TYPE: "bullet", }, + }, { + POSITION: [5, 7, -1.7, 7, 0, 0, 0], }, - ) + ], 4), } Class.mediatorOfficialV2 = { PARENT: "genericSquarenought", LABEL: "Mediator", - GUNS: [], -} -for (let i = 0; i < 4; i++) { - Class.mediatorOfficialV2.GUNS.push( + GUNS: weaponArray([ { - POSITION: [15, 7, 1, 0, 4.25, 90*i, 0], + POSITION: [15, 7, 1, 0, 4.25, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, {reload: 0.85}]), + SHOOT_SETTINGS: combineStats([g.basic, g.twin, {health: 1.09, range: 0.9}]), TYPE: "bullet", }, - }, - { - POSITION: [15, 7, 1, 0, -4.25, 90*i, 0.5], + }, { + POSITION: [15, 7, 1, 0, -4.25, 0, 0.5], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, {reload: 0.85}]), + SHOOT_SETTINGS: combineStats([g.basic, g.twin, {health: 1.09, range: 0.9}]), TYPE: "bullet", }, }, - ) + ], 4), } Class.negotiatorOfficialV2 = { PARENT: "genericSquarenought", LABEL: "Negotiator", - GUNS: [], -} -for (let i = 0; i < 4; i++) { - Class.negotiatorOfficialV2.GUNS.push( - { - POSITION: [9, 8, 1.4, 6, 0, 90*i, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, {size: 0.8, health: 1.3}]), - TYPE: "bullet", - }, + GUNS: weaponArray({ + POSITION: [9, 8, 1.4, 6, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, {size: 0.85, speed: 0.85, maxSpeed: 0.75, health: 1.23, range: 0.75}]), + TYPE: "bullet", }, - ) + }, 4), } Class.enforcerOfficialV2 = { PARENT: "genericSquarenought", LABEL: "Enforcer", - GUNS: [], -} -for (let i = 0; i < 4; i++) { - Class.enforcerOfficialV2.GUNS.push( - { - POSITION: [17, 9, 1, 0, 0, 90*i, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, {reload: 0.9}]), - TYPE: "bullet", - }, + GUNS: weaponArray({ + POSITION: [17, 9, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, {reload: 1.25, health: 1.37, range: 0.9}]), + TYPE: "bullet", }, - ) + }, 4), } Class.executorOfficialV2 = { PARENT: "genericSquarenought", LABEL: "Executor", - GUNS: [], -} -for (let i = 0; i < 4; i++) { - Class.executorOfficialV2.GUNS.push( + GUNS: weaponArray([ { - POSITION: [11, 6, 1, 8, 0, 90*i, 0], + POSITION: [11, 6, 1, 8, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.artillery, { speed: 0.5, maxSpeed: 0.5 }, {reload: 0.8}]), - TYPE: "missile", - STAT_CALCULATOR: gunCalcNames.sustained, + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.artillery, g.artillery, g.skimmer, {reload: 1.1, health: 1.35, speed: 0.7, maxSpeed: 0.65, range: 0.33}]), + TYPE: ["missile", {GUN_STAT_SCALE: {recoil: 0.6}}], + STAT_CALCULATOR: "sustained", }, + }, { + POSITION: [17, 9, 1, 0, 0, 0, 0], }, - { - POSITION: [17, 9, 1, 0, 0, 90*i, 0], - }, - ) + ], 4), } Class.inquisitorOfficialV2 = { PARENT: "genericSquarenought", LABEL: "Inquisitor", - GUNS: [], -} -for (let i = 0; i < 4; i++) { - Class.inquisitorOfficialV2.GUNS.push( - { - POSITION: [5, 11, 1.1, 8, 0, 90*i, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.overseer, g.overseer, {size: 1.5, reload: 0.6}]), - TYPE: "drone", - MAX_CHILDREN: 3, - AUTOFIRE: true, - SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.drone, - WAIT_TO_CYCLE: true, - }, - }, - ) + BODY: { + FOV: squarenoughtBody.FOV * 1.1, + SPEED: squarenoughtBody.SPEED * 0.9, + }, + GUNS: weaponArray({ + POSITION: [5, 11, 1.1, 8, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, g.overseer, {reload: 0.9, health: 0.8, maxSpeed: 0.9}]), + TYPE: "drone", + MAX_CHILDREN: 3, + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "drone", + WAIT_TO_CYCLE: true, + }, + }, 4), } Class.assailantMinionOfficialV2 = { PARENT: "minion", - BODY: { - SPEED: 0.5, - }, SHAPE: 4, - COLOR: 13, - GUNS: [] -} -for (let i = 0; i < 4; i++) { - Class.assailantMinionOfficialV2.GUNS.push( - { - POSITION: [15, 7.5, 1, 0, 0, 90*i, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.assassin, g.minionGun]), - WAIT_TO_CYCLE: true, - TYPE: "bullet", - }, + COLOR: "square", + GUNS: weaponArray({ + POSITION: [15, 7.5, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.assassin, g.minionGun, {reload: 1.8, health: 1.1}]), + WAIT_TO_CYCLE: true, + TYPE: "bullet", }, - ) + }, 4) } Class.assailantOfficialV2 = { PARENT: "genericSquarenought", LABEL: "Assailant", - GUNS: [], -} -for (let i = 0; i < 4; i++) { - Class.assailantOfficialV2.GUNS.push( - { - POSITION: [5, 10, 1, 10.5, 0, 90*i, 0], - }, + BODY: { + FOV: squarenoughtBody.FOV * 1.1, + SPEED: squarenoughtBody.SPEED * 0.85, + }, + GUNS: weaponArray([ { - POSITION: [1.5, 11, 1, 15, 0, 90*i, 0], + POSITION: [5, 10, 1, 10.5, 0, 0, 0], + }, { + POSITION: [1.5, 11, 1, 15, 0, 0, 0], PROPERTIES: { MAX_CHILDREN: 4, - SHOOT_SETTINGS: combineStats([g.factory, {size: 0.9, reload: 0.5}]), + SHOOT_SETTINGS: combineStats([g.factory, {size: 0.9, reload: 1.95, health: 1.3, damage: 0.65, pen: 0.9, speed: 0.8, maxSpeed: 0.8, density: 1.5}]), TYPE: "assailantMinionOfficialV2", - STAT_CALCULATOR: gunCalcNames.drone, + STAT_CALCULATOR: "drone", AUTOFIRE: true, SYNCS_SKILLS: true, MAX_CHILDREN: 2, + WAIT_TO_CYCLE: true, }, + }, { + POSITION: [12, 11, 1, 0, 0, 0, 0], }, - { - POSITION: [12, 11, 1, 0, 0, 90*i, 0], - }, - ) + ], 4), } Class.daemonOfficialV2 = { PARENT: "genericSquarenought", LABEL: "Daemon", - GUNS: [], -} -for (let i = 0; i < 4; i++) { - Class.daemonOfficialV2.GUNS.push( + GUNS: weaponArray([ { - POSITION: [11.5, 4.5, 1, 0, 4.5, 90*i, 0], - }, - { - POSITION: [2, 4.5, 1.7, 11, 4.5, 90*i, 0], + POSITION: [11.5, 4.5, 1, 0, 4.5, 0, 0], + }, { + POSITION: [2, 4.5, 1.7, 11, 4.5, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.twin, {health: 2}]), + SHOOT_SETTINGS: combineStats([g.trap, g.twin, g.pounder, {health: 0.73, speed: 0.7, maxSpeed: 0.7, range: 0.67, shudder: 0.5}]), TYPE: "trap", - STAT_CALCULATOR: gunCalcNames.trap, + STAT_CALCULATOR: "trap", }, - }, - { - POSITION: [11.5, 4.5, 1, 0, -4.5, 90*i, 0], - }, - { - POSITION: [2, 4.5, 1.7, 11, -4.5, 90*i, 0], + }, { + POSITION: [11.5, 4.5, 1, 0, -4.5, 0, 0], + }, { + POSITION: [2, 4.5, 1.7, 11, -4.5, 0, 0.5], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.twin, {health: 2}]), + SHOOT_SETTINGS: combineStats([g.trap, g.twin, g.pounder, {health: 0.73, speed: 0.7, maxSpeed: 0.7, range: 0.67, shudder: 0.5}]), TYPE: "trap", - STAT_CALCULATOR: gunCalcNames.trap, + STAT_CALCULATOR: "trap", }, }, - ) + ], 4), } Class.minotaurOfficialV2 = { PARENT: "genericSquarenought", LABEL: "Minotaur", - GUNS: [], -} -for (let i = 0; i < 4; i++) { - Class.minotaurOfficialV2.GUNS.push( - { - POSITION: [13, 7, 1, 0, 0, 90*i, 0], - }, + GUNS: weaponArray([ { - POSITION: [3.75, 7, 1.75, 13, 0, 90*i, 0], + POSITION: [13, 7, 1, 0, 0, 0, 0], + }, { + POSITION: [3.75, 7, 1.75, 13, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.setTrap, {health: 2}]), + SHOOT_SETTINGS: combineStats([g.trap, g.setTrap, g.pounder, {health: 0.85, shudder: 0.7, range: 0.67}]), TYPE: "unsetTrap", - STAT_CALCULATOR: gunCalcNames.block + STAT_CALCULATOR: "block" }, }, - ) + ], 4), } // T2 Bodies Class.automationOfficialV2 = { PARENT: "genericSquarenought", LABEL: "Automation", - TURRETS: [ - { - POSITION: [11, 0, 0, 0, 0, 1], - TYPE: ["square", {MIRROR_MASTER_ANGLE: true}], - }, - ], -} -for (let i = 0; i < 4; i++) { - Class.automationOfficialV2.TURRETS.push( + TURRETS: weaponArray({ + POSITION: [4, 9, 0, 45, 180, 2], + TYPE: ["spamAutoTurret", {GUN_STAT_SCALE: {reload: 0.9, health: 1.2}}], + }, 4), + PROPS: [ { - POSITION: [4, 9, 0, 90*i+45, 180, 1], - TYPE: "spamAutoTurret", + POSITION: [11, 0, 0, 0, 1], + TYPE: "square" }, - ) + ] } Class.kilobyteTurretOfficialV2 = { PARENT: "autoTankGun", @@ -621,7 +599,7 @@ Class.kilobyteTurretOfficialV2 = { { POSITION: [26, 10, 1, 0, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.assassin, g.autoTurret, {health: 1.2, speed: 0.8}]), + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.power, g.turret, g.assassin, {size: 0.9, health: 1.39, speed: 0.63, recoil: 1.25, range: 0.5}]), TYPE: "bullet", }, }, @@ -632,495 +610,417 @@ Class.kilobyteOfficialV2 = { LABEL: "Kilobyte", TURRETS: [ { - POSITION: [12, 0, 0, 0, 0, 1], - TYPE: ["square", {MIRROR_MASTER_ANGLE: true}], - }, - { - POSITION: [10, 0, 0, 0, 360, 1], + POSITION: [10, 0, 0, 0, 360, 2], TYPE: "kilobyteTurretOfficialV2", }, ], + PROPS: [ + { + POSITION: [12, 0, 0, 0, 1], + TYPE: "square" + }, + ] } -Class.coronaAuraOfficialV2 = addAura(1.5, 0.8, 0.15); Class.coronaOfficialV2 = { PARENT: "genericSquarenought", LABEL: "Corona", TURRETS: [ { - POSITION: [14, 0, 0, 0, 0, 1], - TYPE: ["square", {MIRROR_MASTER_ANGLE: true}], - }, - { - POSITION: [11, 0, 0, 0, 360, 1], + POSITION: [11, 0, 0, 0, 360, 2], TYPE: "coronaAuraOfficialV2", }, ], + PROPS: [ + { + POSITION: [14, 0, 0, 0, 1], + TYPE: "square" + }, + ] } -Class.thermosphereAuraOfficialV2 = addAura(-1, 1.5); Class.thermosphereOfficialV2 = { PARENT: "genericSquarenought", LABEL: "Thermosphere", + BODY: healerBodyStats[0], TURRETS: [ { - POSITION: [14, 0, 0, 0, 0, 1], - TYPE: ["square", {MIRROR_MASTER_ANGLE: true}], - }, - { - POSITION: [11, 0, 0, 0, 360, 1], + POSITION: [11, 0, 0, 0, 360, 2], TYPE: "thermosphereAuraOfficialV2", }, ], + PROPS: [ + { + POSITION: [14, 0, 0, 0, 1], + TYPE: "square" + }, + ] } Class.jumboOfficialV2 = { PARENT: "genericSquarenought", LABEL: "Jumbo", - BODY: { - HEALTH: 2.4, - SHIELD: 2.4, - REGEN: 2, - SPEED: 0.65, - }, - TURRETS: [ - { - POSITION: [15, 0, 0, 0, 0, 1], - TYPE: ['square', {MIRROR_MASTER_ANGLE: true}] - }, + BODY: hpBuffBodyStats[1], + PROPS: [ { - POSITION: [24, 0, 0, 0, 0, 0], - TYPE: ['square', {COLOR: 9, MIRROR_MASTER_ANGLE: true}] + POSITION: [15, 0, 0, 0, 1], + TYPE: 'square' + }, { + POSITION: [24, 0, 0, 0, 0], + TYPE: ['square', {COLOR: 9}] }, ], } Class.colossusTopOfficialV2 = { PARENT: "genericSquarenought", - GUNS: [], -} -for (let i = 0; i < 4; i++) { - Class.colossusTopOfficialV2.GUNS.push( - { - POSITION: [3.5, 17.5, 0.001, 9, 0, 90*i, 0], - PROPERTIES: {COLOR: 9}, - }, - ) + GUNS: weaponArray({ + POSITION: [3.5, 17.5, 0.001, 9, 0, 0, 0], + PROPERTIES: {COLOR: 9}, + }, 4), } Class.colossusBottomOfficialV2 = { PARENT: "genericSquarenought", - GUNS: [], -} -for (let i = 0; i < 4; i++) { - Class.colossusTopOfficialV2.GUNS.push( - { - POSITION: [3.5, 17.5, 0.001, 9, 0, 90*i, 0], - PROPERTIES: {COLOR: 9}, - }, - ) -} -for (let i = 0; i < 4; i++) { - Class.colossusBottomOfficialV2.GUNS.push( - { - POSITION: [4, 17.5, 0.001, 9, 0, 90*i, 0], - PROPERTIES: {COLOR: 9}, - }, - ) + GUNS: weaponArray({ + POSITION: [4, 17.5, 0.001, 9, 0, 0, 0], + PROPERTIES: {COLOR: 9}, + }, 4), } Class.colossusOfficialV2 = { PARENT: "genericSquarenought", - LABEL: "colossus", - BODY: { - SPEED: 1.75, - HEALTH: 0.65, - }, - GUNS: [], - TURRETS: [ + LABEL: "Colossus", + BODY: speedBuffBodyStats[0], + PROPS: [ { - POSITION: [13, 0, 0, 0, 0, 1], - TYPE: ['colossusTopOfficialV2', {MIRROR_MASTER_ANGLE: true}] - }, - { - POSITION: [20, 0, 0, 0, 0, 0], - TYPE: ['colossusBottomOfficialV2', {MIRROR_MASTER_ANGLE: true}] + POSITION: [13, 0, 0, 0, 1], + TYPE: 'colossusTopOfficialV2' + }, { + POSITION: [20, 0, 0, 0, 0], + TYPE: 'colossusBottomOfficialV2' }, ], } // T3 Weapons -Class.bayonetOfficialV2 = { +Class.bladeOfficialV2 = { PARENT: "genericTrinought", - LABEL: "Bayonet", - GUNS: [], -} -for (let i = 0; i < 3; i++) { - Class.bayonetOfficialV2.GUNS.push( + LABEL: "Blade", + BODY: { + FOV: trinoughtBody.FOV * 1.225, + }, + GUNS: weaponArray([ { - POSITION: [28, 7, 1, 0, 0, 120*i, 0], + POSITION: [17, 1, 1, 0, 6, 0, 0], + }, { + POSITION: [17, 1, 1, 0, -6, 0, 0], + }, { + POSITION: [18, 5, 1, 0, 3, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.assassin, g.assassin, g.assassin, {reload: 0.8, density: 2/5}]), + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.rifle, g.twin, {speed: 1.09, maxSpeed: 1.09, health: 1.09, range: 0.65}]), TYPE: "bullet", }, - }, - { - POSITION: [5, 7, -1.6, 7, 0, 120*i, 0], - }, - ) -} -Class.bladeOfficialV2 = { - PARENT: "genericTrinought", - LABEL: "Blade", - GUNS: [], -} -for (let i = 0; i < 3; i++) { - Class.bladeOfficialV2.GUNS.push( - { - POSITION: [17, 1, 1, 0, 6, 120*i, 0], - }, - { - POSITION: [17, 1, 1, 0, -6, 120*i, 0], - }, - { - POSITION: [18, 5, 1, 0, 3, 120*i, 0], + }, { + POSITION: [18, 5, 1, 0, -3, 0, 0.5], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.rifle, g.twin, {speed: 0.8, health: 1.5}]), + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.rifle, g.twin, {speed: 1.09, maxSpeed: 1.09, health: 1.09, range: 0.65}]), TYPE: "bullet", }, }, + ], 3), +} +Class.bayonetOfficialV2 = { + PARENT: "genericTrinought", + LABEL: "Bayonet", + BODY: { + FOV: trinoughtBody.FOV * 1.5, + SPEED: trinoughtBody.SPEED * 0.85, + }, + GUNS: weaponArray([ { - POSITION: [18, 5, 1, 0, -3, 120*i, 0.5], + POSITION: [28, 7, 1, 0, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.rifle, g.twin, {speed: 0.8, health: 1.5}]), + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.assassin, g.assassin, {reload: 1.05, health: 0.98, density: 0.45, range: 0.65}]), TYPE: "bullet", }, + }, { + POSITION: [5, 7, -1.6, 7, 0, 0, 0], }, - ) + ], 3), } Class.mitigatorOfficialV2 = { PARENT: "genericTrinought", LABEL: "Mitigator", - GUNS: [], -} -for (let i = 0; i < 3; i++) { - Class.mitigatorOfficialV2.GUNS.push( + GUNS: weaponArray([ { - POSITION: [10, 8, 1, 3, 5, 120*i, 0], + POSITION: [10, 8, 1, 3, 5, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, {reload: 0.85}]), + SHOOT_SETTINGS: combineStats([g.basic, g.twin, {health: 1.15, range: 0.9}]), TYPE: "bullet", }, - }, - { - POSITION: [10, 8, 1, 3, -5, 120*i, 0.5], + }, { + POSITION: [10, 8, 1, 3, -5, 0, 0.5], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, {reload: 0.85}]), + SHOOT_SETTINGS: combineStats([g.basic, g.twin, {health: 1.15, range: 0.9}]), TYPE: "bullet", }, }, - ) + ], 3), } Class.appeaserOfficialV2 = { PARENT: "genericTrinought", LABEL: "Appeaser", - GUNS: [], -} -for (let i = 0; i < 3; i++) { - Class.appeaserOfficialV2.GUNS.push( + GUNS: weaponArray([ { - POSITION: [7, 11, 1.35, 6, 0, 120*i, 0], + POSITION: [7, 11, 1.35, 6, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, {size: 0.8}]), + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.twin, g.spam, {size: 0.7, health: 1.03, range: 0.75}]), TYPE: "bullet", }, - }, - { - POSITION: [7, 10, 1.3, 8, 0, 120*i, 0], + }, { + POSITION: [7, 10, 1.3, 8, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, {size: 0.8, reload: 0.9}]), + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.twin, g.spam, {size: 0.6, health: 1.03, range: 0.75, reload: 1.05}]), TYPE: "bullet", }, }, - ) + ], 3), } Class.suppressorOfficialV2 = { PARENT: "genericTrinought", LABEL: "Suppressor", - GUNS: [], -} -for (let i = 0; i < 3; i++) { - Class.suppressorOfficialV2.GUNS.push( - { - POSITION: [16.5, 11.5, 1, 0, 0, 120*i, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.destroyer, {reload: 0.85}]), - TYPE: "bullet", - }, + GUNS: weaponArray({ + POSITION: [16.5, 11.5, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.destroyer, {reload: 1.1, health: 1.19}]), + TYPE: "bullet", }, - ) + }, 3), } Class.inhibitorOfficialV2 = { PARENT: "genericTrinought", LABEL: "Inhibitor", - GUNS: [], -} -for (let i = 0; i < 3; i++) { - Class.inhibitorOfficialV2.GUNS.push( - { - POSITION: [10, 14, -0.75, 7, 0, 120*i, 0], - }, + GUNS: weaponArray([ { - POSITION: [15, 15, 1, 0, 0, 120*i, 0], + POSITION: [10, 14, -0.75, 7, 0, 0, 0], + }, { + POSITION: [15, 15, 1, 0, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.artillery, g.skimmer, { speed: 0.5, maxSpeed: 0.5 }, {reload: 0.8}]), + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.artillery, g.artillery, g.skimmer, {reload: 1.15, health: 1.33, speed: 0.7, maxSpeed: 0.7, range: 0.4}]), TYPE: "supermissile", - STAT_CALCULATOR: gunCalcNames.sustained, + STAT_CALCULATOR: "sustained", }, }, - ) + ], 3), } Class.infiltratorOfficialV2 = { PARENT: "genericTrinought", LABEL: "Infiltrator", - GUNS: [], -} -for (let i = 0; i < 3; i++) { - Class.infiltratorOfficialV2.GUNS.push( + BODY: { + FOV: trinoughtBody.FOV * 1.1, + SPEED: trinoughtBody.SPEED * 0.9, + }, + GUNS: weaponArray([ { - POSITION: [5, 6, 1.4, 6, 5.5, 120*i, 0], + POSITION: [5, 6, 1.4, 6, 5.5, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.overseer, g.overseer, {size: 1.5, reload: 0.6}]), + SHOOT_SETTINGS: combineStats([g.drone, g.overseer, g.overseer, {maxSpeed: 0.9, size: 1.5, reload: 1.4}]), TYPE: "drone", MAX_CHILDREN: 2, AUTOFIRE: true, SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.drone, + STAT_CALCULATOR: "drone", WAIT_TO_CYCLE: true, }, - }, - { - POSITION: [5, 6, 1.4, 6, -5.5, 120*i, 0], + }, { + POSITION: [5, 6, 1.4, 6, -5.5, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.overseer, g.overseer, {size: 1.5, reload: 0.6}]), + SHOOT_SETTINGS: combineStats([g.drone, g.overseer, g.overseer, {maxSpeed: 0.9, size: 1.5, reload: 1.4}]), TYPE: "drone", MAX_CHILDREN: 2, AUTOFIRE: true, SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.drone, + STAT_CALCULATOR: "drone", WAIT_TO_CYCLE: true, }, - }, - { - POSITION: [5, 6, 1.4, 8, 0, 120*i, 0], + }, { + POSITION: [5, 6, 1.4, 8, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.overseer, g.overseer, g.pounder, {size: 2, reload: 0.4}]), + SHOOT_SETTINGS: combineStats([g.drone, g.overseer, g.overseer, g.pounder, {damage: 0.85, maxSpeed: 0.9, size: 2, reload: 1.4}]), TYPE: "betadrone", MAX_CHILDREN: 2, AUTOFIRE: true, SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.drone, + STAT_CALCULATOR: "drone", WAIT_TO_CYCLE: true, }, }, - ) + ], 3), } Class.aggressorMinionOfficialV2 = { PARENT: "minion", SHAPE: 3.5, - COLOR: 2, - BODY: { - SPEED: 0.8, - }, - GUNS: [], -} -for (let i = 0; i < 3; i++) { - Class.aggressorMinionOfficialV2.GUNS.push( - { - POSITION: [16, 8.5, 1, 0, 0, 120*i, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.assassin, { speed: 0.93, maxSpeed: 0.93 }, g.minionGun]), - WAIT_TO_CYCLE: true, - TYPE: "bullet", - }, + COLOR: "triangle", + GUNS: weaponArray({ + POSITION: [16, 8.5, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.assassin, g.minionGun, {speed: 1.06, maxSpeed: 1.06, reload: 1.75, health: 1.25}]), + WAIT_TO_CYCLE: true, + TYPE: "bullet", }, - ) + }, 3), } Class.aggressorOfficialV2 = { PARENT: "genericTrinought", LABEL: "Aggressor", - GUNS: [], -} -for (let i = 0; i < 3; i++) { - Class.aggressorOfficialV2.GUNS.push( - { - POSITION: [5, 12, 1, 10, 0, 120*i, 0], - }, + BODY: { + FOV: trinoughtBody.FOV * 1.1, + SPEED: trinoughtBody.SPEED * 0.85, + }, + GUNS: weaponArray([ { - POSITION: [1.5, 13, 1, 15, 0, 120*i, 0], + POSITION: [5, 12, 1, 10, 0, 0, 0], + }, { + POSITION: [1.5, 13, 1, 15, 0, 0, 0], PROPERTIES: { - MAX_CHILDREN: 4, - SHOOT_SETTINGS: combineStats([g.factory, {size: 0.9, reload: 0.5}]), + SHOOT_SETTINGS: combineStats([g.factory, {size: 0.9, reload: 1.8, health: 1.72, damage: 0.67, pen: 0.9, speed: 0.8, maxSpeed: 0.8, density: 1.6}]), TYPE: "aggressorMinionOfficialV2", - STAT_CALCULATOR: gunCalcNames.drone, + STAT_CALCULATOR: "drone", AUTOFIRE: true, SYNCS_SKILLS: true, MAX_CHILDREN: 2, + WAIT_TO_CYCLE: true, }, + }, { + POSITION: [12, 13, 1, 0, 0, 0, 0], }, - { - POSITION: [12, 13, 1, 0, 0, 120*i, 0], - }, - ) + ], 3), } Class.hydraOfficialV2 = { PARENT: "genericTrinought", LABEL: "Hydra", - GUNS: [], -} -for (let i = 0; i < 3; i++) { - Class.hydraOfficialV2.GUNS.push( + GUNS: weaponArray([ { - POSITION: [6, 3.5, 1, 4, 8.5, 120*i, 0], - }, - { - POSITION: [2, 3.5, 1.8, 10, 8.5, 120*i, 2/3], + POSITION: [6, 3.5, 1, 4, 8.5, 0, 0], + }, { + POSITION: [2, 3.5, 1.8, 10, 8.5, 0, 0.5], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.twin, g.pounder, { speed: 1.2 }]), + SHOOT_SETTINGS: combineStats([g.trap, g.twin, g.pounder, {shudder: 0.6, health: 0.7, speed: 1.15, maxSpeed: 1.15, range: 0.85}]), TYPE: "trap", - STAT_CALCULATOR: gunCalcNames.trap, + STAT_CALCULATOR: "trap", }, - }, - { - POSITION: [6, 3.5, 1, 4, -8.5, 120*i, 0], - }, - { - POSITION: [2, 3.5, 1.8, 10, -8.5, 120*i, 1/3], + }, { + POSITION: [6, 3.5, 1, 4, -8.5, 0, 0], + }, { + POSITION: [2, 3.5, 1.8, 10, -8.5, 0, 0.5], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.twin, g.pounder, { speed: 1.2 }]), + SHOOT_SETTINGS: combineStats([g.trap, g.twin, g.pounder, {shudder: 0.6, health: 0.7, speed: 1.15, maxSpeed: 1.15, range: 0.85}]), TYPE: "trap", - STAT_CALCULATOR: gunCalcNames.trap, + STAT_CALCULATOR: "trap", }, - }, - { - POSITION: [12, 5, 1, 0, 0, 120*i, 0], - }, - { - POSITION: [2.5, 5, 1.7, 12, 0, 120*i, 0], + }, { + POSITION: [12, 5, 1, 0, 0, 0, 0], + }, { + POSITION: [2.5, 5, 1.7, 12, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.setTrap, g.twin, g.pounder, { speed: 1.2 }]), + SHOOT_SETTINGS: combineStats([g.trap, g.setTrap, g.twin, g.pounder, {reload: 1.1, health: 1.02, speed: 0.75, maxSpeed: 0.75, range: 0.65}]), TYPE: "unsetTrap", - STAT_CALCULATOR: gunCalcNames.block + STAT_CALCULATOR: "block" }, }, - ) + ], 3), } Class.beelzebubOfficialV2 = { PARENT: "genericTrinought", LABEL: "Beelzebub", - GUNS: [], -} -for (let i = 0; i < 3; i++) { - Class.beelzebubOfficialV2.GUNS.push( - { - POSITION: [13, 10, 1, 0, 0, 120*i, 0], - }, + GUNS: weaponArray([ { - POSITION: [3.5, 10, 1.6, 13, 0, 120*i, 0], + POSITION: [13, 10, 1, 0, 0, 0, 0], + }, { + POSITION: [3.5, 10, 1.6, 13, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.setTrap, g.pounder, { speed: 1.3, maxSpeed: 1.3 }, {size: 1.2, health: 2}]), + SHOOT_SETTINGS: combineStats([g.trap, g.setTrap, g.pounder, {health: 1.4, speed: 1.16, maxSpeed: 1.16, size: 1.2, shudder: 0.65, range: 0.55}]), TYPE: "unsetTrap", - STAT_CALCULATOR: gunCalcNames.block + STAT_CALCULATOR: "block" }, }, - ) + ], 3), } // T3 Bodies Class.mechanismOfficialV2 = { PARENT: "genericTrinought", LABEL: "Mechanism", - TURRETS: [ + TURRETS: weaponArray([ { - POSITION: [10, 0, 0, 180, 0, 1], - TYPE: ["triangle", {MIRROR_MASTER_ANGLE: true}], - }, - ], -} -for (let i = 0; i < 3; i++) { - Class.mechanismOfficialV2.TURRETS.push( - { - POSITION: [3.5, 6, 0, 120*i, 180, 1], + POSITION: [3.5, 6, 0, 0, 180, 2], + TYPE: "spamAutoTurret", + }, { + POSITION: [3.5, 10, 0, 60, 180, 2], TYPE: "spamAutoTurret", }, + ], 3), + PROPS: [ { - POSITION: [3.5, 10, 0, 120*i+60, 180, 1], - TYPE: "spamAutoTurret", + POSITION: [10, 0, 0, 180, 1], + TYPE: "triangle" }, - ) + ], } -Class.trinoughtBigAura = addAura(2, 1.5); Class.fusionOfficialV2 = { PARENT: "genericTrinought", LABEL: "Fusion", TURRETS: [ + ...weaponArray({ + POSITION: [3.5, 10.5, 0, 60, 180, 2], + TYPE: ["spamAutoTurret", {GUN_STAT_SCALE: g.triSecondaryAuto}], + }, 3), { - POSITION: [13, 0, 0, 180, 0, 1], - TYPE: ["triangle", {MIRROR_MASTER_ANGLE: true}], - }, - { - POSITION: [9.5, 0, 0, 0, 360, 1], + POSITION: [9.5, 0, 0, 0, 360, 2], TYPE: "trinoughtBigAura", }, ], -} -for (let i = 0; i < 3; i++) { - Class.fusionOfficialV2.TURRETS.push( + PROPS: [ { - POSITION: [3.5, 10.5, 0, 120*i+60, 180, 1], - TYPE: "spamAutoTurret", + POSITION: [13, 0, 0, 180, 1], + TYPE: "triangle" }, - ) + ] } Class.binaryOfficialV2 = { PARENT: "genericTrinought", LABEL: "Binary", TURRETS: [ + ...weaponArray({ + POSITION: [3.5, 10.5, 0, 60, 180, 2], + TYPE: ["spamAutoTurret", {GUN_STAT_SCALE: g.triSecondaryAuto}], + }, 3), { - POSITION: [13, 0, 0, 180, 0, 1], - TYPE: ["triangle", {MIRROR_MASTER_ANGLE: true}], + POSITION: [10, 0, 0, 0, 360, 2], + TYPE: ["kilobyteTurretOfficialV2", {GUN_STAT_SCALE: g.triKilobyte}], }, ], -} -for (let i = 0; i < 3; i++) { - Class.binaryOfficialV2.TURRETS.push( + PROPS: [ { - POSITION: [3.5, 10.5, 0, 120*i+60, 180, 1], - TYPE: "spamAutoTurret", + POSITION: [13, 0, 0, 180, 1], + TYPE: "triangle" }, - ) + ], } -Class.binaryOfficialV2.TURRETS.push( - { - POSITION: [10, 0, 0, 0, 360, 1], - TYPE: "kilobyteTurretOfficialV2", - }, -) -Class.trinoughtBigHealAura = addAura(-1.5, 1.5); Class.exosphereOfficialV2 = { PARENT: "genericTrinought", LABEL: "Exosphere", + BODY: healerBodyStats[0], TURRETS: [ + ...weaponArray({ + POSITION: [3.5, 10.5, 0, 60, 180, 2], + TYPE: ["spamAutoTurret", {GUN_STAT_SCALE: g.triSecondaryAuto}], + }, 3), { - POSITION: [13, 0, 0, 180, 0, 1], - TYPE: ["triangle", {MIRROR_MASTER_ANGLE: true}], - }, - { - POSITION: [9.5, 0, 0, 0, 360, 1], + POSITION: [9.5, 0, 0, 0, 360, 2], TYPE: "trinoughtBigHealAura", }, ], -} -for (let i = 0; i < 3; i++) { - Class.exosphereOfficialV2.TURRETS.push( + PROPS: [ { - POSITION: [3.5, 10.5, 0, 120*i+60, 180, 1], - TYPE: "spamAutoTurret", + POSITION: [13, 0, 0, 180, 1], + TYPE: "triangle" }, - ) + ] } Class.megabyteTurretOfficialV2 = { PARENT: "autoTankGun", @@ -1129,7 +1029,7 @@ Class.megabyteTurretOfficialV2 = { { POSITION: [26, 13, 1, 0, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.pounder, g.autoTurret, {health: 1.2, speed: 0.8}]), + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.power, g.turret, g.assassin, g.pounder, {size: 0.85, health: 1.31, speed: 0.62, recoil: 1.4, range: 0.52}]), TYPE: "bullet", }, }, @@ -1140,486 +1040,420 @@ Class.megabyteOfficialV2 = { LABEL: "Megabyte", TURRETS: [ { - POSITION: [15, 0, 0, 180, 0, 1], - TYPE: ["triangle", {MIRROR_MASTER_ANGLE: true}], - }, - { - POSITION: [12, 0, 0, 0, 360, 1], + POSITION: [12, 0, 0, 0, 360, 2], TYPE: "megabyteTurretOfficialV2", }, ], + PROPS: [ + { + POSITION: [15, 0, 0, 180, 1], + TYPE: "triangle" + }, + ] } -Class.trinoughtSmallAura = addAura(1, 2.1, 0.15); Class.trojanOfficialV2 = { PARENT: "genericTrinought", LABEL: "Trojan", TURRETS: [ + ...weaponArray({ + POSITION: [3.5, 11, 0, 60, 360, 2], + TYPE: "trinoughtSmallAura", + }, 3), { - POSITION: [13, 0, 0, 180, 0, 1], - TYPE: ["triangle", {MIRROR_MASTER_ANGLE: true}], + POSITION: [10, 0, 0, 0, 360, 2], + TYPE: ["kilobyteTurretOfficialV2", {GUN_STAT_SCALE: g.triKilobyte}], }, ], -} -for (let i = 0; i < 3; i++) { - Class.trojanOfficialV2.TURRETS.push( + PROPS: [ { - POSITION: [3.5, 11, 0, 120*i+60, 360, 1], - TYPE: "trinoughtSmallAura", + POSITION: [13, 0, 0, 180, 1], + TYPE: "triangle" }, - ) + ] } -Class.trojanOfficialV2.TURRETS.push( - { - POSITION: [10, 0, 0, 0, 360, 1], - TYPE: "kilobyteTurretOfficialV2", - }, -) -Class.trinoughtSmallHealAura = addAura(-2/3, 2.1, 0.15); Class.hardwareOfficialV2 = { PARENT: "genericTrinought", LABEL: "Hardware", + BODY: healerBodyStats[0], TURRETS: [ + ...weaponArray({ + POSITION: [3.5, 11, 0, 60, 360, 2], + TYPE: "trinoughtSmallHealAura", + }, 3), { - POSITION: [13, 0, 0, 180, 0, 1], - TYPE: ["triangle", {MIRROR_MASTER_ANGLE: true}], + POSITION: [10, 0, 0, 0, 360, 2], + TYPE: ["kilobyteTurretOfficialV2", {GUN_STAT_SCALE: g.triKilobyte}], }, ], -} -for (let i = 0; i < 3; i++) { - Class.hardwareOfficialV2.TURRETS.push( + PROPS: [ { - POSITION: [3.5, 11, 0, 120*i+60, 360, 1], - TYPE: "trinoughtSmallHealAura", + POSITION: [13, 0, 0, 180, 1], + TYPE: "triangle" }, - ) + ] } -Class.hardwareOfficialV2.TURRETS.push( - { - POSITION: [10, 0, 0, 0, 360, 1], - TYPE: "kilobyteTurretOfficialV2", - }, -) Class.chromosphereOfficialV2 = { PARENT: "genericTrinought", LABEL: "Chromosphere", TURRETS: [ + ...weaponArray({ + POSITION: [3.5, 10.5, 0, 60, 360, 2], + TYPE: "trinoughtSmallAura", + }, 3), { - POSITION: [13, 0, 0, 180, 0, 1], - TYPE: ["triangle", {MIRROR_MASTER_ANGLE: true}], - }, - { - POSITION: [9.5, 0, 0, 0, 360, 1], + POSITION: [9.5, 0, 0, 0, 360, 2], TYPE: "trinoughtBigAura", }, ], -} -for (let i = 0; i < 3; i++) { - Class.chromosphereOfficialV2.TURRETS.push( + PROPS: [ { - POSITION: [3.5, 10.5, 0, 120*i+60, 360, 1], - TYPE: "trinoughtSmallAura", + POSITION: [13, 0, 0, 180, 1], + TYPE: "triangle" }, - ) + ] } Class.mesosphereOfficialV2 = { PARENT: "genericTrinought", LABEL: "Mesosphere", + BODY: healerBodyStats[1], TURRETS: [ + ...weaponArray({ + POSITION: [3.5, 10.5, 0, 60, 360, 2], + TYPE: "trinoughtSmallHealAura", + }, 3), { - POSITION: [13, 0, 0, 180, 0, 1], - TYPE: ["triangle", {MIRROR_MASTER_ANGLE: true}], - }, - { - POSITION: [9.5, 0, 0, 0, 360, 1], + POSITION: [9.5, 0, 0, 0, 360, 2], TYPE: "trinoughtBigHealAura", }, ], -} -for (let i = 0; i < 3; i++) { - Class.mesosphereOfficialV2.TURRETS.push( + PROPS: [ { - POSITION: [3.5, 10.5, 0, 120*i+60, 360, 1], - TYPE: "trinoughtSmallHealAura", + POSITION: [13, 0, 0, 180, 1], + TYPE: "triangle" }, - ) + ] } Class.goliathOfficialV2 = { PARENT: "genericTrinought", LABEL: "Goliath", - BODY: { - HEALTH: 3.2, - SHIELD: 3.2, - REGEN: 2.5, - SPEED: 0.5, - }, - TURRETS: [ - { - POSITION: [14, 0, 0, 180, 0, 1], - TYPE: ['triangle', {COLOR: 9, MIRROR_MASTER_ANGLE: true}] - }, + BODY: hpBuffBodyStats[2], + PROPS: [ { - POSITION: [24, 0, 0, 180, 0, 0], - TYPE: ['triangle', {COLOR: 9, MIRROR_MASTER_ANGLE: true}] + POSITION: [14, 0, 0, 180, 1], + TYPE: ['triangle', {COLOR: 9}] + }, { + POSITION: [24, 0, 0, 180, 0], + TYPE: ['triangle', {COLOR: 9}] }, ], } Class.planetOfficialV2 = { PARENT: "genericTrinought", LABEL: "Planet", - BODY: { - HEALTH: 2.4, - SHIELD: 2.4, - REGEN: 2, - SPEED: 0.65, - }, - TURRETS: [ - { - POSITION: [24, 0, 0, 180, 0, 0], - TYPE: ['triangle', {COLOR: 9, MIRROR_MASTER_ANGLE: true}] - }, - { - POSITION: [12, 0, 0, 180, 0, 1], - TYPE: ["triangle", {MIRROR_MASTER_ANGLE: true}], + BODY: hpBuffBodyStats[1], + TURRETS: weaponArray({ + POSITION: [3.5, 10.5, 0, 60, 360, 2], + TYPE: "trinoughtSmallAura", + }, 3), + PROPS: [ + { + POSITION: [24, 0, 0, 180, 0], + TYPE: ['triangle', {COLOR: 9}] + }, { + POSITION: [12, 0, 0, 180, 1], + TYPE: "triangle" } ], } -for (let i = 0; i < 3; i++) { - Class.planetOfficialV2.TURRETS.push( - { - POSITION: [3.5, 10.5, 0, 120*i+60, 360, 1], - TYPE: "trinoughtSmallAura", - }, - ) -} Class.moonOfficialV2 = { PARENT: "genericTrinought", LABEL: "Moon", - BODY: { - HEALTH: 2.4, - SHIELD: 2.4, - REGEN: 2, - SPEED: 0.65, - }, - TURRETS: [ - { - POSITION: [24, 0, 0, 180, 0, 0], - TYPE: ['triangle', {COLOR: 9, MIRROR_MASTER_ANGLE: true}] - }, - { - POSITION: [12, 0, 0, 180, 0, 1], - TYPE: ["triangle", {MIRROR_MASTER_ANGLE: true}], + BODY: combineBodyStats(hpBuffBodyStats[1], healerBodyStats[0]), + TURRETS: weaponArray({ + POSITION: [3.5, 10.5, 0, 60, 360, 2], + TYPE: "trinoughtSmallHealAura", + }, 3), + PROPS: [ + { + POSITION: [24, 0, 0, 180, 0], + TYPE: ['triangle', {COLOR: 9}] + }, { + POSITION: [12, 0, 0, 180, 1], + TYPE: "triangle" } ], } -for (let i = 0; i < 3; i++) { - Class.moonOfficialV2.TURRETS.push( - { - POSITION: [3.5, 10.5, 0, 120*i+60, 360, 1], - TYPE: "trinoughtSmallHealAura", - }, - ) -} Class.titanTopOfficialV2 = { PARENT: "genericTrinought", - GUNS: [], -} -for (let i = 0; i < 3; i++) { - Class.titanTopOfficialV2.GUNS.push( - { - POSITION: [5, 26, 0.001, 8, 0, 120*i, 0], - PROPERTIES: {COLOR: 9}, - }, - ) + GUNS: weaponArray({ + POSITION: [5, 26, 0.001, 8, 0, 0, 0], + PROPERTIES: {COLOR: 9}, + }, 3), } Class.titanOfficialV2 = { PARENT: "genericTrinought", LABEL: "Titan", - BODY: { - SPEED: 2.15, - HEALTH: 0.5, - }, - GUNS: [], - TURRETS: [ + BODY: speedBuffBodyStats[1], + PROPS: [ { - POSITION: [11, 0, 0, 0, 0, 1], - TYPE: ["titanTopOfficialV2", {MIRROR_MASTER_ANGLE: true}] - }, - { - POSITION: [20, 0, 0, 0, 0, 0], - TYPE: ["titanTopOfficialV2", {MIRROR_MASTER_ANGLE: true}] + POSITION: [11, 0, 0, 0, 1], + TYPE: "titanTopOfficialV2" + }, { + POSITION: [20, 0, 0, 0, 0], + TYPE: "titanTopOfficialV2" }, ], } Class.sirenOfficialV2 = { PARENT: "genericTrinought", LABEL: "Siren", - BODY: { - SPEED: 1.75, - HEALTH: 0.65, - }, - GUNS: [], - TURRETS: [ - { - POSITION: [12, 0, 0, 180, 0, 1], - TYPE: ["triangle", {MIRROR_MASTER_ANGLE: true}], - }, - { - POSITION: [20, 0, 0, 0, 0, 0], - TYPE: ["titanTopOfficialV2", {MIRROR_MASTER_ANGLE: true}] + BODY: speedBuffBodyStats[0], + TURRETS: weaponArray({ + POSITION: [3.5, 10.5, 0, 60, 360, 1], + TYPE: "trinoughtSmallAura", + }, 3), + PROPS: [ + { + POSITION: [12, 0, 0, 180, 1], + TYPE: "triangle" + }, { + POSITION: [20, 0, 0, 0, 0], + TYPE: "titanTopOfficialV2" }, ], } -for (let i = 0; i < 3; i++) { - Class.sirenOfficialV2.TURRETS.push( - { - POSITION: [3.5, 10.5, 0, 120*i+60, 360, 1], - TYPE: "trinoughtSmallAura", - }, - ) -} Class.harpyOfficialV2 = { PARENT: "genericTrinought", LABEL: "Harpy", - BODY: { - SPEED: 1.75, - HEALTH: 0.65, - }, - GUNS: [], - TURRETS: [ - { - POSITION: [12, 0, 0, 180, 0, 1], - TYPE: ["triangle", {MIRROR_MASTER_ANGLE: true}], - }, + BODY: combineBodyStats(speedBuffBodyStats[0], healerBodyStats[0]), + TURRETS: weaponArray({ + POSITION: [3.5, 10.5, 0, 60, 360, 1], + TYPE: "trinoughtSmallHealAura", + }, 3), + PROPS: [ { - POSITION: [20, 0, 0, 0, 0, 0], - TYPE: ["titanTopOfficialV2", {MIRROR_MASTER_ANGLE: true}] + POSITION: [12, 0, 0, 180, 1], + TYPE: "triangle" + }, { + POSITION: [20, 0, 0, 0, 0], + TYPE: "titanTopOfficialV2" }, ], } -for (let i = 0; i < 3; i++) { - Class.harpyOfficialV2.TURRETS.push( - { - POSITION: [3.5, 10.5, 0, 120*i+60, 360, 1], - TYPE: "trinoughtSmallHealAura", - }, - ) -} // T4 Weapons -Class.javelinOfficialV2 = { +Class.rapierOfficialV2 = { PARENT: "genericPentanought", - LABEL: "Javelin", - GUNS: [], -} -for (let i = 0; i < 5; i++) { - Class.javelinOfficialV2.GUNS.push( + LABEL: "Rapier", + BODY: { + FOV: pentanoughtBody.FOV * 1.225, + }, + GUNS: weaponArray([ { - POSITION: [28, 7, 1, 0, 0, 72*i, 0], + POSITION: [17, 1, 1, 0, 6, 0, 0], + }, { + POSITION: [17, 1, 1, 0, -6, 0, 0], + }, { + POSITION: [18, 5, 1, 0, 3, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.assassin, g.assassin, g.assassin, g.assassin, {reload: 0.8, density: 2/9}]), + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.rifle, g.twin, {speed: 1.13, maxSpeed: 1.13, health: 1.15, range: 0.65}]), TYPE: "bullet", }, - }, - { - POSITION: [5, 7, -1.6, 7, 0, 72*i, 0], - }, - ) -} -Class.rapierOfficialV2 = { - PARENT: "genericPentanought", - LABEL: "Rapier", - GUNS: [], -} -for (let i = 0; i < 5; i++) { - Class.rapierOfficialV2.GUNS.push( - { - POSITION: [17, 1, 1, 0, 6, 72*i, 0], - }, - { - POSITION: [17, 1, 1, 0, -6, 72*i, 0], - }, - { - POSITION: [18, 5, 1, 0, 3, 72*i, 0], + }, { + POSITION: [18, 5, 1, 0, -3, 0, 0.5], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.rifle, {speed: 0.8, health: 1.5}]), + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.rifle, g.twin, {speed: 1.13, maxSpeed: 1.13, health: 1.15, range: 0.65}]), TYPE: "bullet", }, }, + ], 5), +} +Class.javelinOfficialV2 = { + PARENT: "genericPentanought", + LABEL: "Javelin", + BODY: { + FOV: pentanoughtBody.FOV * 1.5, + SPEED: pentanoughtBody.SPEED * 0.85, + }, + GUNS: weaponArray([ { - POSITION: [18, 5, 1, 0, -3, 72*i, 0.5], + POSITION: [28, 7, 1, 0, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.rifle, {speed: 0.8, health: 1.5}]), + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.assassin, g.assassin, {reload: 1.13, health: 1.1, density: 0.55, range: 0.65}]), TYPE: "bullet", }, + }, { + POSITION: [5, 7, -1.6, 7, 0, 0, 0], }, - ) + ], 5), } Class.diplomatOfficialV2 = { PARENT: "genericPentanought", LABEL: "Diplomat", - GUNS: [], -} -for (let i = 0; i < 5; i++) { - Class.diplomatOfficialV2.GUNS.push( + GUNS: weaponArray([ { - POSITION: [13, 7, 1, 0, 3.25, 72*i, 0.5], + POSITION: [13, 7, 1, 0, 3.25, 0, 0.5], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.spam, g.spam, {size: 0.85}]), + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.triplet, {health: 1.15}]), TYPE: "bullet", }, - }, - { - POSITION: [13, 7, 1, 0, -3.25, 72*i, 0.5], + }, { + POSITION: [13, 7, 1, 0, -3.25, 0, 0.5], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.spam, g.spam, {size: 0.85}]), + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.triplet, {health: 1.15}]), TYPE: "bullet", - }, - }, - { - POSITION: [15, 7, 1, 0, 0, 72*i, 0], + }, + }, { + POSITION: [15, 7, 1, 0, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.spam, g.spam, {size: 0.85}]), + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.triplet, {health: 1.15}]), TYPE: "bullet", }, }, - ) + ], 5), } Class.arbitratorOfficialV2 = { PARENT: "genericPentanought", LABEL: "Arbitrator", - GUNS: [], -} -for (let i = 0; i < 5; i++) { - Class.arbitratorOfficialV2.GUNS.push( + GUNS: weaponArray([ { - POSITION: [7.5, 10.75, 1.33, 5.5, 0, 72*i, 0], + POSITION: [7.5, 10.75, 1.33, 5.5, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.spam, g.spam, {size: 0.7, reload: 1.2}]), + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.twin, g.triplet, g.spam, g.spam, {size: 0.7, health: 1.05, range: 0.8, reload: 1}]), TYPE: "bullet", }, - }, - { - POSITION: [7.5, 9.5, 1.33, 7.5, 0, 72*i, 0], + }, { + POSITION: [7.5, 9.5, 1.33, 7.5, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.spam, g.spam, {size: 0.7, reload: 1.1}]), + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.twin, g.triplet, g.spam, g.spam, {size: 0.65, health: 1.05, range: 0.8, reload: 1.05}]), TYPE: "bullet", }, - }, - { - POSITION: [7.5, 7.25, 1.25, 9.5, 0, 72*i, 0], + }, { + POSITION: [7.5, 7.25, 1.25, 9.5, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.spam, g.spam, {size: 0.7, reload: 1}]), + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.twin, g.triplet, g.spam, g.spam, {size: 0.7, health: 1.05, range: 0.8, reload: 1.1}]), TYPE: "bullet", }, }, - ) + ], 5), } Class.retardantOfficialV2 = { PARENT: "genericPentanought", LABEL: "Retardant", - GUNS: [], -} -for (let i = 0; i < 5; i++) { - Class.retardantOfficialV2.GUNS.push( - { - POSITION: [17, 12, 1, 0, 0, 72*i, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.destroyer, g.annihilator, {reload: 0.9, health: 1.1}]), - TYPE: "bullet", - }, + GUNS: weaponArray({ + POSITION: [17, 12, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.destroyer, {reload: 1.1, health: 1.26}]), + TYPE: "bullet", }, - ) + }, 5), } Class.tyrantOfficialV2 = { PARENT: "genericPentanought", LABEL: "Tyrant", - GUNS: [], -} -for (let i = 0; i < 5; i++) { - Class.tyrantOfficialV2.GUNS.push( - { - POSITION: [10, 11, -0.75, 7, 0, 72*i, 0], - }, + GUNS: weaponArray([ { - POSITION: [15, 12, 1, 0, 0, 72*i, 0], + POSITION: [10, 11, -0.75, 7, 0, 0, 0], + }, { + POSITION: [15, 12, 1, 0, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.destroyer, g.artillery, g.skimmer, { speed: 0.5, maxSpeed: 0.5 }, {reload: 0.8}]), + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.artillery, g.artillery, g.skimmer, {reload: 1.18, health: 1.39, speed: 0.7, maxSpeed: 0.7, range: 0.4}]), TYPE: "supermissile", - STAT_CALCULATOR: gunCalcNames.sustained, + STAT_CALCULATOR: "sustained", }, }, - ) + ], 5), } Class.raiderOfficialV2 = { PARENT: "genericPentanought", LABEL: "Raider", - GUNS: [], -} -for (let i = 0; i < 5; i++) { - Class.raiderOfficialV2.GUNS.push( + BODY: { + FOV: pentanoughtBody.FOV * 1.1, + SPEED: pentanoughtBody.SPEED * 0.9, + }, + GUNS: weaponArray([ { - POSITION: [4, 5, 2.1, 8, 3.25, 72*i, 0], + POSITION: [4, 5, 2.1, 8, 3, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.overseer, g.overseer, g.overseer, {size: 1.5, reload: 0.6}]), - TYPE: ["drone", {COLOR: 5}], + SHOOT_SETTINGS: combineStats([g.drone, g.overseer, g.overseer, {damage: 0.9, health: 0.63, maxSpeed: 0.9, size: 1.5, reload: 1.5}]), + TYPE: "drone", MAX_CHILDREN: 2, AUTOFIRE: true, SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.drone, + STAT_CALCULATOR: "drone", WAIT_TO_CYCLE: true, }, - }, - { - POSITION: [4, 5, 2.1, 8, -3.25, 72*i, 0], + }, { + POSITION: [4, 5, 2.1, 8, -3, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.overseer, g.overseer, g.overseer, {size: 1.5, reload: 0.6}]), - TYPE: ["drone", {COLOR: 5}], + SHOOT_SETTINGS: combineStats([g.drone, g.overseer, g.overseer, {damage: 0.9, health: 0.63, maxSpeed: 0.9, size: 1.5, reload: 1.5}]), + TYPE: "drone", MAX_CHILDREN: 2, AUTOFIRE: true, SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.drone, + STAT_CALCULATOR: "drone", WAIT_TO_CYCLE: true, }, - }, - { - POSITION: [6, 6.5, 1.4, 8, 0, 72*i, 0], + }, { + POSITION: [6, 6.5, 1.4, 8, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.overseer, g.overseer, g.overseer, g.pounder, {size: 2, reload: 0.4}]), - TYPE: ["betadrone", {COLOR: 5}], - MAX_CHILDREN: 2, + SHOOT_SETTINGS: combineStats([g.drone, g.overseer, g.overseer, g.pounder, {damage: 1.06, maxSpeed: 0.9, size: 2, reload: 1.5}]), + TYPE: "betadrone", + MAX_CHILDREN: 1, AUTOFIRE: true, SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.drone, + STAT_CALCULATOR: "drone", WAIT_TO_CYCLE: true, }, }, - ) + ], 5), } Class.gladiatorGenericMinionOfficialV2 = { PARENT: "minion", - BODY: { - SPEED: 1, - }, SHAPE: 3.5, - COLOR: 5, + COLOR: "crasher", GUNS: [], } Class.gladiatorTritankMinionOfficialV2 = { PARENT: "gladiatorGenericMinionOfficialV2", - GUNS: [], + GUNS: weaponArray({ + POSITION: [15, 8.5, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.assassin, g.minionGun, {speed: 1.06, maxSpeed: 1.06, reload: 1.8, health: 1.3}]), + WAIT_TO_CYCLE: true, + TYPE: ["bullet", {COLOR: 5}], + }, + }, 3), } Class.gladiatorTritrapMinionOfficialV2 = { PARENT: "gladiatorGenericMinionOfficialV2", - GUNS: [], + GUNS: weaponArray([ + { + POSITION: [13, 7, 1, 0, 0, 0, 0], + }, { + POSITION: [3, 7, 1.7, 13, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, g.pounder, g.flankGuard, g.minionGun, {reload: 1.2, speed: 0.8, maxSpeed: 0.8}]), + TYPE: "trap", + STAT_CALCULATOR: "trap", + }, + }, + ], 3), } Class.gladiatorTriswarmMinionOfficialV2 = { PARENT: "gladiatorGenericMinionOfficialV2", - GUNS: [], + GUNS: weaponArray({ + POSITION: [7, 8.5, -1.5, 7, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.swarm, g.flankGuard, g.minionGun, {speed: 1.1, maxSpeed: 1.1, reload: 1.6, size: 1.6, range: 1.15}]), + TYPE: ["swarm", {COLOR: 5}], + STAT_CALCULATOR: "swarm", + }, + }, 3), } Class.gladiatorAutoMinionOfficialV2 = makeAuto({ PARENT: "gladiatorGenericMinionOfficialV2", }, "Minion", {size: 12, angle: 0}); -Class.gladiatorAuraMinionAuraOfficialV2 = addAura(1, 1.2); Class.gladiatorAuraMinionOfficialV2 = { PARENT: "gladiatorGenericMinionOfficialV2", TURRETS: [ @@ -1629,7 +1463,6 @@ Class.gladiatorAuraMinionOfficialV2 = { } ] } -Class.gladiatorHealAuraMinionAuraOfficialV2 = addAura(-2/3, 1.2); Class.gladiatorHealAuraMinionOfficialV2 = { PARENT: "gladiatorGenericMinionOfficialV2", TURRETS: [ @@ -1639,134 +1472,85 @@ Class.gladiatorHealAuraMinionOfficialV2 = { } ] } -for (let i = 0; i < 3; i++) { - Class.gladiatorTritankMinionOfficialV2.GUNS.push( - { - POSITION: [15, 8.5, 1, 0, 0, 120*i, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.assassin, { speed: 0.7, maxSpeed: 0.7 }, g.minionGun]), - WAIT_TO_CYCLE: true, - TYPE: ["bullet", {COLOR: 5}], - }, - }, - ); - Class.gladiatorTritrapMinionOfficialV2.GUNS.push( - { - POSITION: [13, 7, 1, 0, 0, 120*i, 0], - }, - { - POSITION: [3, 7, 1.7, 13, 0, 120*i, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.flankGuard, g.minionGun]), - TYPE: "trap", - STAT_CALCULATOR: gunCalcNames.trap, - }, - }, - ); - Class.gladiatorTriswarmMinionOfficialV2.GUNS.push( - { - POSITION: [7, 8.5, -1.5, 7, 0, 120*i, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm, {size: 1.6, range: 0.5}]), - TYPE: ["swarm", {COLOR: 5}], - STAT_CALCULATOR: gunCalcNames.swarm, - }, - }, - ); -} Class.gladiatorOfficialV2 = { PARENT: "genericPentanought", LABEL: "Gladiator", - GUNS: [], -} -for (let i = 0; i < 5; i++) { - Class.gladiatorOfficialV2.GUNS.push( - { - POSITION: [4.75, 12, 1, 10, 0, 72*i, 0], - }, + BODY: { + FOV: pentanoughtBody.FOV * 1.1, + SPEED: pentanoughtBody.SPEED * 0.85, + }, + GUNS: weaponArray([ { - POSITION: [1.5, 13, 1, 14.75, 0, 72*i, 0], + POSITION: [4.75, 12, 1, 10, 0, 0, 0], + }, { + POSITION: [1.5, 13, 1, 14.75, 0, 0, 0], PROPERTIES: { - MAX_CHILDREN: 4, - SHOOT_SETTINGS: combineStats([g.factory, {size: 0.9, reload: 0.5}]), + SHOOT_SETTINGS: combineStats([g.factory, {size: 0.9, reload: 2.1, health: 1.16, damage: 0.62, pen: 0.9, speed: 0.8, maxSpeed: 0.8, density: 1.6}]), TYPE: "minion", - STAT_CALCULATOR: gunCalcNames.drone, + STAT_CALCULATOR: "drone", AUTOFIRE: true, SYNCS_SKILLS: true, MAX_CHILDREN: 2, + WAIT_TO_CYCLE: true, }, + }, { + POSITION: [12, 13, 1, 0, 0, 0, 0], }, - { - POSITION: [12, 13, 1, 0, 0, 72*i, 0], - }, - ) + ], 5), +} +let minionIndex = 0; +for (let gun of Class.gladiatorOfficialV2.GUNS) { + minionIndex = setGladiatorMinion(gun, minionIndex); } -Class.gladiatorOfficialV2.GUNS[1].PROPERTIES.TYPE = "gladiatorTritankMinionOfficialV2"; -Class.gladiatorOfficialV2.GUNS[4].PROPERTIES.TYPE = "gladiatorTritrapMinionOfficialV2"; -Class.gladiatorOfficialV2.GUNS[7].PROPERTIES.TYPE = "gladiatorTriswarmMinionOfficialV2"; -Class.gladiatorOfficialV2.GUNS[10].PROPERTIES.TYPE = "gladiatorAutoMinionOfficialV2"; -Class.gladiatorOfficialV2.GUNS[13].PROPERTIES.TYPE = "gladiatorAuraMinionOfficialV2"; Class.cerberusOfficialV2 = { PARENT: "genericPentanought", LABEL: "Cerberus", - GUNS: [], -} -for (let i = 0; i < 5; i++) { - Class.cerberusOfficialV2.GUNS.push( - { - POSITION: [12, 4, 1, 0, 2.5, 72*i+10, 0.5], - }, + GUNS: weaponArray([ { - POSITION: [1.5, 4, 1.6, 12, 2.5, 72*i+10, 0.5], + POSITION: [12, 4, 1, 0, 2.5, 10, 0.5], + }, { + POSITION: [1.5, 4, 1.6, 12, 2.5, 10, 0.5], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.twin, g.pounder, { speed: 1.2 }]), + SHOOT_SETTINGS: combineStats([g.trap, g.twin, g.pounder, {shudder: 0.6, health: 0.55, reload: 1.2, speed: 1.26, maxSpeed: 1.26, range: 0.67}]), TYPE: "trap", - STAT_CALCULATOR: gunCalcNames.trap, + STAT_CALCULATOR: "trap", }, - }, - { - POSITION: [12, 4, 1, 0, -2.5, 72*i-10, 0.5], - }, - { - POSITION: [1.5, 4, 1.6, 12, -2.5, 72*i-10, 0.5], + }, { + POSITION: [12, 4, 1, 0, -2.5, -10, 0.5], + }, { + POSITION: [1.5, 4, 1.6, 12, -2.5, -10, 0.5], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.twin, g.pounder, { speed: 1.2 }]), + SHOOT_SETTINGS: combineStats([g.trap, g.twin, g.pounder, {shudder: 0.6, health: 0.55, reload: 1.2, speed: 1.26, maxSpeed: 1.26, range: 0.67}]), TYPE: "trap", - STAT_CALCULATOR: gunCalcNames.trap, + STAT_CALCULATOR: "trap", }, - }, - { - POSITION: [14, 5.5, 1, 0, 0, 72*i, 0], - }, - { - POSITION: [2, 5.5, 1.7, 14, 0, 72*i, 0], + }, { + POSITION: [14, 5.5, 1, 0, 0, 0, 0], + }, { + POSITION: [2, 5.5, 1.7, 14, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.setTrap, g.twin, g.pounder, { speed: 1.2 }]), + SHOOT_SETTINGS: combineStats([g.trap, g.setTrap, g.twin, g.pounder, {reload: 1.15, health: 0.85, speed: 0.75, maxSpeed: 0.75, range: 0.5}]), TYPE: "unsetTrap", - STAT_CALCULATOR: gunCalcNames.block + STAT_CALCULATOR: "block" }, }, - ) + ], 5), } Class.luciferOfficialV2 = { PARENT: "genericPentanought", LABEL: "Lucifer", - GUNS: [], -} -for (let i = 0; i < 5; i++) { - Class.luciferOfficialV2.GUNS.push( - { - POSITION: [13, 10, 1, 0, 0, 72*i, 0], - }, + GUNS: weaponArray([ { - POSITION: [3.5, 10, 1.6, 13, 0, 72*i, 0], + POSITION: [13, 10, 1, 0, 0, 0, 0], + }, { + POSITION: [3.5, 10, 1.6, 13, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.setTrap, g.pounder, { speed: 1.3, maxSpeed: 1.3 }, {size: 1.3, health: 2}]), + SHOOT_SETTINGS: combineStats([g.trap, g.setTrap, g.pounder, {reload: 1.2, speed: 1.15, maxSpeed: 1.15, size: 1.25, health: 1.15, range: 0.37}]), TYPE: "unsetTrap", - STAT_CALCULATOR: gunCalcNames.block + STAT_CALCULATOR: "block" }, }, - ) + ], 5), } // T4 Bodies @@ -1774,97 +1558,82 @@ Class.skynetOfficialV2 = { PARENT: "genericPentanought", LABEL: "Skynet", TURRETS: [ - { - POSITION: [12, 0, 0, 180, 0, 1], - TYPE: ["pentagon", {COLOR: -1, MIRROR_MASTER_ANGLE: true}], - } + ...weaponArray({ + POSITION: [3.25, 4.5, 0, 0, 180, 2], + TYPE: ["spamAutoTurret", {GUN_STAT_SCALE: {reload: 1.1, health: 0.93, damage: 0.8}}], + }, 5), + ...weaponArray({ + POSITION: [3.25, 8, 0, 36, 180, 2], + TYPE: ["spamAutoTurret", {GUN_STAT_SCALE: {reload: 1.1, health: 0.93, damage: 0.8}}], + }, 5) ], -} -for (let i = 0; i < 5; i++) { - Class.skynetOfficialV2.TURRETS.push( - { - POSITION: [3.25, 4.5, 0, 72*i, 180, 1], - TYPE: "spamAutoTurret", - }, - ) -} -for (let i = 0; i < 5; i++) { - Class.skynetOfficialV2.TURRETS.push( + PROPS: [ { - POSITION: [3.25, 8, 0, 72*i+36, 180, 1], - TYPE: "spamAutoTurret", - }, - ) + POSITION: [12, 0, 0, 180, 1], + TYPE: "pentagon", + } + ] } -Class.pentanoughtBigAura = addAura(2.5, 1.45); Class.supernovaOfficialV2 = { PARENT: "genericPentanought", LABEL: "Supernova", TURRETS: [ + ...weaponArray({ + POSITION: [3.25, 9, 0, 36, 180, 2], + TYPE: ["spamAutoTurret", {GUN_STAT_SCALE: g.pentaSecondaryAuto}], + }, 5), { - POSITION: [13, 0, 0, 180, 0, 1], - TYPE: ["pentagon", {COLOR: -1, MIRROR_MASTER_ANGLE: true}], - }, - { - POSITION: [9, 0, 0, 0, 360, 1], + POSITION: [9, 0, 0, 0, 360, 2], TYPE: "pentanoughtBigAura", }, ], -} -for (let i = 0; i < 5; i++) { - Class.supernovaOfficialV2.TURRETS.push( + PROPS: [ { - POSITION: [3.25, 9, 0, 72*i+36, 180, 1], - TYPE: "spamAutoTurret", + POSITION: [13, 0, 0, 180, 1], + TYPE: "pentagon", }, - ) + ] } Class.cipherOfficialV2 = { PARENT: "genericPentanought", LABEL: "Cipher", TURRETS: [ + ...weaponArray({ + POSITION: [3.25, 9, 0, 36, 180, 2], + TYPE: ["spamAutoTurret", {GUN_STAT_SCALE: g.pentaSecondaryAuto}], + }, 5), { - POSITION: [13, 0, 0, 180, 0, 1], - TYPE: ["pentagon", {COLOR: -1, MIRROR_MASTER_ANGLE: true}], + POSITION: [11.5, 0, 0, 0, 360, 2], + TYPE: ["megabyteTurretOfficialV2", {GUN_STAT_SCALE: g.pentaMegabyte}], }, ], -} -for (let i = 0; i < 5; i++) { - Class.cipherOfficialV2.TURRETS.push( + PROPS: [ { - POSITION: [3.25, 9, 0, 72*i+36, 180, 1], - TYPE: "spamAutoTurret", + POSITION: [13, 0, 0, 180, 1], + TYPE: "pentagon", }, - ) + ] } -Class.cipherOfficialV2.TURRETS.push( - { - POSITION: [11.5, 0, 0, 0, 360, 1], - TYPE: "megabyteTurretOfficialV2", - }, -) -Class.pentanoughtBigHealAura = addAura(-2, 1.45); Class.interstellarOfficialV2 = { PARENT: "genericPentanought", LABEL: "Interstellar", + BODY: healerBodyStats[1], TURRETS: [ + ...weaponArray({ + POSITION: [3.25, 9, 0, 36, 180, 2], + TYPE: ["spamAutoTurret", {GUN_STAT_SCALE: g.pentaSecondaryAuto}], + }, 5), { - POSITION: [13, 0, 0, 180, 0, 1], - TYPE: ["pentagon", {COLOR: -1, MIRROR_MASTER_ANGLE: true}], - }, - { - POSITION: [9.5, 0, 0, 0, 360, 1], + POSITION: [9.5, 0, 0, 0, 360, 2], TYPE: "pentanoughtBigHealAura", }, ], -} -for (let i = 0; i < 5; i++) { - Class.interstellarOfficialV2.TURRETS.push( + PROPS: [ { - POSITION: [3.25, 9, 0, 72*i+36, 180, 1], - TYPE: "spamAutoTurret", + POSITION: [13, 0, 0, 180, 1], + TYPE: "pentagon", }, - ) + ] } Class.gigabyteTurretOfficialV2 = { PARENT: "autoTankGun", @@ -1873,7 +1642,7 @@ Class.gigabyteTurretOfficialV2 = { { POSITION: [26, 16, 1, 0, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.pounder, g.destroyer, g.autoTurret, {speed: 1.1, health: 0.8}]), + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.power, g.turret, g.assassin, g.pounder, g.destroyer, {size: 0.75, health: 1.24, speed: 0.9, recoil: 1.4, range: 0.9}]), TYPE: "bullet", }, }, @@ -1884,344 +1653,273 @@ Class.gigabyteOfficialV2 = { LABEL: "Gigabyte", TURRETS: [ { - POSITION: [14.5, 0, 0, 180, 0, 1], - TYPE: ["pentagon", {COLOR: -1, MIRROR_MASTER_ANGLE: true}], - }, - { - POSITION: [13, 0, 0, 0, 360, 1], + POSITION: [13, 0, 0, 0, 360, 2], TYPE: "gigabyteTurretOfficialV2", }, ], + PROPS: [ + { + POSITION: [14.5, 0, 0, 180, 1], + TYPE: "pentagon", + }, + ] } Class.malwareOfficialV2 = { PARENT: "genericPentanought", LABEL: "Malware", TURRETS: [ + ...weaponArray({ + POSITION: [4, 8.5, 0, 36, 360, 2], + TYPE: "pentanoughtSmallAura", + }, 5), { - POSITION: [13, 0, 0, 180, 0, 1], - TYPE: ["pentagon", {COLOR: -1, MIRROR_MASTER_ANGLE: true}], + POSITION: [11.5, 0, 0, 0, 360, 2], + TYPE: ["megabyteTurretOfficialV2", {GUN_STAT_SCALE: g.pentaMegabyte}], }, ], -} -Class.pentanoughtSmallAura = addAura(1, 1.6, 0.15); -for (let i = 0; i < 5; i++) { - Class.malwareOfficialV2.TURRETS.push( + PROPS: [ { - POSITION: [4, 8.5, 0, 72*i+36, 360, 1], - TYPE: "pentanoughtSmallAura", + POSITION: [13, 0, 0, 180, 1], + TYPE: "pentagon", }, - ) + ] } -Class.malwareOfficialV2.TURRETS.push( - { - POSITION: [11.5, 0, 0, 0, 360, 1], - TYPE: "megabyteTurretOfficialV2", - }, -) -Class.pentanoughtSmallHealAura = addAura(-2/3, 1.6, 0.15); Class.softwareOfficialV2 = { PARENT: "genericPentanought", LABEL: "Software", + BODY: healerBodyStats[1], TURRETS: [ + ...weaponArray({ + POSITION: [4, 8.5, 0, 36, 360, 2], + TYPE: "pentanoughtSmallHealAura", + }, 5), { - POSITION: [13, 0, 0, 180, 0, 1], - TYPE: ["pentagon", {COLOR: -1, MIRROR_MASTER_ANGLE: true}], + POSITION: [11.5, 0, 0, 0, 360, 2], + TYPE: ["megabyteTurretOfficialV2", {GUN_STAT_SCALE: g.pentaMegabyte}], }, ], -} -for (let i = 0; i < 5; i++) { - Class.softwareOfficialV2.TURRETS.push( + PROPS: [ { - POSITION: [4, 8.5, 0, 72*i+36, 360, 1], - TYPE: "pentanoughtSmallHealAura", + POSITION: [13, 0, 0, 180, 1], + TYPE: "pentagon", }, - ) -} -Class.softwareOfficialV2.TURRETS.push( - { - POSITION: [11.5, 0, 0, 0, 360, 1], - TYPE: "megabyteTurretOfficialV2", - }, -) -if (useOldPhotosphere) { - Class.photosphereSmallAuraOfficialV2 = addAura(1, 1.85, 0.15); - Class.photosphereBigAuraOfficialV2 = addAura(1.5, 4); + ] } Class.photosphereOfficialV2 = { PARENT: "genericPentanought", LABEL: "Photosphere", - TURRETS: [ + PROPS: [ { - POSITION: [12, 0, 0, 180, 0, 1], - TYPE: ["pentagon", {COLOR: -1, MIRROR_MASTER_ANGLE: true}], + POSITION: [12, 0, 0, 180, 1], + TYPE: "pentagon", }, ], } if (useOldPhotosphere) { - for (let i = 0; i < 5; i++) { - Class.photosphereOfficialV2.TURRETS.push( - { - POSITION: [3.5, 8.75, 0, 72*i+36, 360, 1], - TYPE: "photosphereSmallAuraOfficialV2", - }, - ) - } - for (let i = 0; i < 5; i++) { - Class.photosphereOfficialV2.TURRETS.push( - { - POSITION: [3, 4, 0, 72*i, 360, 1], - TYPE: "photosphereBigAuraOfficialV2", - }, - ) - } + Class.photosphereOfficialV2.TURRETS = [ + ...weaponArray({ + POSITION: [3.5, 8.75, 0, 36, 360, 2], + TYPE: "photosphereSmallAuraOfficialV2", + }, 5), + ...weaponArray({ + POSITION: [3, 4, 0, 0, 360, 2], + TYPE: "photosphereBigAuraOfficialV2", + }, 5) + ] } else { - for (let i = 0; i < 5; i++) { - Class.photosphereOfficialV2.TURRETS.push( - { - POSITION: [4, 8.5, 0, 72*i+36, 360, 1], - TYPE: "pentanoughtSmallAura", - }, - ) - } - Class.photosphereOfficialV2.TURRETS.push( + Class.photosphereOfficialV2.TURRETS = [ + ...weaponArray({ + POSITION: [4, 8.5, 0, 36, 360, 2], + TYPE: "pentanoughtSmallAura", + }, 5), { - POSITION: [9, 0, 0, 0, 360, 1], + POSITION: [9, 0, 0, 0, 360, 2], TYPE: "pentanoughtBigAura", }, - ) + ] } Class.stratosphereOfficialV2 = { PARENT: "genericPentanought", LABEL: "Stratosphere", + BODY: healerBodyStats[2], TURRETS: [ + ...weaponArray({ + POSITION: [4, 8.5, 0, 36, 360, 2], + TYPE: "pentanoughtSmallHealAura", + }, 5), { - POSITION: [13, 0, 0, 180, 0, 1], - TYPE: ["pentagon", {COLOR: -1, MIRROR_MASTER_ANGLE: true}], - }, - { - POSITION: [9.5, 0, 0, 0, 360, 1], + POSITION: [9.5, 0, 0, 0, 360, 2], TYPE: "pentanoughtBigHealAura", }, ], -} -for (let i = 0; i < 5; i++) { - Class.stratosphereOfficialV2.TURRETS.push( + PROPS: [ { - POSITION: [4, 8.5, 0, 72*i+36, 360, 1], - TYPE: "pentanoughtSmallHealAura", + POSITION: [13, 0, 0, 180, 1], + TYPE: "pentagon", }, - ) + ] } Class.behemothOfficialV2 = { PARENT: "genericPentanought", LABEL: "Behemoth", - BODY: { - HEALTH: 4, - SHIELD: 4, - REGEN: 2.5, - SPEED: 0.4, - }, - TURRETS: [ - { - POSITION: [15, 0, 0, 180, 0, 1], - TYPE: ["pentagon", {COLOR: 9, MIRROR_MASTER_ANGLE: true}], - }, + BODY: hpBuffBodyStats[3], + PROPS: [ { - POSITION: [24, 0, 0, 180, 0, 0], - TYPE: ["pentagon", {COLOR: 9, MIRROR_MASTER_ANGLE: true}], + POSITION: [15, 0, 0, 180, 1], + TYPE: ["pentagon", {COLOR: 9}], + }, { + POSITION: [24, 0, 0, 180, 0], + TYPE: ["pentagon", {COLOR: 9}], }, ], } Class.astronomicOfficialV2 = { PARENT: "genericPentanought", LABEL: "Astronomic", - BODY: { - HEALTH: 3.2, - SHIELD: 3.2, - REGEN: 2.5, - SPEED: 0.5, - }, - TURRETS: [ - { - POSITION: [13, 0, 0, 180, 0, 1], - TYPE: ["pentagon", {COLOR: -1, MIRROR_MASTER_ANGLE: true}], - }, - { - POSITION: [24, 0, 0, 180, 0, 0], - TYPE: ["pentagon", {COLOR: 9, MIRROR_MASTER_ANGLE: true}], + BODY: hpBuffBodyStats[2], + TURRETS: weaponArray({ + POSITION: [4, 8.5, 0, 36, 360, 2], + TYPE: "pentanoughtSmallAura", + }, 5), + PROPS: [ + { + POSITION: [13, 0, 0, 180, 1], + TYPE: "pentagon", + }, { + POSITION: [24, 0, 0, 180, 0], + TYPE: ["pentagon", {COLOR: 9}], }, ], } -for (let i = 0; i < 5; i++) { - Class.astronomicOfficialV2.TURRETS.push( - { - POSITION: [4, 8.5, 0, 72*i+36, 360, 1], - TYPE: "pentanoughtSmallAura", - }, - ) -} Class.grandioseOfficialV2 = { PARENT: "genericPentanought", LABEL: "Grandiose", - BODY: { - HEALTH: 3.2, - SHIELD: 3.2, - REGEN: 2.5, - SPEED: 0.5, - }, - TURRETS: [ - { - POSITION: [13, 0, 0, 180, 0, 1], - TYPE: ["pentagon", {COLOR: -1, MIRROR_MASTER_ANGLE: true}], - }, - { - POSITION: [24, 0, 0, 180, 0, 0], - TYPE: ["pentagon", {COLOR: 9, MIRROR_MASTER_ANGLE: true}], + BODY: combineBodyStats(hpBuffBodyStats[2], healerBodyStats[1]), + TURRETS: weaponArray({ + POSITION: [4, 8.5, 0, 36, 360, 2], + TYPE: "pentanoughtSmallHealAura", + }, 5), + PROPS: [ + { + POSITION: [13, 0, 0, 180, 1], + TYPE: "pentagon", + }, { + POSITION: [24, 0, 0, 180, 0], + TYPE: ["pentagon", {COLOR: 9}], }, ], } -for (let i = 0; i < 5; i++) { - Class.grandioseOfficialV2.TURRETS.push( - { - POSITION: [4, 8.5, 0, 72*i+36, 360, 1], - TYPE: "pentanoughtSmallHealAura", - }, - ) -} Class.pentagonLeviathanTopOfficialV2 = { PARENT: "genericPentanought", LABEL: "Leviathan", - MIRROR_MASTER_ANGLE: true, - GUNS: [], + GUNS: weaponArray({ + POSITION: [6, 13.5, 0.001, 9, 0, 0, 0], + PROPERTIES: {COLOR: 9}, + }, 5), } Class.pentagonLeviathanBottomOfficialV2 = { PARENT: "genericPentanought", LABEL: "Leviathan", - MIRROR_MASTER_ANGLE: true, - GUNS: [], -} -for (let i = 0; i < 5; i++) { - Class.pentagonLeviathanTopOfficialV2.GUNS.push( - { - POSITION: [6, 13.5, 0.001, 9, 0, 72*i, 0], - PROPERTIES: {COLOR: 9}, - }, - ); - Class.pentagonLeviathanBottomOfficialV2.GUNS.push( - { - POSITION: [7, 17, 0.001, 9, 0, 72*i, 0], - PROPERTIES: {COLOR: 9}, - }, - ); + GUNS: weaponArray({ + POSITION: [7, 17, 0.001, 9, 0, 0, 0], + PROPERTIES: {COLOR: 9}, + }, 5), } Class.hexagonLeviathanTopOfficialV2 = { PARENT: "genericHexnought", LABEL: "Leviathan", - MIRROR_MASTER_ANGLE: true, - GUNS: [], + GUNS: weaponArray({ + POSITION: [6, 10, 0.001, 9.5, 0, 0, 0], + PROPERTIES: {COLOR: 9}, + }, 6), } Class.hexagonLeviathanBottomOfficialV2 = { PARENT: "genericHexnought", LABEL: "Leviathan", - MIRROR_MASTER_ANGLE: true, - GUNS: [], -} -for (let i = 0; i < 6; i++) { - Class.hexagonLeviathanTopOfficialV2.GUNS.push( - { - POSITION: [6, 10, 0.001, 9.5, 0, 60*i, 0], - PROPERTIES: {COLOR: 9}, - }, - ) - Class.hexagonLeviathanBottomOfficialV2.GUNS.push( - { - POSITION: [7, 13.5, 0.001, 9.5, 0, 60*i, 0], - PROPERTIES: {COLOR: 9}, - }, - ) + GUNS: weaponArray({ + POSITION: [7, 13.5, 0.001, 9.5, 0, 0, 0], + PROPERTIES: {COLOR: 9}, + }, 6), } Class.leviathanOfficialV2 = { PARENT: "genericPentanought", LABEL: "Leviathan", - GUNS: [], - BODY: { - SPEED: 2.35, - HEALTH: 0.35, - }, - TURRETS: [ - { - POSITION: [12, 0, 0, 0, 0, 1], - TYPE: ["pentagonLeviathanTopOfficialV2", {COLOR: -1, MIRROR_MASTER_ANGLE: true}] - }, + BODY: speedBuffBodyStats[2], + PROPS: [ { - POSITION: [20, 0, 0, 0, 0, 0], - TYPE: ["pentagonLeviathanBottomOfficialV2", {COLOR: -1, MIRROR_MASTER_ANGLE: true}] + POSITION: [12, 0, 0, 0, 1], + TYPE: "pentagonLeviathanTopOfficialV2" + }, { + POSITION: [20, 0, 0, 0, 0], + TYPE: "pentagonLeviathanBottomOfficialV2" }, ], } Class.valrayvnOfficialV2 = { PARENT: "genericPentanought", LABEL: "Valrayvn", - GUNS: [], - BODY: { - SPEED: 2.15, - HEALTH: 0.5, - }, - TURRETS: [ - { - POSITION: [12, 0, 0, 180, 0, 1], - TYPE: ["pentagon", {COLOR: -1, MIRROR_MASTER_ANGLE: true}], - }, - { - POSITION: [20, 0, 0, 0, 0, 0], - TYPE: ["pentagonLeviathanBottomOfficialV2", {COLOR: -1, MIRROR_MASTER_ANGLE: true}] + BODY: speedBuffBodyStats[1], + TURRETS: weaponArray({ + POSITION: [4, 8.5, 0, 36, 360, 2], + TYPE: "pentanoughtSmallAura", + }, 5), + PROPS: [ + { + POSITION: [12, 0, 0, 180, 1], + TYPE: "pentagon" + }, { + POSITION: [20, 0, 0, 0, 0], + TYPE: "pentagonLeviathanBottomOfficialV2" }, ], } -for (let i = 0; i < 5; i++) { - Class.valrayvnOfficialV2.TURRETS.push( - { - POSITION: [4, 8.5, 0, 72*i+36, 360, 1], - TYPE: "pentanoughtSmallAura", - }, - ) -} Class.pegasusOfficialV2 = { PARENT: "genericPentanought", LABEL: "Pegasus", - GUNS: [], - BODY: { - SPEED: 2.15, - HEALTH: 0.5, - }, - TURRETS: [ - { - POSITION: [12, 0, 0, 180, 0, 1], - TYPE: ["pentagon", {COLOR: -1, MIRROR_MASTER_ANGLE: true}], - }, - { - POSITION: [20, 0, 0, 0, 0, 0], - TYPE: ["pentagonLeviathanBottomOfficialV2", {COLOR: -1, MIRROR_MASTER_ANGLE: true}] + BODY: combineBodyStats(speedBuffBodyStats[1], healerBodyStats[1]), + TURRETS: weaponArray({ + POSITION: [4, 8.5, 0, 36, 360, 2], + TYPE: "pentanoughtSmallHealAura", + }, 5), + PROPS: [ + { + POSITION: [12, 0, 0, 180, 1], + TYPE: "pentagon" + }, { + POSITION: [20, 0, 0, 0, 0], + TYPE: "pentagonLeviathanBottomOfficialV2" }, ], } -for (let i = 0; i < 5; i++) { - Class.pegasusOfficialV2.TURRETS.push( - { - POSITION: [4, 8.5, 0, 72*i+36, 360, 1], - TYPE: "pentanoughtSmallHealAura", - }, - ) + +// Generate split upgrades buffer upgrades +const firstTier = ['sword', 'pacifier', 'peacekeeper', 'invader', 'centaur']; +for (let def of firstTier) { + let newDef = `${def}2OfficialV2`; + let originalDef = `${def}OfficialV2`; + Class[newDef] = dereference(originalDef); + Class[newDef].BATCH_UPGRADES = true; + + // Save to upgrades + util.forcePush(Class.dreadOfficialV2, 'UPGRADES_TIER_0', [newDef, "dreadBodyOfficialV2"]); + util.forcePush(Class.dreadWeaponOfficialV2, 'UPGRADES_TIER_0', originalDef); } +/* +The above does the following: + +Class.dreadOfficialV2.UPGRADES_TIER_0 = [ + ["sword2OfficialV2", "dreadBodyOfficialV2",], + ["pacifier2OfficialV2", "dreadBodyOfficialV2"], + ["peacekeeper2OfficialV2", "dreadBodyOfficialV2"], + ["invader2OfficialV2", "dreadBodyOfficialV2"], + ["centaur2OfficialV2", "dreadBodyOfficialV2"], +]; + +Class.dreadWeaponOfficialV2.UPGRADES_TIER_0 = ["swordOfficialV2", "pacifierOfficialV2", "peacekeeperOfficialV2", "invaderOfficialV2", "centaurOfficialV2"]; +*/ + Class.addons.UPGRADES_TIER_0.push("dreadOfficialV2"); - Class.dreadOfficialV2.UPGRADES_TIER_0 = [ - ["sword2OfficialV2", "dreadBodyOfficialV2",], - ["pacifier2OfficialV2", "dreadBodyOfficialV2"], - ["peacekeeper2OfficialV2", "dreadBodyOfficialV2"], - ["invader2OfficialV2", "dreadBodyOfficialV2"], - ["centaur2OfficialV2", "dreadBodyOfficialV2"], - ]; Class.sword2OfficialV2.UPGRADES_TIER_0 = ["swordOfficialV2"]; Class.pacifier2OfficialV2.UPGRADES_TIER_0 = ["pacifierOfficialV2"]; @@ -2229,8 +1927,6 @@ Class.addons.UPGRADES_TIER_0.push("dreadOfficialV2"); Class.invader2OfficialV2.UPGRADES_TIER_0 = ["invaderOfficialV2"]; Class.centaur2OfficialV2.UPGRADES_TIER_0 = ["centaurOfficialV2"]; - Class.dreadWeaponOfficialV2.UPGRADES_TIER_0 = ["swordOfficialV2", "pacifierOfficialV2", "peacekeeperOfficialV2", "invaderOfficialV2", "centaurOfficialV2"]; - Class.swordOfficialV2.UPGRADES_TIER_0 = ["gladiusOfficialV2", "sabreOfficialV2"]; Class.gladiusOfficialV2.UPGRADES_TIER_0 = ["bladeOfficialV2"]; Class.bladeOfficialV2.UPGRADES_TIER_0 = ["rapierOfficialV2"]; @@ -2330,7 +2026,7 @@ Class.addons.UPGRADES_TIER_0.push("dreadOfficialV2"); const hexDreadNames = { Javelin: { - Javelin: 'Javelin', + Javelin: 'Javelin II', Rapier: 'Lance', Diplomat: 'Envoy', Arbitrator: 'Cutlass', @@ -2342,7 +2038,7 @@ const hexDreadNames = { Lucifer: 'Kitsune', }, Rapier: { - Rapier: 'Rapier', + Rapier: 'Rapier II', Diplomat: 'Emissary', Arbitrator: 'Umpire', Retardant: 'Impeder', @@ -2353,7 +2049,7 @@ const hexDreadNames = { Lucifer: 'Damocles', }, Diplomat: { - Diplomat: 'Diplomat', + Diplomat: 'Diplomat II', Arbitrator: 'Moderator', Retardant: 'Insurgent', Tyrant: 'Dictator', @@ -2363,7 +2059,7 @@ const hexDreadNames = { Lucifer: 'Manticore', }, Arbitrator: { - Arbitrator: 'Arbitrator', + Arbitrator: 'Arbitrator II', Retardant: 'Extinguisher', Tyrant: 'Shogun', Raider: 'Buccaneer', @@ -2372,7 +2068,7 @@ const hexDreadNames = { Lucifer: 'Keres', }, Retardant: { - Retardant: 'Retardant', + Retardant: 'Retardant II', Tyrant: 'Anarchist', Raider: 'Freebooter', Gladiator: 'Combatant', @@ -2380,76 +2076,135 @@ const hexDreadNames = { Lucifer: 'Demogorgon', }, Tyrant: { - Tyrant: 'Tyrant', + Tyrant: 'Tyrant II', Raider: 'Corsair', Gladiator: 'Amazon', Cerberus: 'Ouroboros', Lucifer: 'Raiju', }, Raider: { - Raider: 'Raider', + Raider: 'Raider II', Gladiator: 'Filibuster', Cerberus: 'Wyvern', Lucifer: 'Kraken', }, Gladiator: { - Gladiator: 'Gladiator', + Gladiator: 'Gladiator II', Cerberus: 'Ogre', Lucifer: 'Wendigo', }, Cerberus: { - Cerberus: 'Cerberus', + Cerberus: 'Cerberus II', Lucifer: 'Oni', }, Lucifer: { - Lucifer: 'Lucifer', + Lucifer: 'Lucifer II', }, }; +function setGladiatorMinion(gun, index) { + if (!gun.PROPERTIES) return index; + if (!gun.PROPERTIES.TYPE) return index; + if (!gun.PROPERTIES.TYPE.includes("inion")) return index; + switch (index) { + case 0: + gun.PROPERTIES.TYPE = "gladiatorTritankMinionOfficialV2"; + break; + case 1: + gun.PROPERTIES.TYPE = "gladiatorTritrapMinionOfficialV2"; + break; + case 2: + gun.PROPERTIES.TYPE = "gladiatorTriswarmMinionOfficialV2"; + break; + case 3: + gun.PROPERTIES.TYPE = "gladiatorAutoMinionOfficialV2"; + break; + case 4: + gun.PROPERTIES.TYPE = "gladiatorAuraMinionOfficialV2"; + break; + case 5: + gun.PROPERTIES.TYPE = "gladiatorHealAuraMinionOfficialV2"; + break; + } + return index + 1; +} function mergeHexnoughtWeaponV2(weapon1, weapon2) { weapon1 = ensureIsClass(weapon1); weapon2 = ensureIsClass(weapon2); - let PARENT = Class.genericHexnought, - BODY = JSON.parse(JSON.stringify(PARENT.BODY)), + let PARENT = "genericHexnought", GUNS = [], gunsOnOneSide = [], weapon2GunsOnOneSide = [], - TURRETS = []; + TURRETS = [], + turretsOnOneSide = [], + weapon2TurretsOnOneSide = []; // Label let name1 = hexDreadNames[weapon1.LABEL][weapon2.LABEL], name2 = hexDreadNames[weapon2.LABEL][weapon1.LABEL], - weaponName = "", + weaponName = weapon1.LABEL + weapon2.LABEL, orientationId = 0; - if(name1) { + if (name1) { weaponName = name1; - } else { + } else if (name2) { weaponName = name2, orientationId = 1; } let LABEL = weaponName, - className = weaponName.toLowerCase() + orientationId + "OfficialV2"; + className = weapon1.LABEL.toLowerCase() + weapon2.LABEL + orientationId + "OfficialV2"; // Guns ---------------------- - if (weapon1.GUNS) gunsOnOneSide.push(...JSON.parse(JSON.stringify(weapon1.GUNS.slice(0, weapon1.GUNS.length / 5)))); - if (weapon2.GUNS) weapon2GunsOnOneSide = JSON.parse(JSON.stringify(weapon2.GUNS.slice(0, weapon2.GUNS.length / 5))); + if (weapon1.GUNS) { + for (let i = 0; i < weapon1.GUNS.length; i += 5) { + gunsOnOneSide.push(dereference(weapon1.GUNS[i])); + } + } + if (weapon2.GUNS) { + for (let i = 0; i < weapon2.GUNS.length; i += 5) { + weapon2GunsOnOneSide.push(dereference(weapon2.GUNS[i])); + } + } for (let g in weapon2GunsOnOneSide) weapon2GunsOnOneSide[g].POSITION[5] += 60; gunsOnOneSide.push(...weapon2GunsOnOneSide) + // Turrets ------------------- + if (weapon1.TURRETS) { + for (let i = 0; i < weapon1.TURRETS.length; i += 5) { + turretsOnOneSide.push(dereference(weapon1.TURRETS[i])); + } + } + if (weapon2.TURRETS) { + for (let i = 0; i < weapon2.TURRETS.length; i += 5) { + weapon2TurretsOnOneSide.push(dereference(weapon2.TURRETS[i])); + } + } + + for (let t in weapon2TurretsOnOneSide) weapon2TurretsOnOneSide[t].POSITION[3] += 60; + turretsOnOneSide.push(...weapon2TurretsOnOneSide) + // Scale to fit size constraints for (let g in gunsOnOneSide) { gunsOnOneSide[g].POSITION[1] *= hexnoughtScaleFactor ** 2; gunsOnOneSide[g].POSITION[4] *= hexnoughtScaleFactor ** 2; } + for (let t in turretsOnOneSide) { + turretsOnOneSide[t].POSITION[0] *= hexnoughtScaleFactor ** 2; + } + for (let i = 0; i < 3; i++) { for (let g in gunsOnOneSide) { let gun = JSON.parse(JSON.stringify(gunsOnOneSide[g])); gun.POSITION[5] += 120 * i; GUNS.push(gun); } + for (let t in turretsOnOneSide) { + let turret = JSON.parse(JSON.stringify(turretsOnOneSide[t])); + turret.POSITION[3] += 120 * i; + TURRETS.push(turret); + } }; // Gladiator @@ -2457,36 +2212,25 @@ function mergeHexnoughtWeaponV2(weapon1, weapon2) { let droneSpawnerIndex = 0 for (let g in GUNS) { let gun = GUNS[g]; - if (gun.PROPERTIES && gun.PROPERTIES.TYPE == "gladiatorTritankMinionOfficialV2") { - switch (droneSpawnerIndex) { - case 1: - gun.PROPERTIES.TYPE = "gladiatorTritrapMinionOfficialV2"; - break; - case 2: - gun.PROPERTIES.TYPE = "gladiatorTriswarmMinionOfficialV2"; - break; - case 3: - gun.PROPERTIES.TYPE = "gladiatorAutoMinionOfficialV2"; - break; - case 4: - gun.PROPERTIES.TYPE = "gladiatorAuraMinionOfficialV2"; - break; - case 5: - gun.PROPERTIES.TYPE = "gladiatorHealAuraMinionOfficialV2"; - break; - } - droneSpawnerIndex++; - } + droneSpawnerIndex = setGladiatorMinion(gun, droneSpawnerIndex); } } // Body stat modification - if (weapon1.BODY) for (let m in weapon1.BODY) BODY[m] *= weapon1.BODY[m]; - if (weapon2.BODY) for (let m in weapon2.BODY) BODY[m] *= weapon2.BODY[m]; + // Arithmetic mean of body stats + let bodyStatFactors = {FOV: 2, SPEED: 2, HEALTH: 2, SHIELD: 2, REGEN: 2, RESIST: 2, DENSITY: 2}; + let weapon1Body = weapon1.BODY ?? pentanoughtBody; + let weapon2Body = weapon2.BODY ?? pentanoughtBody; + for (let m in bodyStatFactors) { + bodyStatFactors[m] = (weapon1Body[m] ?? pentanoughtBody[m]) / pentanoughtBody[m]; + bodyStatFactors[m] += (weapon2Body[m] ?? pentanoughtBody[m]) / pentanoughtBody[m]; + bodyStatFactors[m] *= hexnoughtBody[m] / 2; + } // Smash it together Class[className] = { - PARENT, BODY, LABEL, GUNS, TURRETS, + PARENT, LABEL, GUNS, TURRETS, + BODY: bodyStatFactors }; return className; } @@ -2495,65 +2239,59 @@ function makeHexnoughtBodyV2(body) { body = ensureIsClass(body); - let PARENT = Class.genericHexnought, + let PARENT = "genericHexnought", BODY = {}, - GUNS = [], - gunsOnOneSide = [], TURRETS = [], + PROPS = [], LABEL = body.LABEL; // Label let className = LABEL.toLowerCase() + "HexOfficialV2"; - // Guns ---------------------- - if (body.GUNS) gunsOnOneSide.push(...JSON.parse(JSON.stringify(body.GUNS.slice(0, body.GUNS.length / 5 * 2)))); - for (let g in gunsOnOneSide) { - gunsOnOneSide[g].POSITION[5] *= 5 / 6; - gunsOnOneSide[g].POSITION[1] *= hexnoughtScaleFactor ** 3; - gunsOnOneSide[g].POSITION[4] *= hexnoughtScaleFactor ** 2; - } - - for (let i = 0; i < 3; i++) { - for (let g in gunsOnOneSide) { - let gun = JSON.parse(JSON.stringify(gunsOnOneSide[g])); - gun.POSITION[5] += 120 * i; - GUNS.push(gun); - } - }; - // Turrets -------------------- - let turretRingLoopLength = Math.floor(body.TURRETS.length / 5); + if (body.TURRETS) { + let turretRingLoopLength = Math.floor(body.TURRETS.length / 5); - // Turret adding - for (let t = 0; t < body.TURRETS.length; t++) { - let turret = body.TURRETS[t]; - if (turret.TYPE[0].indexOf('pentagon') >= 0) { // Replace pentagons with hexagons - TURRETS.push( - { - POSITION: [turret.POSITION[0], 0, 0, 0, 0, turret.POSITION[5]], - TYPE: ['hexagon' + turret.TYPE[0].substring(8), turret.TYPE[1]], - } - ); - } else if (turret.POSITION[1]) { // Do whole turret loop at once - for (let i = 0; i < turretRingLoopLength; i++) { - for (let j = 0; j < 6; j++) { - turret = body.TURRETS[t + i * 5]; - TURRETS.push( - { - POSITION: [turret.POSITION[0] * hexnoughtScaleFactor, turret.POSITION[1] * hexnoughtScaleFactor ** 0.5, turret.POSITION[2], turret.POSITION[3] / 6 * 5 + 60 * j, turret.POSITION[4], turret.POSITION[5]], - TYPE: turret.TYPE, - } - ) + // Turret adding + for (let t = 0; t < body.TURRETS.length; t++) { + let turret = body.TURRETS[t]; + if (turret.POSITION[1]) { // Do whole turret loop at once + for (let i = 0; i < turretRingLoopLength; i++) { + for (let j = 0; j < 6; j++) { + turret = body.TURRETS[t + i * 5 + 1]; + TURRETS.push( + { + POSITION: [turret.POSITION[0] * hexnoughtScaleFactor, turret.POSITION[1] * hexnoughtScaleFactor ** 0.5, turret.POSITION[2], turret.POSITION[3] / 6 * 5 + 60 * j, turret.POSITION[4], turret.POSITION[5]], + TYPE: turret.TYPE, + } + ) + } } + t += 5 * turretRingLoopLength - 1; + } else { // Centered turrets + TURRETS.push( + { + POSITION: [turret.POSITION[0] * hexnoughtScaleFactor ** 0.5, 0, 0, turret.POSITION[3], turret.POSITION[4], turret.POSITION[5]], + TYPE: turret.TYPE, + } + ) + } + } + } + if (body.PROPS) { + for (let prop of body.PROPS) { + prop = dereference(prop); + let type = prop.TYPE; + if (typeof type == "string") { + type = [type]; } - t += 5 * turretRingLoopLength - 1; - } else { // Centered turrets - TURRETS.push( + type[0] = type[0].replace("pentagon", "hexagon"); + PROPS.push( { - POSITION: [turret.POSITION[0] * hexnoughtScaleFactor ** 0.5, 0, 0, turret.POSITION[3], turret.POSITION[4], turret.POSITION[5]], - TYPE: turret.TYPE, + POSITION: [prop.POSITION[0], 0, 0, prop.POSITION[3], prop.POSITION[4]], + TYPE: type } - ) + ); } } @@ -2562,7 +2300,7 @@ function makeHexnoughtBodyV2(body) { // Smash it together Class[className] = { - PARENT, BODY, LABEL, GUNS, TURRETS, + PARENT, BODY, LABEL, TURRETS, PROPS, }; return [className]; } @@ -2575,4 +2313,4 @@ if(buildHexnoughts) { Class[i].UPGRADES_TIER_0.push(mergeHexnoughtWeaponV2(i, j)); } } -} +} \ No newline at end of file diff --git a/server/modules/definitions/addons/exampleAddon.js b/server/modules/definitions/addons/exampleAddon.js index 3eb655784..8c88557be 100644 --- a/server/modules/definitions/addons/exampleAddon.js +++ b/server/modules/definitions/addons/exampleAddon.js @@ -72,4 +72,4 @@ Class.exampleAddon = { }; Class.addons.UPGRADES_TIER_0.push("exampleAddon"); -console.log('[exampleAddon] The Abomination has been created.'); +console.log('[exampleAddon] The Abomination has been created.'); \ No newline at end of file diff --git a/server/modules/definitions/addons/geometryDashDart.js b/server/modules/definitions/addons/geometryDashDart.js new file mode 100644 index 000000000..99a98d793 --- /dev/null +++ b/server/modules/definitions/addons/geometryDashDart.js @@ -0,0 +1,72 @@ +const { combineStats, makeDeco } = require('../facilitators'); +const g = require('../gunvals'); + + Class.geometryDash_square = makeDeco(4, 'blue'); + Class.geometryDash_square.MIRROR_MASTER_ANGLE = true; + + Class.geometryDash_longRect = { + SHAPE: 'M 0 0 L 5 0 L 5 2 L 0 2 L 0 0', + COLOR: 'blue', + MIRROR_MASTER_ANGLE: true + }; + + Class.geometryDash = { + PARENT: 'genericTank', + LABEL: 'Geometry Dash', + SHAPE: 4, + BODY: { + HEALTH: 1e7, + SHIELD: 0, + DAMAGE: 0, + ACCELERATION: 10, + SPEED: 20, + PUSHABILITY: 0 + }, + COLOR: '#FFFF00', + SIZE: 20, + SKILL_CAP: Array(10).fill(10), + EXTRA_SKILL: 10, + FACING_TYPE: 'autospin', + TURRETS: [ + { + POSITION: { SIZE: 5, X: 4, Y: 5, LAYER: 1 }, + TYPE: 'geometryDash_square' + }, + { + POSITION: { SIZE: 5, X: 4, Y: -5, LAYER: 1 }, + TYPE: 'geometryDash_square' + }, + { + POSITION: { SIZE: 5, X: -6.1, Y: 2, ANGLE: 90, LAYER: 1 }, + TYPE: 'geometryDash_longRect' + } + ], + UPGRADES_TIER_0: ['geometryDashWave'] + } + + Class.geometryDashWave = { + PARENT: 'genericTank', + LABEL: 'Dart', + NAME: 'Wave', + SHAPE: 3, + BODY: { + HEALTH: 1e7, + DAMAGE: 1e7, + SHIELD: 0, + ACCELERATION: 0, + SPEED: 0, + PUSHABILITY: 0 + }, + COLOR: '#FFFF00', + SIZE: 20, + GUNS: [{ + POSITION: { LENGTH: 13, WIDTH: 8, ASPECT: 2, ANGLE: 180 }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.tonsmorerecoil, g.tonsmorerecoil, g.veryfast, { reload: 0.05, range: 0.2 }]), + TYPE: 'bullet', + COLOR: 'blue' + } + }] + } + + Class.addons.UPGRADES_TIER_0.push('geometryDash'); \ No newline at end of file diff --git a/server/modules/definitions/addons/labyFood.js b/server/modules/definitions/addons/labyFood.js index 72c1ba124..b05b202e9 100644 --- a/server/modules/definitions/addons/labyFood.js +++ b/server/modules/definitions/addons/labyFood.js @@ -1,8 +1,8 @@ module.exports = ({ Config }) => { // To enable this addon, simply comment out the line below. - return console.log('[labyFood.js] Addon disabled by default'); + //return console.log('[labyFood.js] Addon disabled by default'); - const disableCrashers = false; + const disableCrashers = false; // there is no `ENEMY_CAP`, so we are "reconstructing them" Config.ENEMY_CAP_NEST = 0; diff --git a/server/modules/definitions/addons/playerskins.js b/server/modules/definitions/addons/playerskins.js new file mode 100644 index 000000000..39f6d7fb0 --- /dev/null +++ b/server/modules/definitions/addons/playerskins.js @@ -0,0 +1,195 @@ +const { combineStats, makeAuto, makeOver, makeDeco, makeGuard, makeBird, makeCeption } = require('../facilitators.js'); +const { base, statnames, dfltskl, smshskl } = require('../constants.js'); +require('../groups/generics.js'); +const g = require('../gunvals.js'); + + +Class.bsignalcharm = makeDeco("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/tv.png?v=1708615075011") +Class.tcharm = makeDeco("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2024_01_29_0ry_Kleki.png?v=1708536680813") +Class.dfxcharm = makeDeco("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/MOSHED-2023-12-14-17-8-14.gif?v=1708618924966") +Class.primalcharm = makeDeco("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/primal.webp?v=1708602763032") +Class.kangaroocharm = makeDeco("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/image.webp?v=1708602765689") +Class.cogcharm = makeDeco("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Gear-icon-transparent-background.png?v=1705579178381") +Class.skypecharm = makeDeco("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/skype.png?v=1708623594494") +Class.coincharm = makeDeco("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2e2ccc30-5baf-41a2-aceb-c5456a1cc6dc.image.png?v=1708619146196") +Class.discordcharm = makeDeco("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2023_12_06_0yl_Kleki.png?v=1701908710293") +Class.incomcharm = makeDeco("https://cdn.glitch.global/68f0db33-c86d-4aa5-9a35-a6750a92eae7/1200px-Icon-round-Question_mark.svg.png?v=1699273933044") +Class.eggcharm = makeDeco("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/1165825970528325682l.webp?v=1714156807621", "veryLightGrey") +Class.squarecharm = makeDeco("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/1165934167280848969.webp?v=1714156773284", "gold") +Class.trianglecharm = makeDeco("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/1165934432608321546.webp?v=1714156768932", "orange") +Class.pentagoncharm = makeDeco("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/1165825970528325682.webp?v=1714156764280", "purple") +Class.gemcharm = makeDeco("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/1165826077843796018.webp?v=1714156778841", "aqua") +Class.tokaycharm = makeDeco("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/spider_2.png?v=1722633319003") +Class.minoscharm = makeDeco("https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/06f19349-48de-46ec-9877-6ea585848961.image.png?v=1739043712157") + +Class.bsignalskin = { + MAX_CHILDREN: 0, + SKILL_CAP: [12, 12, 12, 12, 12, 12, 12, 12, 12, 12], + SKILL: Array(10).fill(12), + TURRETS: [{ + POSITION: [18, 0, 0, 0, 360, -2], + TYPE: "bsignalcharm" + }] +}; +Class.tankcharmskin = { + MAX_CHILDREN: 0, + SKILL_CAP: [12, 12, 12, 12, 12, 12, 12, 12, 12, 12], + SKILL: Array(10).fill(12), + TURRETS: [{ + POSITION: [10, 6, 5.5, 0, 360, 3], + TYPE: "tcharm" + }] +}; +Class.dfxskin = { + MAX_CHILDREN: 0, + SKILL_CAP: [12, 12, 12, 12, 12, 12, 12, 12, 12, 12], + SKILL: Array(10).fill(12), + TURRETS: [{ + POSITION: [10, 6, 5.5, 0, 360, 3], + TYPE: "dfxcharm" + }] +}; +Class.primalskin = { + MAX_CHILDREN: 0, + SKILL_CAP: [12, 12, 12, 12, 12, 12, 12, 12, 12, 12], + SKILL: Array(10).fill(12), + TURRETS: [{ + POSITION: [10, 6, 5.5, 0, 360, 3], + TYPE: "primalcharm" + }] +}; +Class.kangarooskin = { + MAX_CHILDREN: 0, + SKILL_CAP: [12, 12, 12, 12, 12, 12, 12, 12, 12, 12], + SKILL: Array(10).fill(12), + TURRETS: [{ + POSITION: [10, 6, 5.5, 0, 360, 3], + TYPE: "kangaroocharm" + }] +}; +Class.cswmskin = { + MAX_CHILDREN: 0, + SKILL_CAP: [12, 12, 12, 12, 12, 12, 12, 12, 12, 12], + SKILL: Array(10).fill(12), + TURRETS: [{ + POSITION: [10, 6, 5.5, 0, 360, 3], + TYPE: "sandwichdeco" + }] +}; +Class.cogskin = { + MAX_CHILDREN: 0, + SKILL_CAP: [12, 12, 12, 12, 12, 12, 12, 12, 12, 12], + SKILL: Array(10).fill(12), + TURRETS: [{ + POSITION: [18, 0, 0, 0, 360, 3], + TYPE: "cogcharm" + }] +}; +Class.skypeskin = { + MAX_CHILDREN: 0, + SKILL_CAP: [12, 12, 12, 12, 12, 12, 12, 12, 12, 12], + SKILL: Array(10).fill(12), + TURRETS: [{ + POSITION: [10, 6, 5.5, 0, 360, 3], + TYPE: "skypecharm" + }] +}; +Class.coinskin = { + MAX_CHILDREN: 0, + SKILL_CAP: [12, 12, 12, 12, 12, 12, 12, 12, 12, 12], + SKILL: Array(10).fill(12), + TURRETS: [{ + POSITION: [10, 6, 5.5, 0, 360, 3], + TYPE: "coincharm" + }] +}; +Class.discordskin = { + MAX_CHILDREN: 0, + SKILL_CAP: [12, 12, 12, 12, 12, 12, 12, 12, 12, 12], + SKILL: Array(10).fill(12), + TURRETS: [{ + POSITION: [15, -5, 5.5, 0, 360, 3], + TYPE: "discordcharm" + }] +}; +Class.deltaDecoskin = { + MAX_CHILDREN: 0, + SKILL_CAP: [12, 12, 12, 12, 12, 12, 12, 12, 12, 12], + SKILL: Array(10).fill(12), + TURRETS: [{ + POSITION: [34, 0, 0, 0, 360, 3], + TYPE: "deltaDeco" + }] +}; +Class.incomskin = { + MAX_CHILDREN: 0, + SKILL_CAP: [12, 12, 12, 12, 12, 12, 12, 12, 12, 12], + SKILL: Array(10).fill(12), + TURRETS: [{ + POSITION: [10, -5, 5.5, 0, 360, 3], + TYPE: "incomcharm" + }] +}; +Class.eggskin = { + MAX_CHILDREN: 0, + SKILL_CAP: [12, 12, 12, 12, 12, 12, 12, 12, 12, 12], + SKILL: Array(10).fill(12), + TURRETS: [{ + POSITION: [15, -5, 5.5, 0, 360, 3], + TYPE: "eggcharm" + }] +}; +Class.squareskin = { + MAX_CHILDREN: 0, + SKILL_CAP: [12, 12, 12, 12, 12, 12, 12, 12, 12, 12], + SKILL: Array(10).fill(12), + TURRETS: [{ + POSITION: [13, -5, 5.5, 0, 360, 3], + TYPE: "squarecharm" + }] +}; +Class.triangleskin = { + MAX_CHILDREN: 0, + SKILL_CAP: [12, 12, 12, 12, 12, 12, 12, 12, 12, 12], + SKILL: Array(10).fill(12), + TURRETS: [{ + POSITION: [13, -5, 5.5, 0, 360, 3], + TYPE: "trianglecharm" + }] +}; +Class.pentagonskin = { + MAX_CHILDREN: 0, + SKILL_CAP: [12, 12, 12, 12, 12, 12, 12, 12, 12, 12], + SKILL: Array(10).fill(12), + TURRETS: [{ + POSITION: [10, -5, 5.5, 0, 360, 3], + TYPE: "pentagoncharm" + }] +}; +Class.gemskin = { + MAX_CHILDREN: 0, + SKILL_CAP: [12, 12, 12, 12, 12, 12, 12, 12, 12, 12], + SKILL: Array(10).fill(12), + TURRETS: [{ + POSITION: [15, -5, 5.5, 0, 360, 3], + TYPE: "gemcharm" + }] +}; +Class.tokayskin = { + MAX_CHILDREN: 0, + SKILL_CAP: [12, 12, 12, 12, 12, 12, 12, 12, 12, 12], + SKILL: Array(10).fill(12), + TURRETS: [{ + POSITION: [10, -6, 5.5, 0, 360, 3], + TYPE: "tokaycharm" + }] +}; +Class.minosskin = { + MAX_CHILDREN: 0, + SKILL_CAP: [12, 12, 12, 12, 12, 12, 12, 12, 12, 12], + SKILL: Array(10).fill(12), + TURRETS: [{ + POSITION: [10, -6, 5.5, 0, 360, 3], + TYPE: "minoscharm" + }] +}; \ No newline at end of file diff --git a/server/modules/definitions/addons/poundsnipe.js b/server/modules/definitions/addons/poundsnipe.js new file mode 100644 index 000000000..02c8910d6 --- /dev/null +++ b/server/modules/definitions/addons/poundsnipe.js @@ -0,0 +1,434 @@ +const { combineStats, makeAuto, makeOver, makeDeco, makeGuard, makeBird, makeCeption } = require('../facilitators.js'); +const { base, statnames, dfltskl, smshskl } = require('../constants.js'); +require('../groups/generics.js'); +const g = require('../gunvals.js'); + +Class.poundsnipesnipe = { + PARENT: "genericTank", + LABEL: "Kevin", + BODY: { + FOV: 1.2 * base.FOV + }, + GUNS: [ + { + POSITION: { + LENGTH: 24, + WIDTH: 8.5 + }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper]), + TYPE: "bullet" + } + }, + { + POSITION: { + LENGTH: 1, + WIDTH: 1 + }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.fake, g.lance]), + TYPE: "bullet", + ALT_FIRE: true + } + }, { + POSITION: [13.95, 5.15, 1, 0, 0, 0, 0], + PROPERTIES: { + COLOR: "#0000ff" + } + } + ], + ON: [ + { + event: "altFire", + handler: ({ body }) => { + body.define("poundsnipe0"); + setTimeout(() => body.define("poundsnipe1"), 250); + setTimeout(() => body.define("poundsnipe2"), 500); + setTimeout(() => body.define("poundsnipepound"), 750); + + } + } + ], +} +Class.poundsnipe0 = { + PARENT: "genericTank", + LABEL: "Kevin", + BODY: { + FOV: 1.15 * base.FOV + }, + GUNS: [ + { + POSITION: { + LENGTH: 23.125, + WIDTH: 9.375 + }, + }, { + POSITION: [13.95, 5.15, 1, 0, 0, 0, 0], + PROPERTIES: { + COLOR: "#4000bf" + } + } + ], +} +Class.poundsnipe1 = { + PARENT: "genericTank", + LABEL: "Kevin", + BODY: { + FOV: 1.1 * base.FOV + }, + GUNS: [ + { + POSITION: { + LENGTH: 22.25, + WIDTH: 10.25 + }, + }, { + POSITION: [13.95, 5.15, 1, 0, 0, 0, 0], + PROPERTIES: { + COLOR: "#800080" + } + } + ], +} +Class.poundsnipe2 = { + PARENT: "genericTank", + LABEL: "Kevin", + BODY: { + FOV: 1.05 * base.FOV + }, + GUNS: [ + { + POSITION: { + LENGTH: 21.375, + WIDTH: 11.125 + }, + }, { + POSITION: [13.95, 5.15, 1, 0, 0, 0, 0], + PROPERTIES: { + COLOR: "#bf0040" + } + } + ], +} +Class.poundsnipepound = { + PARENT: "genericTank", + LABEL: "Kevin", + BODY: { + FOV: 1 * base.FOV + }, + GUNS: [ + { + POSITION: { + LENGTH: 20.5, + WIDTH: 12 + }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder]), + TYPE: "bullet" + } + }, + { + POSITION: { + LENGTH: 1, + WIDTH: 1 + }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.fake, g.lance]), + TYPE: "bullet", + ALT_FIRE: true + } + }, { + POSITION: [13.95, 5.15, 1, 0, 0, 0, 0], + PROPERTIES: { + COLOR: "ff0000" + } + } + ], + ON: [ + { + event: "altFire", + handler: ({ body }) => { + body.define("poundsnipe2"); + setTimeout(() => body.define("poundsnipe1"), 250); + setTimeout(() => body.define("poundsnipe0"), 500); + setTimeout(() => body.define("poundsnipesnipe"), 750); + + } + } + ], +} + +Class.speedtripletriple = { + PARENT: "genericTank", + LABEL: "Speed Triple", + DANGER: 7, + BODY: { + HEALTH: 0.8 * base.HEALTH, + SHIELD: 0.8 * base.SHIELD, + DENSITY: 1 * base.DENSITY, + SPEED: base.SPEED * 0.9 + }, + GUNS: [ + { + POSITION: { + LENGTH: 19, + WIDTH: 8, + Y: -2, + ANGLE: -17.5, + DELAY: 0.5 + }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.tripleShot]), + TYPE: "bullet" + } + }, + { + POSITION: { + LENGTH: 19, + WIDTH: 8, + Y: 2, + ANGLE: 17.5, + DELAY: 0.5 + }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.tripleShot]), + TYPE: "bullet" + } + }, + { + POSITION: { + LENGTH: 22, + WIDTH: 8 + }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.tripleShot]), + TYPE: "bullet" + } + }, + { + POSITION: { + LENGTH: 1, + WIDTH: 1 + }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.fake, g.lance]), + TYPE: "bullet", + ALT_FIRE: true + } + },{ + POSITION: [13.95, 5.15, 1, 0, 0, 0, 0], + PROPERTIES: { + COLOR: "#0000ff" + } + } + ], + ON: [ + { + event: "altFire", + handler: ({ body }) => { + body.define("speedtriple0"); + setTimeout(() => body.define("speedtriple1"), 250); + setTimeout(() => body.define("speedtriple2"), 500); + setTimeout(() => body.define("speedtriplespeed"), 750); + + } + } + ], +} +Class.speedtriple0 = { + PARENT: "genericTank", + LABEL: "Speed Triple", + DANGER: 7, + BODY: { + HEALTH: 0.8 * base.HEALTH, + SHIELD: 0.8 * base.SHIELD, + DENSITY: 0.9 * base.DENSITY, + SPEED: base.SPEED * 0.925 + }, + GUNS: [ + { + POSITION: { + LENGTH: 18.25, + WIDTH: 8, + Y: -1.5, + ANGLE: -50.625, + DELAY: 0.5 + }, + }, + { + POSITION: { + LENGTH: 18.25, + WIDTH: 8, + Y: 1.5, + ANGLE: 50.625, + DELAY: 0.5 + }, + }, + { + POSITION: { + LENGTH: 21, + WIDTH: 8 + }, + }, { + POSITION: [13.95, 5.15, 1, 0, 0, 0, 0], + PROPERTIES: { + COLOR: "#4000bf" + } + } + ] +} +Class.speedtriple1 = { + PARENT: "genericTank", + LABEL: "Speed Triple", + DANGER: 7, + BODY: { + HEALTH: 0.8 * base.HEALTH, + SHIELD: 0.8 * base.SHIELD, + DENSITY: 0.8 * base.DENSITY, + SPEED: base.SPEED * 0.925 + }, + GUNS: [ + { + POSITION: { + LENGTH: 17.5, + WIDTH: 8, + Y: -1, + ANGLE: -83.75, + DELAY: 0.5 + }, + }, + { + POSITION: { + LENGTH: 17.5, + WIDTH: 8, + Y: 1, + ANGLE: 83.75, + DELAY: 0.5 + }, + }, + { + POSITION: { + LENGTH: 20, + WIDTH: 8 + }, + }, { + POSITION: [13.95, 5.15, 1, 0, 0, 0, 0], + PROPERTIES: { + COLOR: "#800080" + } + } + ] +} +Class.speedtriple2 = { + PARENT: "genericTank", + LABEL: "Speed Triple", + DANGER: 7, + BODY: { + HEALTH: 0.8 * base.HEALTH, + SHIELD: 0.8 * base.SHIELD, + DENSITY: 0.7 * base.DENSITY, + SPEED: base.SPEED * 0.925 + }, + GUNS: [ + { + POSITION: { + LENGTH: 16.75, + WIDTH: 8, + Y: -0.5, + ANGLE: -116.875, + DELAY: 0.5 + }, + }, + { + POSITION: { + LENGTH: 16.75, + WIDTH: 8, + Y: 0.5, + ANGLE: 116.875, + DELAY: 0.5 + }, + }, + { + POSITION: { + LENGTH: 19, + WIDTH: 8 + }, + }, { + POSITION: [13.95, 5.15, 1, 0, 0, 0, 0], + PROPERTIES: { + COLOR: "#bf0040" + } + } + ] +} +Class.speedtriplespeed = { + PARENT: "genericTank", + LABEL: "Speed Triple", + BODY: { + HEALTH: 0.8 * base.HEALTH, + SHIELD: 0.8 * base.SHIELD, + DENSITY: 0.6 * base.DENSITY, + SPEED: base.SPEED * 1 + }, + DANGER: 7, + GUNS: [ + { + POSITION: [18, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.triAngleFront, { recoil: 4 }]), + TYPE: "bullet", + LABEL: "Front", + }, + }, + { + POSITION: [16, 8, 1, 0, 0, 150, 0.1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), + TYPE: "bullet", + LABEL: "thruster", + }, + }, + { + POSITION: [16, 8, 1, 0, 0, 210, 0.1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), + TYPE: "bullet", + LABEL: "thruster", + }, + }, + { + POSITION: { + LENGTH: 1, + WIDTH: 1 + }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.fake, g.lance]), + TYPE: "bullet", + ALT_FIRE: true + } + },{ + POSITION: [13.95, 5.15, 1, 0, 0, 0, 0], + PROPERTIES: { + COLOR: "ff0000" + } + } + ], + ON: [ + { + event: "altFire", + handler: ({ body }) => { + body.define("speedtriple2"); + setTimeout(() => body.define("speedtriple1"), 250); + setTimeout(() => body.define("speedtriple0"), 500); + setTimeout(() => body.define("speedtripletriple"), 750); + + } + } + ], +} + +Class.sniper.UPGRADES_TIER_3.push("poundsnipesnipe") +Class.pounder.UPGRADES_TIER_3.push("poundsnipepound") +Class.tripleShot.UPGRADES_TIER_3.push("speedtripletriple") +Class.triAngle.UPGRADES_TIER_3.push("speedtriplespeed") +Class.addons.UPGRADES_TIER_0.push("poundsnipesnipe", "speedtripletriple") \ No newline at end of file diff --git a/server/modules/definitions/addons/solario.js b/server/modules/definitions/addons/solario.js new file mode 100644 index 000000000..c43394e11 --- /dev/null +++ b/server/modules/definitions/addons/solario.js @@ -0,0 +1,1260 @@ +const { combineStats, makeDeco } = require('../facilitators.js'); +const { base, dfltskl, statnames } = require('../constants.js'); +const g = require('../gunvals.js'); + +Class.solarioTurret1 = { + PARENT: "genericTank", + LABEL: "Turret", + CONTROLLERS: ["canRepel", "onlyAcceptInArc", "mapAltToFire", "nearestDifferentMaster"], + COLOR: 13, + SHAPE: 0, + BODY: { + FOV: 0.8, + }, + HAS_NO_RECOIL: true, + GUNS: [ + { + POSITION: [16, 14, 1, 0, 0, 0, 0], + }, + { + POSITION: [4, 14, 1.8, 16, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, g.flankGuard, g.autoTurret, { reload: 1.3 }]), + TYPE: "trap" + }, + }, + ], +} +Class.solarioRingTurret = { + PARENT: "genericTank", + LABEL: "Turret", + COLOR: 13, + HAS_NO_RECOIL: true, + MIRROR_MASTER_ANGLE: true, + GUNS: [{ + POSITION: [10, 8, 0, 0, 0, 180, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, {reload: 1.25, recoil: 0, size: 1.7}, g.autoTurret, { reload: 2, speed: 2, maxSpeed: 2 }]), + TYPE: ["laser", { ARENA_CLOSER: true }], + AUTOFIRE: true + }, + }, { + POSITION: [24, 1, 1, 0, 0, 180, 2 / 3], + PROPERTIES: { + COLOR: 'red', + }, + }], +} +Class.solarioCircAttack = { + PARENT: "bullet", + SHAPE: "M 0 -1 A 1 1 0 0 0 0 1 A 1 1 0 0 0 0 -1 Z M 0 -1 A 0.001 0.001 0 0 1 0 1 A 0.001 0.001 0 0 1 0 -1", + FACING_TYPE: ["spin", { speed: 0.02 }], + MOTION_TYPE: ["grow", { growSpeed: 2 }], + ARENA_CLOSER: true +} +Class.solarioTurret2 = { + PARENT: "genericTank", + CONTROLLERS: ["canRepel", "onlyAcceptInArc", "mapAltToFire", "nearestDifferentMaster"], + LABEL: "Turret", + COLOR: 13, + SHAPE: 3, + BODY: { + FOV: 0.8, + }, + HAS_NO_RECOIL: true, + GUNS: [ + { + POSITION: [26, 10, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.autoTurret, { reload: 1.5 }]), + TYPE: "bullet" + }, + }, + ], +} +Class.solarioTurret3 = { + PARENT: "genericTank", + LABEL: "Turret", + CONTROLLERS: ["canRepel", "onlyAcceptInArc", "mapAltToFire", "nearestDifferentMaster"], + SHAPE: 4, + COLOR: 13, + BODY: { + FOV: 0.8, + }, + HAS_NO_RECOIL: true, + GUNS: [ + { + POSITION: [16, 4, 1, 0, -3.5, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.autoTurret, g.pelleter, g.twin, g.power]), + TYPE: "bullet", + HAS_NO_RECOIL: true + }, + }, + { + POSITION: [16, 4, 1, 0, 3.5, 0, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.autoTurret, g.pelleter, g.twin, g.power]), + TYPE: "bullet" + }, + }, + ], +} +Class.solarioTurret4 = { + PARENT: "genericTank", + LABEL: "Turret", + CONTROLLERS: ["canRepel", "onlyAcceptInArc", "mapAltToFire", "nearestDifferentMaster"], + COLOR: 13, + SHAPE: 6, + BODY: { + FOV: 0.8, + }, + HAS_NO_RECOIL: true, + GUNS: [ + { + POSITION: [22, 14, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.autoTurret]), + TYPE: "bullet" + }, + }, + ], +} +Class.laser = { + PARENT: "bullet", + SHAPE: -1, + BODY: { + PENETRATION: 1.1, + SPEED: 5.8, + RANGE: 100, + DENSITY: 0.9, + HEALTH: 0.155, + DAMAGE: 5.6, + }, + BUFF_VS_FOOD: true, +} +Class.hyperlaser = { + PARENT: "laser", + SHAPE: "M -1 -1 L 8 -1 L 8 1 L -1 1 L -1 -1", + IMMUNE_TO_TILES: true, + BORDERLESS: true, +} +Class.solariominilaser = { + PARENT: "genericTank", + LABEL: "Solario SMG", + DANGER: 6, + HAS_NO_RECOIL: true, + BODY: { + FOV: 1.2, + }, + GUNS: [ + { + /*** LENGTH WIDTH ASPECT X Y ANGLE DELAY */ + POSITION: [21, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, { reload: 0.5 }, { reload: 1.333 }]), + TYPE: "laser", + }, + }, + { + POSITION: [19, 8, 1, 0, 0, 0, 1 / 3], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, { reload: 0.5 }, { reload: 1.333 }]), + TYPE: "laser", + }, + }, + { + POSITION: [17, 8, 1, 0, 0, 0, 2 / 3], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, { reload: 0.5 }, { reload: 1.333 }]), + TYPE: "laser", + }, + }, + { + POSITION: [24, 1, 1, 0, 0, 0, 0], + PROPERTIES: { + COLOR: 'red', + SHOOT_SETTINGS: combineStats([g.fake]), + TYPE: "laser", + }, + } + ], +} +/*Class.revogun = { + LABEL: 'Auto Turret', + SYNC_TURRET_SKILLS: true, + BODY: { + FOV: 1 + }, + COLOR: 16, + CONTROLLERS: ['onlyAcceptInArc', 'nearestDifferentMaster'], + GUNS: [{ + POSITION: [13.5, 10, 1, 8, 0, 0, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.autoTurret, { reload: 2 }]), + TYPE: "bullet" + } + } + ] +} +Class.turretBaseKiva = { + LABEL: "Basethingygygyyasgsdgajskhg", + SHAPE: 'M 0 -1 A 1 1 0 0 0 0 1 A 1 1 0 0 0 0 -1 Z M 0 -1 A 0.001 0.001 0 0 1 0 1 A 0.001 0.001 0 0 1 0 -1', + COLOR: "#FC8208",//iT WonT FUckING SpIN + SYNC_TURRET_SKILLS: true, + CONTROLLERS: [["spin", { independent: true }]], + INDEPENDENT: true, + TURRETS: [{ + POSITION: [4.65, 9.85, 0, 90, 220, 1], + TYPE: ["revogun", { COLOR: "#FC8208" }] + }, { + POSITION: [4.65, 9.85, 0, 270, 220, 1], + TYPE: ["revogun", { COLOR: "#FC8208" }] + }] +}; +Class.baseBullet = { + PARENT: "trap", + MOTION_TYPE: "motor", + HITS_OWN_TYPE: "never", + BODY: { + SPEED: 1.25, + RANGE: 120, + }, + LABEL: "Base", + SHAPE: 'M 0 -1 A 1 1 0 0 0 0 1 A 1 1 0 0 0 0 -1 Z M 0 -1 A 0.001 0.001 0 0 1 0 1 A 0.001 0.001 0 0 1 0 -1', + CONTROLLERS: [["spin", { independent: true, speed: 0.1 }], "boomerang"], + INDEPENDENT: true, + FACING_TYPE: "toTarget", + COLOR: "#FC8208", + TURRETS: [{ + POSITION: [4.65, 9.85, 0, 90, 220, 1], + TYPE: ["revogun", { COLOR: "#FC8208", BODY: { FOV: 2 } }] + }, { + POSITION: [4.65, 9.85, 0, 270, 220, 1], + TYPE: ["revogun", { COLOR: "#FC8208", BODY: { FOV: 2 } }] + }], +ON: [{ + event: "death", + handler: ({ body }) => { + if (!body.master.isDead) return + body.master.define(Class.baseThrower) + } + } + ] +}; +Class.baseThrower = { + PARENT: "genericTank", + LABEL: "Kivaaritehdas", + DANGER: 6, + SYNC_TURRET_SKILLS: true, + GUNS: [{ + POSITION: [20, 8, 1, 0, 0, 0, 0.2], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard]), + TYPE: "bullet" + } + }, { + POSITION: [1, 38, 1, 0, 0, 0, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, g.setTrap, g.boomerang, { damage: 0.3, pen: 0.2, health: 4, range: 1.5, speed: 1, maxSpeed: 1.4 }]), + TYPE: ["baseBullet", { COLOR: "#FC8208", KEEP_OWN_COLOR: false }], + ALT_FIRE: true, + ALPHA: 0 + } + }], + TURRETS: [{ + POSITION: [34, 0, 0, 0, 360, 0], + TYPE: "turretBaseKiva", + }], + ON: [{ + event: "altFire", + handler: ({ body }) => { + body.define(Class.baseThrowerFire, true) + } + } + ] +}; +Class.baseThrowerFire = { + PARENT: "genericTank", + LABEL: "Kivaaritehdas", + DANGER: 6, + GUNS: [{ + POSITION: [20, 8, 1, 0, 0, 0, 0.2], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard]), + TYPE: "bullet" + } + }] +};*/ +Class.solarioturretBase = { + LABEL: "Base", + SHAPE: 'M 0 -1.6 A 1.5 1.5 0 0 0 0 1.6 A 1.5 1.5 0 0 0 0 -1.6 Z M 0 -1.5 A 0.001 0.001 0 0 1 0 1.5 A 0.001 0.001 0 0 1 0 -1.5', + COLOR: 13, + SYNC_TURRET_SKILLS: true, + CONTROLLERS: [["spin", { independent: true }]], + INDEPENDENT: true, + TURRETS: [{ + POSITION: [5, 15, 0, 90, 220, 1], + TYPE: "solarioTurret1", + }, { + POSITION: [5, 15, 0, 180, 220, 1], + TYPE: "solarioTurret2", + }, { + POSITION: [5, 15, 0, 270, 220, 1], + TYPE: "solarioTurret3", + }, { + POSITION: [5, 15, 0, 0, 220, 1], + TYPE: "solarioTurret4", + }] +} +Class.solarioturretBase2ndRing = { + LABEL: "Base", + SHAPE: 'M 0 -3.1 A 3 3 0 0 0 0 3.1 A 3 3 0 0 0 0 -3.1 Z M 0 -3 A 0.001 0.001 0 0 1 0 3 A 0.001 0.001 0 0 1 0 -3', + COLOR: 13, + CONTROLLERS: [["spin", { independent: true }]], + INDEPENDENT: true, + TURRETS: [{ + POSITION: [5, 30, 0, 90, 220, 1], + TYPE: "solarioTurret1", + }, { + POSITION: [5, 30, 0, 180, 220, 1], + TYPE: "solarioTurret2", + }, { + POSITION: [5, 30, 0, 270, 220, 1], + TYPE: "solarioTurret3", + }, { + POSITION: [5, 30, 0, 0, 220, 1], + TYPE: "solarioTurret4", + }] +} +Class.solarioRingAttack = { + LABEL: "Base", + SHAPE: 'M 0 -3.1 A 3 3 0 0 0 0 3.1 A 3 3 0 0 0 0 -3.1 Z M 0 -3 A 0.001 0.001 0 0 1 0 3 A 0.001 0.001 0 0 1 0 -3', + COLOR: 13, + BODY: { + PUSHABILITY: 0, + RANGE: 300, + }, + ARENA_CLOSER: true, + DIE_AT_RANGE: true, + MOTION_TYPE: "solarioarena", + FACING_TYPE: ["spin", { speed: 0.3 }], + INDEPENDENT: true, + TURRETS: [{ + POSITION: [3, 30, 0, 270, 0, 1], + TYPE: "solarioRingTurret", + }, { + POSITION: [3, 30, 0, 0, 0, 1], + TYPE: "solarioRingTurret", + }, { + POSITION: [3, 30, 0, 90, 0, 1], + TYPE: "solarioRingTurret", + }, { + POSITION: [3, 30, 0, 180, 0, 1], + TYPE: "solarioRingTurret", + }] +} +Class.solarioturretBase2 = { + LABEL: "Base", + SHAPE: 'M 0 -1.6 A 1.5 1.5 0 0 0 0 1.6 A 1.5 1.5 0 0 0 0 -1.6 Z M 0 -1.5 A 0.001 0.001 0 0 1 0 1.5 A 0.001 0.001 0 0 1 0 -1.5', + COLOR: 33, + CONTROLLERS: [["spin", { independent: true }]], + INDEPENDENT: true, + TURRETS: [{ + POSITION: [5, 15, 0, 90, 220, 1], + TYPE: ["solarioTurret1", { COLOR: 33 }], + }, { + POSITION: [5, 15, 0, 180, 220, 1], + TYPE: ["solarioTurret2", { COLOR: 33 }], + }, { + POSITION: [5, 15, 0, 270, 220, 1], + TYPE: ["solarioTurret3", { COLOR: 33 }], + }, { + POSITION: [5, 15, 0, 0, 220, 1], + TYPE: ["solarioTurret4", { COLOR: 33 }], + }] +} +Class.solarioturretBase2ndRing2 = { + LABEL: "Base", + SHAPE: 'M 0 -3.1 A 3 3 0 0 0 0 3.1 A 3 3 0 0 0 0 -3.1 Z M 0 -3 A 0.001 0.001 0 0 1 0 3 A 0.001 0.001 0 0 1 0 -3', + COLOR: 33, + CONTROLLERS: [["spin", { independent: true }]], + INDEPENDENT: true, + TURRETS: [{ + POSITION: [5, 30, 0, 90, 220, 1], + TYPE: ["rocketeerTurret", { COLOR: 33, HAS_NO_RECOIL: true }], + }, { + POSITION: [5, 30, 0, 180, 220, 1], + TYPE: ["boomerTurret", { COLOR: 33, HAS_NO_RECOIL: true }], + }, { + POSITION: [5, 30, 0, 270, 220, 1], + TYPE: ["barricadeTurret", { COLOR: 33, HAS_NO_RECOIL: true }], + }, { + POSITION: [5, 30, 0, 0, 220, 1], + TYPE: ["bigauto4gun", { COLOR: 33, HAS_NO_RECOIL: true }], + }] +} +Class.solarioturretBase3 = { + LABEL: "Base", + SHAPE: 'M 0 -1.6 A 1.5 1.5 0 0 0 0 1.6 A 1.5 1.5 0 0 0 0 -1.6 Z M 0 -1.5 A 0.001 0.001 0 0 1 0 1.5 A 0.001 0.001 0 0 1 0 -1.5', + COLOR: 32, + CONTROLLERS: [["spin", { independent: true }]], + INDEPENDENT: true, + TURRETS: [{ + POSITION: [5, 15, 0, 90, 220, 1], + TYPE: ["solarioTurret1", { COLOR: 32, HAS_NO_RECOIL: true }], + }, { + POSITION: [5, 15, 0, 180, 220, 1], + TYPE: ["solarioTurret2", { COLOR: 32, HAS_NO_RECOIL: true }], + }, { + POSITION: [5, 15, 0, 270, 220, 1], + TYPE: ["solarioTurret3", { COLOR: 32, HAS_NO_RECOIL: true }], + }, { + POSITION: [5, 15, 0, 0, 220, 1], + TYPE: ["solarioTurret4", { COLOR: 32, HAS_NO_RECOIL: true }], + }] +} +Class.solarioturretBase2ndRing3 = { + LABEL: "Base", + SHAPE: 'M 0 -3.1 A 3 3 0 0 0 0 3.1 A 3 3 0 0 0 0 -3.1 Z M 0 -3 A 0.001 0.001 0 0 1 0 3 A 0.001 0.001 0 0 1 0 -3', + COLOR: 32, + CONTROLLERS: [["spin", { independent: true }]], + INDEPENDENT: true, + TURRETS: [{ + POSITION: [5, 30, 0, 90, 220, 1], + TYPE: ["rocketeerTurret", { COLOR: 32, HAS_NO_RECOIL: true }], + }, { + POSITION: [5, 30, 0, 180, 220, 1], + TYPE: ["boomerTurret", { COLOR: 32, HAS_NO_RECOIL: true }], + }, { + POSITION: [5, 30, 0, 270, 220, 1], + TYPE: ["barricadeTurret", { COLOR: 32, HAS_NO_RECOIL: true }], + }, { + POSITION: [5, 30, 0, 0, 220, 1], + TYPE: ["bigauto4gun", { COLOR: 32, HAS_NO_RECOIL: true }], + }] +} +Class.solarioturretBase3rdRing3 = { + LABEL: "Base", + SHAPE: 'M 0 -4.8 A 4.5 4.5 90 0 0 0 4.8 A 4.5 4.5 90 0 0 0 -4.8 Z M 0 -4.5 A 0.001 0.001 90 0 1 0 4.5 A 0.001 0.001 90 0 1 0 -4.5', + COLOR: 32, + CONTROLLERS: [["spin", { independent: true }]], + INDEPENDENT: true, + TURRETS: [{ + POSITION: [5, 47, 0, 60, 220, 1], + TYPE: ["machineTripleTurret", { COLOR: 32, HAS_NO_RECOIL: true }], + }, { + POSITION: [5, 47, 0, 120, 220, 1], + TYPE: ["launcherTurret", { COLOR: 32, HAS_NO_RECOIL: true }], + }, { + POSITION: [5, 47, 0, 180, 220, 1], + TYPE: ["skimmerTurret", { COLOR: 32, HAS_NO_RECOIL: true }], + }, { + POSITION: [5, 47, 0, 240, 220, 1], + TYPE: ["twisterTurret", { COLOR: 32, HAS_NO_RECOIL: true }], + }, { + POSITION: [5, 47, 0, 300, 220, 1], + TYPE: ["nailgunTurret", { COLOR: 32, HAS_NO_RECOIL: true }], + }, { + POSITION: [5, 47, 0, 0, 220, 1], + TYPE: ["artilleryTurret", { COLOR: 32, HAS_NO_RECOIL: true }], + }] +} +Class.solarioOutline = makeDeco("M 0 -3.1 A 3 3 0 0 0 0 3.1 A 3 3 0 0 0 0 -3.1 Z M 0 -3 A 0.001 0.001 0 0 1 0 3 A 0.001 0.001 0 0 1 0 -3", 13) +Class.solariobase = { + PARENT: "genericBoss", + HAS_NO_RECOIL: true, + FACING_TYPE: ['spin', {speed: 0.015}], + LABEL: "Solario", + SHAPE: 0, + UPGRADE_TOOLTIP: "𝒯𝒽𝑒 𝒹𝓎𝒾𝓃𝑔 𝓈𝓉𝒶𝓇", + BODY: { + HEALTH: 5500, + }, + SIZE: 15, + DANGER: 15, +} +Class.solario = { + PARENT: "solariobase", + COLOR: 13, + GLOW: { + RADIUS: 50, + COLOR: 13, + ALPHA: 1, + RECURSION: 8 + }, + GUNS: [{ + POSITION: [15, 10, 1, 0, 0, 0, 0], + }, { + POSITION: [15, 10, 1, 0, 0, 180, 0], + }, { + POSITION: [0, 0, 1, 0, 0, 0, 25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.fake, { reload: 5 }]), + TYPE: "bullet", + AUTOFIRE: true, + IDENTIFIER: "startlaserattack" + }, + }, { + POSITION: [1, 10, 1, 0, 0, 0, 1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.fake, { reload: 75 }]), + TYPE: "bullet", + AUTOFIRE: true, + IDENTIFIER: "solarioAttack" + }, + }, { + POSITION: [1, 10, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { reload: 8, recoil: 0, shudder: 4.25, size: 2, health: 2.25, damage: 1.75, pen: 1.5, speed: 1.35, spray: 4 }, { health: 15 }, { maxSpeed: 0, speed: 0, range: 5, pen: 3 }]), + TYPE: "solarioCircAttack", + ALT_FIRE: true, + }, + }, { + POSITION: [1, 10, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { health: 999 }, { maxSpeed: 0, speed: 0, range: 1.4, reload: 5 }]), + TYPE: "solarioRingAttack", + ALT_FIRE: true + }, + }, { + POSITION: [1, 10, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { health: 999 }, {speed: 0.01, maxSpeed: 0.01, health: 99999, pen: 99, density: 38281381283, resist: 421848412}]), + TYPE: ["blackholeondeath", { PERSISTS_AFTER_DEATH: true }], + SHOOT_ON_DEATH: true, + ALT_FIRE: true + } + }, + ], + TURRETS: [{ + POSITION: [30, 0, 0, 0, 360, 0], + TYPE: "solarioturretBase", + }, { + POSITION: [30, 0, 0, 0, 360, 0], + TYPE: "solarioturretBase2ndRing", + }, { + POSITION: [16, 0, 0, 0, 360, 3], + TYPE: ["solariominilaser", { HAS_NO_RECOIL: true, CONTROLLERS: ["canRepel", "onlyAcceptInArc", "mapAltToFire", "nearestDifferentMaster"]}] + }, { + POSITION: [8.2, 0, 0, 0, 360, 2], + TYPE: "solarioOutline" + }, + ], + ON: [ + { + event: 'fire', + handler: ({ body, gun }) => { + if (gun.identifier == 'startlaserattack') { + sockets.broadcast('Solario: DODGE THIS!!'); + setTimeout(() => body.define('solariolaser'), 1000); + } + if (gun.identifier == 'solarioAttack') { + body.guns[3].canShoot = false; + let attack = ~~(Math.random() * 2); + switch(attack) { + case 0: + body.guns[4].fire(); + setTimeout(() => { if (body != null) body.guns[4].fire(); }, 12000); + break; + case 1: + body.guns[5].fire(); + break; + } + } + } + }, { + event: "death", + handler: ({}) => { + sockets.broadcast('NOOOOOOO!') + } + }, { + event: "damage", + handler: ({ body }) => { + if (body.health.amount < (body.health.max / 3) * 2) { + sockets.broadcast('Solario: YOU CANT STOP ME!!!!!'); + body.define('solariophase2'); + } + } + } + ], +} +Class.solariolaser = { + PARENT: "solariobase", + COLOR: 13, + GLOW: { + RADIUS: 50, + COLOR: 13, + ALPHA: 1, + RECURSION: 8 + }, + BODY: { + REGEN: 0, + }, + GUNS: [{ + POSITION: [15, 10, 1, 0, 0, 0, 5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { reload: 0.05, health: 5, pen: 100, speed: 14, maxSpeed: 14, spread: 4, size: 2, range: 0.6 }]), + TYPE: "laser", + AUTOFIRE: true, + COLOR: "red", + }, + }, { + POSITION: [15, 10, 1, 0, 0, 180, 5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { reload: 0.05, health: 5, pen: 100, speed: 14, maxSpeed: 14, spread: 4, size: 2, range: 0.6 }]), + TYPE: "laser", + AUTOFIRE: true, + COLOR: "red", + }, + }, { + POSITION: [350, 10, 2.5, 0, 0, 360, 0], + PROPERTIES: { + COLOR: "red", + ALPHA: 0.5 + } + }, { + POSITION: [350, 10, 2.5, 0, 0, 180, 0], + PROPERTIES: { + COLOR: "red", + ALPHA: 0.5 + } + }, { + POSITION: [0, 0, 1, 0, 0, 0, 15], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.fake, { reload: 5 }]), + TYPE: "bullet", + AUTOFIRE: true, + IDENTIFIER: "endlaserattack", + }, + }, { + POSITION: [1, 10, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { health: 999 }, {speed: 0.01, maxSpeed: 0.01, health: 99999, pen: 99, density: 38281381283, resist: 421848412}]), + TYPE: "blackholeondeath", + SHOOT_ON_DEATH: true, + ALT_FIRE: true + } + }, + ], + TURRETS: [{ + POSITION: [30, 0, 0, 0, 360, 0], + TYPE: "solarioturretBase", + }, { + POSITION: [30, 0, 0, 0, 360, 0], + TYPE: "solarioturretBase2ndRing", + }, { + POSITION: [16, 0, 0, 0, 360, 3], + TYPE: ["solariominilaser", { HAS_NO_RECOIL: true, CONTROLLERS: ["canRepel", "onlyAcceptInArc", "mapAltToFire", "nearestDifferentMaster"]}] + }, { + POSITION: [8.2, 0, 0, 0, 360, 2], + TYPE: "solarioOutline" + }, + ], + ON: [ + { + event: 'fire', + handler: ({ body, gun }) => { + if (gun.identifier == 'endlaserattack') { + sockets.broadcast('Solario: RAHH!'); + body.children = []; + setTimeout(() => body.define('solario'), 500); + } + } + }, { + event: "death", + handler: ({}) => { + sockets.broadcast('NOOOOOOO!') + } + }, { + event: "damage", + handler: ({ body }) => { + if (body.health.amount < (body.health.max / 3) * 2) { + sockets.broadcast('Solario: YOU CANT STOP ME!!!!!'); + body.define('solariolaserphase2'); + } + } + } + ], +}; +Class.solariophase2 = { + PARENT: "solariobase", + COLOR: 33, + GLOW: { + RADIUS: 50, + STRENGTH: 30, + COLOR: 33, + ALPHA: 0.8, + RECURSION: 8 + }, + GUNS: [{ + POSITION: [15, 10, 1, 0, 0, 0, 0], + }, { + POSITION: [15, 10, 1, 0, 0, 90, 0], + }, { + POSITION: [15, 10, 1, 0, 0, 180, 0], + }, { + POSITION: [15, 10, 1, 0, 0, 270, 0], + }, { + POSITION: [0, 0, 1, 0, 0, 0, 25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.fake, { reload: 5 }]), + TYPE: "bullet", + AUTOFIRE: true, + IDENTIFIER: "startlaserattack", + }, + }, { + POSITION: [1, 10, 1, 0, 0, 0, 1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.fake, { reload: 75 }]), + TYPE: "bullet", + AUTOFIRE: true, + IDENTIFIER: "solarioAttack" + }, + }, { + POSITION: [1, 10, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { reload: 8, recoil: 0, shudder: 4.25, size: 2, health: 2.25, damage: 1.75, pen: 1.5, speed: 1.35, spray: 4 }, { health: 999 }, { maxSpeed: 0, speed: 0, range: 5, pen: 3 }]), + TYPE: ["solarioCircAttack", { COLOR: 33}], + ALT_FIRE: true, + }, + }, { + POSITION: [1, 10, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { health: 999 }, { maxSpeed: 0, speed: 0, range: 1.4, reload: 5 }]), + TYPE: ["solarioRingAttack", { COLOR: 33}], + ALT_FIRE: true + }, + }, { + POSITION: [1, 10, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, { health: 4, size: 2 }]), + TYPE: "baseThrower", + ALT_FIRE: true + } + }, { + POSITION: [1, 10, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { health: 999 }, {speed: 0.01, maxSpeed: 0.01, health: 99999, pen: 99, density: 38281381283, resist: 421848412}]), + TYPE: "blackholeondeath", + SHOOT_ON_DEATH: true, + ALT_FIRE: true + } + }, + ], + TURRETS: [{ + POSITION: [30, 0, 0, 0, 360, 0], + TYPE: ["solarioturretBase2", { COLOR: 33 }], + }, { + POSITION: [30, 0, 0, 0, 360, 0], + TYPE: ["solarioturretBase2ndRing2", { COLOR: 33 }], + }, { + POSITION: [16, 0, 0, 0, 360, 3], + TYPE: ["solariominilaser", { HAS_NO_RECOIL: true, CONTROLLERS: ["canRepel", "onlyAcceptInArc", "mapAltToFire", "nearestDifferentMaster"]}] + }, { + POSITION: [8.2, 0, 0, 0, 360, 2], + TYPE: ["solarioOutline", { COLOR: 33 }] + }, + ], + ON: [ +{ + event: 'fire', + handler: ({ body, gun }) => { + if (gun.identifier == 'startlaserattack') { + sockets.broadcast('Solario: DODGE THIS!!'); + setTimeout(() => body.define('solariolaserphase2'), 1000); + } + if (gun.identifier == 'solarioAttack') { + body.guns[3].canShoot = false; + let attack = ~~(Math.random() * 3); + switch(attack) { + case 0: + body.guns[6].fire(); + setTimeout(() => { if (body != null) body.guns[6].fire(); }, 6000); + setTimeout(() => { if (body != null) body.guns[6].fire(); }, 12000); + break; + case 1: + body.guns[7].fire(); + break; + case 2: + body.guns[8].fire(); + setTimeout(() => { if (body != null) body.guns[8].fire(); }, 500); + setTimeout(() => { if (body != null) body.guns[8].fire(); }, 1000); + setTimeout(() => { if (body != null) body.guns[8].fire(); }, 1500); + break; + } + } + } + }, { + event: "death", + handler: ({}) => { + sockets.broadcast('NOOOOOOO!') + } + }, { + event: "damage", + handler: ({ body }) => { + if (body.health.amount < body.health.max / 3) { + sockets.broadcast('Solario: GRRRAAAAAH, THATS IT!!!!!'); + body.define('solariophase3'); + } + } + }, + ], +}; +Class.solariolaserphase2 = { + PARENT: "solariophase2", + BODY: { + REGEN: 0, + }, + GUNS: [{ + POSITION: [15, 10, 1, 0, 0, 0, 5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { reload: 0.05, health: 5, pen: 100, speed: 14, maxSpeed: 14, spread: 4, size: 2, range: 0.6 }]), + TYPE: "laser", + AUTOFIRE: true, + COLOR: "red", + }, + }, { + POSITION: [15, 10, 1, 0, 0, 90, 5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { reload: 0.05, health: 5, pen: 100, speed: 14, maxSpeed: 14, spread: 4, size: 2, range: 0.6 }]), + TYPE: "laser", + AUTOFIRE: true, + COLOR: "red", + }, + }, { + POSITION: [15, 10, 1, 0, 0, 180, 5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { reload: 0.05, health: 5, pen: 100, speed: 14, maxSpeed: 14, spread: 4, size: 2, range: 0.6 }]), + TYPE: "laser", + AUTOFIRE: true, + COLOR: "red", + }, + }, { + POSITION: [15, 10, 1, 0, 0, 270, 5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { reload: 0.05, health: 5, pen: 100, speed: 14, maxSpeed: 14, spread: 4, size: 2, range: 0.6 }]), + TYPE: "laser", + AUTOFIRE: true, + COLOR: "red", + }, + }, { + POSITION: [350, 10, 2.5, 0, 0, 360, 0], + PROPERTIES: { + COLOR: "red", + ALPHA: 0.5 + } + }, { + POSITION: [350, 10, 2.5, 0, 0, 90, 0], + PROPERTIES: { + COLOR: "red", + ALPHA: 0.5 + } + }, { + POSITION: [350, 10, 2.5, 0, 0, 180, 0], + PROPERTIES: { + COLOR: "red", + ALPHA: 0.5 + } + }, { + POSITION: [350, 10, 2.5, 0, 0, 270, 0], + PROPERTIES: { + COLOR: "red", + ALPHA: 0.5 + } + }, { + POSITION: [0, 0, 1, 0, 0, 0, 15], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.fake, { reload: 5 }]), + TYPE: "bullet", + AUTOFIRE: true, + IDENTIFIER: "endlaserattack", + }, + }, { + POSITION: [1, 10, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { health: 999 }, {speed: 0.01, maxSpeed: 0.01, health: 99999, pen: 99, density: 38281381283, resist: 421848412}]), + TYPE: "blackholeondeath", + SHOOT_ON_DEATH: true, + ALT_FIRE: true + } + }, + ], + ON: [ + { + event: 'fire', + handler: ({ body, gun }) => { + if (gun.identifier == 'endlaserattack') { + sockets.broadcast('Solario: RAHH!'); + setTimeout(() => body.define('solariophase2'), 500); + } + } + }, { + event: "death", + handler: ({ body }) => { + sockets.broadcast('NOOOOOOO!') + } + }, { + event: "damage", + handler: ({ body }) => { + if (body.health.amount < body.health.max / 3) { + sockets.broadcast('Solario: GRRRAAAAAH, THATS IT!!!!!'); + body.define('solariolaserphase3'); + } + } + }, + ], +} +Class.solariophase3 = { + PARENT: "solariobase", + SKILL_CAP: Array(10).fill(12), + SKILL: Array(10).fill(12), + COLOR: 32, + GLOW: { + RADIUS: 60, + STRENGTH: 32, + COLOR: 32, + ALPHA: 1, + RECURSION: 10 + }, + GUNS: [{ + POSITION: [15, 20, 1, 0, 0, 0, 0], + }, { + POSITION: [15, 10, 1, 0, 0, 60, 0], + }, { + POSITION: [15, 10, 1, 0, 0, 120, 0], + }, { + POSITION: [15, 20, 1, 0, 0, 180, 0], + }, { + POSITION: [15, 10, 1, 0, 0, 240, 0], + }, { + POSITION: [15, 10, 1, 0, 0, 300, 0], + }, { + POSITION: [0, 0, 1, 0, 0, 0, 25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.fake, { reload: 5 }]), + TYPE: "bullet", + AUTOFIRE: true, + IDENTIFIER: "startlaserattack", + }, + }, { + POSITION: [1, 10, 1, 0, 0, 0, 1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.fake, { reload: 75 }]), // reload: 75 + TYPE: "bullet", + AUTOFIRE: true, + IDENTIFIER: "solarioAttack" + }, + }, { + POSITION: [1, 10, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { reload: 8, recoil: 0, shudder: 4.25, size: 2, health: 2.25, damage: 1.75, pen: 1.5, speed: 1.35, spray: 4 }, { health: 999 }, { maxSpeed: 0, speed: 0, range: 5, pen: 3 }]), + TYPE: ["solarioCircAttack", { COLOR: 32 }], + ALT_FIRE: true, + }, + }, { + POSITION: [1, 10, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { health: 999 }, { maxSpeed: 0, speed: 0, range: 1.4, reload: 5 }]), + TYPE: ["solarioRingAttack", { COLOR: 32 }], + ALT_FIRE: true + }, + }, { + POSITION: [1, 10, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, { health: 10, size: 2.5 }]), + TYPE: "baseThrower", + ALT_FIRE: true + } + }, { + POSITION: [1, 10, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { health: 999 }, {speed: 0.01, range: 7, maxSpeed: 0.01, health: 99999, pen: 99, density: 38281381283, resist: 421848412}]), + TYPE: ["blackholeondeath", { PERSISTS_AFTER_DEATH: true }], + ALT_FIRE: true, + SHOOT_ON_DEATH: true + } + }, + ], + TURRETS: [{ + POSITION: [30, 0, 0, 0, 360, 0], + TYPE: ["solarioturretBase3", { COLOR: 32 }], + }, { + POSITION: [30, 0, 0, 0, 360, 0], + TYPE: ["solarioturretBase2ndRing3", { COLOR: 32 }], + }, { + POSITION: [30, 0, 0, 0, 360, 0], + TYPE: ["solarioturretBase3rdRing3", { COLOR: 32 }], + }, { + POSITION: [16, 0, 0, 0, 360, 3], + TYPE: ["solariominilaser", { HAS_NO_RECOIL: true, CONTROLLERS: ["canRepel", "onlyAcceptInArc", "mapAltToFire", "nearestDifferentMaster"]}] + }, { + POSITION: [8.2, 0, 0, 0, 360, 2], + TYPE: ["solarioOutline", { COLOR: 32 }] + }, { + POSITION: [10, 0, 0, 0, 360, -1], + TYPE: ["solarioOutline", { COLOR: 32 }] + }, + ], + ON: [ +{ + event: 'fire', + handler: ({ body, gun }) => { + if (gun.identifier == 'startlaserattack') { + sockets.broadcast('Solario: DODGE THIS!!'); + setTimeout(() => body.define('solariolaserphase3'), 1000); + } + if (gun.identifier == 'solarioAttack') { + body.guns[3].canShoot = false; + let attack = ~~(Math.random() * 3); + switch(attack) { + case 0: + body.guns[8].fire(); + setTimeout(() => { if (body != null) body.guns[8].fire(); }, 4000); + setTimeout(() => { if (body != null) body.guns[8].fire(); }, 8000); + setTimeout(() => { if (body != null) body.guns[8].fire(); }, 12000); + break; + case 1: + body.guns[9].fire(); + setTimeout(() => { if (body != null) body.guns[9].fire(); }, 1000); + break; + case 2: + body.guns[10].fire(); + setTimeout(() => { if (body != null) body.guns[10].fire(); }, 500); + setTimeout(() => { if (body != null) body.guns[10].fire(); }, 1000); + setTimeout(() => { if (body != null) body.guns[10].fire(); }, 1500); + setTimeout(() => { if (body != null) body.guns[10].fire(); }, 2000); + setTimeout(() => { if (body != null) body.guns[10].fire(); }, 2500); + setTimeout(() => { if (body != null) body.guns[10].fire(); }, 3000); + break; + } + } + }, + }, { + event: "death", + handler: ({ body }) => { + sockets.broadcast('NOOOOOOO!'); + let o = new Entity(body).define("blackholeondeath") + } + }, + ], +}; +Class.solariolaserphase3 = { + PARENT: "solariophase3", + BODY: { + REGEN: 0, + }, + GUNS: [{ + POSITION: [15, 20, 1, 0, 0, 0, 5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { reload: 0.05, health: 5, pen: 100, speed: 14, maxSpeed: 14, spread: 4, size: 2, range: 0.6 }, { spread: 0, size: 0.6 }]), + TYPE: "hyperlaser", + AUTOFIRE: true, + COLOR: "red", + }, + }, { + POSITION: [15, 10, 1, 0, 0, 60, 5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { reload: 0.05, health: 5, pen: 100, speed: 14, maxSpeed: 14, spread: 4, size: 2, range: 0.6 }]), + TYPE: "laser", + AUTOFIRE: true, + COLOR: "red", + }, + }, { + POSITION: [15, 10, 1, 0, 0, 120, 5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { reload: 0.05, health: 5, pen: 100, speed: 14, maxSpeed: 14, spread: 4, size: 2, range: 0.6 }]), + TYPE: "laser", + AUTOFIRE: true, + COLOR: "red", + }, + }, { + POSITION: [15, 20, 1, 0, 0, 180, 5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { reload: 0.05, health: 5, pen: 100, speed: 14, maxSpeed: 14, spread: 4, size: 2, range: 0.6 }, { spread: 0, size: 0.6 }]), + TYPE: "hyperlaser", + AUTOFIRE: true, + COLOR: "red", + } + }, { + POSITION: [15, 10, 1, 0, 0, 240, 5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { reload: 0.05, health: 5, pen: 100, speed: 14, maxSpeed: 14, spread: 4, size: 2, range: 0.6 }]), + TYPE: "laser", + AUTOFIRE: true, + COLOR: "red", + }, + }, { + POSITION: [15, 10, 1, 0, 0, 300, 5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { reload: 0.05, health: 5, pen: 100, speed: 14, maxSpeed: 14, spread: 4, size: 2, range: 0.6 }]), + TYPE: ["laser", {ARENA_CLOSER: true}], + AUTOFIRE: true, + COLOR: "red", + }, + }, { + POSITION: [350, 20, 2, 0, 0, 0, 0], + PROPERTIES: { + COLOR: "red", + ALPHA: 0.5 + } + }, { + POSITION: [350, 10, 2.5, 0, 0, 60, 0], + PROPERTIES: { + COLOR: "red", + ALPHA: 0.5 + } + }, { + POSITION: [350, 10, 2.5, 0, 0, 120, 0], + PROPERTIES: { + COLOR: "red", + ALPHA: 0.5 + } + }, { + POSITION: [350, 20, 2, 0, 0, 180, 0], + PROPERTIES: { + COLOR: "red", + ALPHA: 0.5 + } + }, { + POSITION: [350, 10, 2.5, 0, 0, 240, 0], + PROPERTIES: { + COLOR: "red", + ALPHA: 0.5 + } + }, { + POSITION: [350, 10, 2.5, 0, 0, 300, 0], + PROPERTIES: { + COLOR: "red", + ALPHA: 0.5 + } + }, { + POSITION: [0, 0, 1, 0, 0, 0, 15], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.fake, { reload: 5 }]), + TYPE: "bullet", + AUTOFIRE: true, + IDENTIFIER: "endlaserattack", + }, + }, { + POSITION: [1, 10, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { health: 999 }, {speed: 0.01, range: 7, maxSpeed: 0.01, health: 99999, pen: 99, density: 38281381283, resist: 421848412}]), + TYPE: ["blackholeondeath", { PERSISTS_AFTER_DEATH: true }], + ALT_FIRE: true, + SHOOT_ON_DEATH: true, + } + }, + ], + ON: [ + { + event: 'fire', + handler: ({ body, gun }) => { + if (gun.identifier == 'endlaserattack') { + sockets.broadcast('Solario: RAHH!'); + setTimeout(() => body.define('solariophase3'), 500); + } + } + }, { + event: "death", + handler: ({ body }) => { + sockets.broadcast('NOOOOOOO!'); + setTimeout(() => sockets.broadcast('YOU HAVE 10 SECONDS TO RUN FROM MY LAST ATTACK'), 1000); + setTimeout(() => { let o = new Entity(body).define("blackholeondeath") }, 11000) + } + }, + ], +} +Class.blackholeondeath = { + PERSISTS_AFTER_DEATH: true, + COLOR: "black", + MOTION_TYPE: ["grow", { growSpeed: 1.4 }], + ARENA_CLOSER: true, + TYPE: "bullet", + ACCEPTS_SCORE: false, + BODY: { + PENETRATION: 99, + SPEED: 1, + RANGE: 200, + DENSITY: 38281381283, + RESIST: 38281381283, + HEALTH: 124124, + DAMAGE: 124124, + }, + FACING_TYPE: "smoothWithMotion", + CAN_GO_OUTSIDE_ROOM: true, + HITS_OWN_TYPE: "never", + DIE_AT_RANGE: true, + GUNS: [{ + POSITION: [4, 4, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { damage: 0, health: 0.8, spray: 45, range: 0.08, recoil: 0, speed: 0.8, pen: 0 }]), + TYPE: ["bullet", { SIZE: 5, ALPHA: 0.5 }], + AUTOFIRE: true + }, + }], + ON: [{ + event: "tick", + handler: ({ body }) => { + for (let instance of entities) { + if (instance.team != body.team && (instance.isPlayer || instance.master.isPlayer || instance.type == "food")) { + let diffX = instance.x - body.x, + diffY = instance.y - body.y, + dist2 = diffX ** 2 + diffY ** 2, + number1 = 1, + number2 = 1, + number3 = 1/7, + number4 = 1, + number5 = 1, + distance = 250, + forceMulti = (((((body.size / 12)*250) ** 2)** number1) * number2) / dist2; + if (dist2 <= ((body.size / 12)*250) ** 2) { + if (instance.id != body.id /*&& !instance.ac && instance.alpha*/) { + instance.velocity.x += util.clamp(body.x - instance.x, -90, 90) * instance.damp * ((number5 - (number5/((forceMulti ** number3)* number4)))+ 0.001);//0.05 + instance.velocity.y += util.clamp(body.y - instance.y, -90, 90) * instance.damp * ((number5 - (number5/((forceMulti ** number3)* number4)))+ 0.001);//0.05 + } + } + if (dist2 < body.size ** 2 + instance.size ** 2) { + if (instance.id != body.id) { + instance.isProtected = false; + instance.invuln = false; + instance.damageReceived = Infinity, + instance.kill(), + instance.destroy(), + instance.removeFromGrid(), + instance.isGhost = true; + } + } + } + } + } + }, { + event: "death", + handler: ({ body }) => { + } + }, + ], +} +Class.solariospawner = { + PARENT: "spectator", + LABEL: "Solario Spawner", + TOOLTIP: "Right click to spawn Solario the Dying Sun", + SKILL_CAP: [31, 0, 0, 0, 0, 0, 0, 0, 0, 31], + GUNS: [{ + POSITION: [14, 12, 1, 4, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { recoil: 0 }]), + TYPE: "bullet" + } + }, { + POSITION: [12, 12, 1.4, 4, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { recoil: 0 }]), + INDEPENDENT_CHILDREN: true, + TYPE: "solario", + ALT_FIRE: true + }, + }], + }; +Class.solariospawner.UPGRADES_TIER_0 = ['solario', 'solariophase2', 'solariophase3'] +Class.addons.UPGRADES_TIER_0.push('solariospawner') \ No newline at end of file diff --git a/server/modules/definitions/combined.js b/server/modules/definitions/combined.js index f8b530de3..3be9a71a7 100644 --- a/server/modules/definitions/combined.js +++ b/server/modules/definitions/combined.js @@ -2,15 +2,17 @@ let fs = require('fs'), path = require('path'), groups = fs.readdirSync(path.join(__dirname, './groups')), definitionCount = 0, - definitionGroupsLoadStart = Date.now(); + definitionGroupsLoadStart = performance.now(); + console.log(`Loading ${groups.length} groups...`); + for (let filename of groups) { console.log(`Loading group: ${filename}`); require('./groups/' + filename); } -let definitionGroupsLoadEnd = Date.now(); -console.log("Loaded definitions in " + (definitionGroupsLoadEnd - definitionGroupsLoadStart) + " milliseconds. \n"); +let definitionGroupsLoadEnd = performance.now(); +console.log("Loaded definitions in " + util.rounder(definitionGroupsLoadEnd - definitionGroupsLoadStart, 3) + " milliseconds. \n"); console.log(`Loading addons...`); @@ -18,7 +20,7 @@ function processAddonFolder(directory) { let folder = fs.readdirSync(directory); for (let filename of folder) { let filepath = directory + `/${filename}`; - let isDirectory = fs.statSync(path.join(directory, filename)).isDirectory(); + let isDirectory = fs.statSync(filepath).isDirectory(); if (isDirectory) { processAddonFolder(filepath); } @@ -28,7 +30,7 @@ function processAddonFolder(directory) { console.log(`Loading addon: ${filename}`); let result = require(filepath); if ('function' === typeof result) { - result({ Config: c, Events: events }); + result({ Class, Config, Events }); } loadedAddons.push(filename.slice(0, -3)); } @@ -36,48 +38,27 @@ function processAddonFolder(directory) { processAddonFolder(path.join(__dirname, './addons')); definitionCount = Object.keys(Class).length; -let addonsLoadEnd = Date.now(); -console.log("Loaded addons in " + (addonsLoadEnd - definitionGroupsLoadEnd) + " milliseconds. \n"); +let addonsLoadEnd = performance.now(); +console.log("Loaded addons in " + util.rounder(addonsLoadEnd - definitionGroupsLoadEnd, 3) + " milliseconds. \n"); // "Flattening" refers to removing PARENT attributes and applying the parents' attributes to the definition themselves, if not overwritten later on. -if (c.flattenDefintions) { +if (Config.flattenDefintions) { console.log(`Flattening ${definitionCount} definitions...`); - let flattenDefinition = (output, definition) => { - definition = ensureIsClass(definition); - - if (definition.PARENT) { - if (!Array.isArray(definition.PARENT)) { - flattenDefinition(output, definition.PARENT); - } else for (let parent in definition.PARENT) { - flattenDefinition(output, definition.PARENT[parent]); - } - } - - for (let key in definition) { - if (key !== "PARENT") { - output[key] = definition[key]; - } - } - - return output; - }; - + let flattened = {}; for (let key in Class) { let output = {}; - flattenDefinition(output, Class[key]); + util.flattenDefinition(output, Class[key]); flattened[key] = output; } Class = flattened; - definitionCount = Object.keys(Class).length; - console.log("Definitions flattened in " + (Date.now() - addonsLoadEnd) + " milliseconds. \n"); + console.log("Definitions flattened in " + (performance.now() - addonsLoadEnd) + " milliseconds. \n"); } -console.log(`Combined ${groups.length} definition groups and ${loadedAddons.length} addons into ${definitionCount} ${c.flattenDefintions ? 'flattened ' : ''}definitions!\n`); - +console.log(`Combined ${groups.length} definition groups and ${loadedAddons.length} addons into ${definitionCount} ${Config.flattenDefintions ? 'flattened ' : ''}definitions!\n`); // Index the definitions let i = 0; for (let key in Class) { if (!Class.hasOwnProperty(key)) continue; Class[key].index = i++; -} +} \ No newline at end of file diff --git a/server/modules/definitions/constants.js b/server/modules/definitions/constants.js index 25ac48e7f..830bf97ff 100644 --- a/server/modules/definitions/constants.js +++ b/server/modules/definitions/constants.js @@ -1,6 +1,6 @@ module.exports = { basePolygonDamage: 1, - basePolygonHealth: 2, + basePolygonHealth: 6, // SKILL DEFINITIONS dfltskl: 9, @@ -75,17 +75,13 @@ module.exports = { BULLET_DAMAGE: 'Ball Damage', RELOAD: 'Ball Density', }, - }, - gunCalcNames: { - default: 0, - bullet: 1, - drone: 2, - swarm: 3, - fixedReload: 4, - thruster: 5, - sustained: 6, - necro: 7, - trap: 8, + lancer: { + BULLET_SPEED: "Lance Range", + BULLET_HEALTH: "Lance Longevity", + BULLET_PEN: "Lance Sharpness", + BULLET_DAMAGE: "Lance Damage", + RELOAD: "Lance Density", + }, }, base: { ACCEL: 1.6, @@ -96,7 +92,7 @@ module.exports = { PENETRATION: 1.05, SHIELD: 8, REGEN: 0.025, - FOV: 1.03, + FOV: 1.02, DENSITY: 0.5, } -}; +}; \ No newline at end of file diff --git a/server/modules/definitions/facilitators.js b/server/modules/definitions/facilitators.js index 8f0261838..aa87ad148 100644 --- a/server/modules/definitions/facilitators.js +++ b/server/modules/definitions/facilitators.js @@ -1,4 +1,3 @@ -const { gunCalcNames } = require('./constants.js') const { MAX_SKILL } = require("../../config.js") const g = require('./gunvals.js') let skcnv = { @@ -62,7 +61,7 @@ exports.combineStats = function (stats) { return data; } catch (err) { console.log(err); - console.log(JSON.stringify(stats)); + throw JSON.stringify(stats); } } exports.setBuild = (build) => { @@ -82,6 +81,8 @@ exports.skillSet = (args) => { // functions exports.dereference = type => { + type = ensureIsClass(type); + let output = JSON.parse(JSON.stringify(type)); if (type.GUNS) { for (let i = 0; i < type.GUNS.length; i++) { @@ -104,29 +105,9 @@ exports.dereference = type => { } // gun functions -exports.makeMulti = (type, count, name = -1, startRotation = 0) => { - type = ensureIsClass(type); - let greekNumbers = ',Double ,Triple ,Quad ,Penta ,Hexa ,Septa ,Octo ,Nona ,Deca ,Hendeca ,Dodeca ,Trideca ,Tetradeca ,Pentadeca ,Hexadeca ,Septadeca ,Octadeca ,Nonadeca ,Icosa ,Henicosa ,Doicosa ,Triaicosa ,Tetraicosa ,Pentaicosa ,Hexaicosa ,Septaicosa ,Octoicosa ,Nonaicosa ,Triaconta '.split(','), - output = exports.dereference(type), - fraction = 360 / count; - output.GUNS = []; - for (let gun of type.GUNS) { - for (let i = 0; i < count; i++) { - let newgun = exports.dereference(gun); - if (Array.isArray(newgun.POSITION)) { - newgun.POSITION[5] += startRotation + fraction * i; - } else { - newgun.POSITION.ANGLE = (newgun.POSITION.ANGLE ?? 0) + startRotation + fraction * i; - } - if (gun.PROPERTIES) newgun.PROPERTIES = gun.PROPERTIES; - output.GUNS.push(newgun); - }; - } - output.LABEL = name == -1 ? (greekNumbers[count - 1] || (count + ' ')) + type.LABEL : name; - return output; -} -exports.makeGuard = (type, name = -1) => { +exports.makeGuard = (type, name = -1, shotentity = "trap") => { type = ensureIsClass(type); + shotentity ?? "trap" let output = exports.dereference(type), cannons = [{ POSITION: [13, 8, 1, 0, 0, 180, 0], @@ -134,8 +115,8 @@ exports.makeGuard = (type, name = -1) => { POSITION: [4, 8, 1.7, 13, 0, 180, 0], PROPERTIES: { SHOOT_SETTINGS: exports.combineStats([g.trap]), - TYPE: "trap", - STAT_CALCULATOR: gunCalcNames.trap, + TYPE: shotentity, + STAT_CALCULATOR: "trap", }, }]; output.GUNS = type.GUNS == null ? cannons : type.GUNS.concat(cannons); @@ -174,7 +155,7 @@ exports.makeBird = (type, name = -1, options = {}) => { // Thrusters let backRecoil = 0.5 * backRecoilFactor; - let thrusterProperties = { SHOOT_SETTINGS: exports.combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster, { recoil: backRecoil }]), TYPE: "bullet", LABEL: gunCalcNames.thruster }; + let thrusterProperties = { SHOOT_SETTINGS: exports.combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster, { recoil: backRecoil }]), TYPE: "bullet", LABEL: "thruster" }; let shootyBois = [{ POSITION: [16, 8, 1, 0, 0, 150, 0.1], PROPERTIES: thrusterProperties @@ -227,16 +208,27 @@ exports.makeOver = (type, name = -1, options = {}) => { let cycle = options.cycle ?? true; let maxChildren = options.maxDrones ?? 3; let stats = options.extraStats ?? []; + let dronetype = options.type ?? "drone"; let spawnerProperties = { SHOOT_SETTINGS: exports.combineStats([g.drone, g.overseer, ...stats]), - TYPE: ["drone", {INDEPENDENT: independent}], + TYPE: [dronetype, {INDEPENDENT: independent}], AUTOFIRE: true, SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.drone, + STAT_CALCULATOR: "drone", WAIT_TO_CYCLE: cycle, MAX_CHILDREN: maxChildren, }; - + if (dronetype == "turretedDrone") { + let drivedeco = { + POSITION: [7, 14, 0, 180, 0, 0], + TYPE: ["autoTurret", { INDEPENDENT: true, MIRROR_MASTER_ANGLE: true }], + }; + if (type.TURRETS == null) { + output.TURRETS = [drivedeco]; + } else { + output.TURRETS = [...type.TURRETS, drivedeco]; + } + } let spawners = []; if (count % 2 == 1) { spawners.push({ @@ -269,7 +261,7 @@ exports.makeBattle = (type, name = -1, options = {}) => { let spawnerProperties = { SHOOT_SETTINGS: exports.combineStats([g.swarm, ...stats]), TYPE: independent ? "autoswarm" : "swarm", - STAT_CALCULATOR: gunCalcNames.swarm, + STAT_CALCULATOR: "swarm", }; let spawners = []; @@ -407,12 +399,14 @@ exports.makeDeco = (shape = 0, color = 16) => { }; } exports.makeRadialAuto = (type, options = {}) => { - /* + - type: what turret (or regular Class) to use as the radial auto + Available options: - count: number of turrets - - turret: what turret definition to use (leave null to make a new turret), overrides the `type` parameter + - isTurret: whether or not the `type` is a turret already (if this option is `false`, the `type` is assumed to + not be a turret and the faciliator will create a new turret modeled after the `type`) - extraStats: extra stats to append to all turret barrels, on top of g.autoTurret - turretIdentifier: Class[turretIdentifier] to refer to the turret in other uses if necessary - size: turret size @@ -430,16 +424,19 @@ exports.makeRadialAuto = (type, options = {}) => { let turretIdentifier = type; if (!isTurret) { - type = exports.dereference(ensureIsClass(type)); + type = exports.dereference(type); let extraStats = options.extraStats ?? []; + if (!Array.isArray(extraStats)) { + extraStats = [extraStats]; + } turretIdentifier = options.turretIdentifier ?? `auto${type.LABEL}Gun`; Class[turretIdentifier] = { PARENT: 'genericTank', LABEL: "", BODY: { - FOV: 3, + FOV: 2, }, CONTROLLERS: ["canRepel", "onlyAcceptInArc", "mapAltToFire", "nearestDifferentMaster"], COLOR: "grey", @@ -474,15 +471,68 @@ exports.makeRadialAuto = (type, options = {}) => { }, count) } } -exports.addAura = (damageFactor = 1, sizeFactor = 1, opacity = 0.3, auraColor) => { +exports.makeTurret = (type, options = {}) => { + + /* + - type: what Class to turn into an auto turret + + Available options: + - canRepel: whether or not the auto turret can fire backwards with secondary fire + - limitFov: whether or not the auto turret should bother to try to limit its FOV arc + - hasAI: whether or not the auto turret can think and shoot on its own + - extraStats: array of stats to append onto the shoot settings of all of the turret's guns + - label: turret label + - color: turret color + - fov: turret FOV + - independent: turret independence + */ + + type = exports.dereference(type); + + let CONTROLLERS = []; + if (options.canRepel) { // default false + CONTROLLERS.push("canRepel", "mapAltToFire"); + } + if (options.limitFov) { // default false + CONTROLLERS.push("onlyAcceptInArc"); + } + if (options.hasAI ?? true) { // default true + CONTROLLERS.push("nearestDifferentMaster"); + } + + let GUNS = type.GUNS; + let extraStats = options.extraStats ?? [g.autoTurret]; + if (!Array.isArray(extraStats)) { + extraStats = [extraStats]; + } + for (let gun of GUNS) { + if (!gun.PROPERTIES) continue; + if (!gun.PROPERTIES.SHOOT_SETTINGS) continue; + + gun.PROPERTIES.SHOOT_SETTINGS = exports.combineStats([gun.PROPERTIES.SHOOT_SETTINGS, ...extraStats]) + } + + return { + PARENT: 'genericTank', + LABEL: options.label ?? "", + COLOR: options.color ?? "grey", + BODY: { FOV: options.fov ?? 2 }, + INDEPENDENT: options.independent ?? false, + CONTROLLERS, + GUNS, + AI: options.aiSettings, + TURRETS: type.TURRETS, + } +} +exports.addAura = (damageFactor = 1, sizeFactor = 1, opacity = 0.3, auraColor, symbolType) => { let isHeal = damageFactor < 0; let auraType = isHeal ? "healAura" : "aura"; - let symbolType = isHeal ? "healerSymbol" : "auraSymbol"; + if (symbolType == null) symbolType = isHeal ? "healerSymbol" : "auraSymbol"; auraColor = auraColor ?? (isHeal ? 12 : 0); return { PARENT: "genericTank", INDEPENDENT: true, - LABEL: "", + LABEL: "Auras", COLOR: 17, GUNS: [ { @@ -504,6 +554,70 @@ exports.addAura = (damageFactor = 1, sizeFactor = 1, opacity = 0.3, auraColor) = ] }; } +exports.setTurretProjectileRecoil = (type, recoilFactor) => { + type = exports.dereference(type); + + if (!type.GUNS) return; + + // Sets the recoil of each of the turret's guns to the desired value. + for (let gun of type.GUNS) { + if (!gun.PROPERTIES) continue; + + // Set gun type to account for recoil factor + let finalType = gun.PROPERTIES.TYPE; + if (!Array.isArray(finalType)) { + finalType = [finalType, {}]; + } + if (typeof finalType[1] != "object") { + finalType[1] = {}; + } + // Set via BODY.RECOIL_FACTOR + if (!finalType[1].BODY) { + finalType[1].BODY = {}; + } + finalType[1].BODY.RECOIL_MULTIPLIER = recoilFactor; + + // Save changes + gun.PROPERTIES.TYPE = finalType; + } + + return type; +} +exports.makeAura = (type, name = -1, options = {}) => { + let turret = { + type: "auraBasicGen", + size: 14, + }; + if (options.type != null) { + turret.type = options.type; + } + if (options.size != null) { + turret.size = options.size; + } + let output = exports.dereference(type); + let aurathing = { + /********* SIZE X Y ANGLE ARC */ + POSITION: [turret.size, 0, 0, 0, 0, 1], + TYPE: [ + turret.type, + ], + }; + if (type.GUNS != null) { + output.GUNS = type.GUNS; + } + if (type.TURRETS == null) { + output.TURRETS = [aurathing]; + } else { + output.TURRETS = [...type.TURRETS, aurathing]; + } + if (name == -1) { + output.LABEL = "Aura " + type.LABEL; + } else { + output.LABEL = name; + } + output.DANGER = type.DANGER + 2; + return output; +} // misc functions exports.menu = (name = -1, color = -1, shape = 0) => { @@ -524,28 +638,41 @@ exports.menu = (name = -1, color = -1, shape = 0) => { IGNORED_BY_AI: true, }; } -exports.weaponArray = (weapons, count) => { +exports.weaponArray = (weapons, count, delayIncrement = 0, delayOverflow = false) => { + // delayIncrement: how much each side's delay increases by + // delayOverflow: false to constrain the delay value between [0, 1) if (!Array.isArray(weapons)) { weapons = [weapons] } let isTurret = weapons[0].TYPE != undefined; - let angleIndex = isTurret ? 3 : 5; + let angleKey = isTurret ? 3 : 5; + let delayKey = 6; let output = []; for (let weapon of weapons) { for (let i = 0; i < count; i++) { let angle = 360 / count * i; + let delay = delayIncrement * i; let newWeapon = exports.dereference(weapon); - if (Array.isArray(newWeapon.POSITION)) { - newWeapon.POSITION[angleIndex] += angle; - } else { - newWeapon.POSITION.ANGLE = (newWeapon.POSITION.ANGLE ?? 0) + angle; + + if (!Array.isArray(newWeapon.POSITION)) { + angleKey = "ANGLE"; + delayKey = "DELAY"; + } + + newWeapon.POSITION[angleKey] = (newWeapon.POSITION[angleKey] ?? 0) + angle; + if (!isTurret) { + newWeapon.POSITION[delayKey] = (newWeapon.POSITION[delayKey] ?? 0) + delay; + if (!delayOverflow) { + newWeapon.POSITION[delayKey] %= 1; + } } output.push(newWeapon); } } return output; } + class LayeredBoss { constructor(identifier, NAME, PARENT = "celestial", SHAPE = 9, COLOR = 0, trapTurretType = "baseTrapTurret", trapTurretSize = 6.5, layerScale = 5, BODY, SIZE, VALUE) { this.identifier = identifier ?? NAME.charAt(0).toLowerCase() + NAME.slice(1); @@ -574,7 +701,7 @@ class LayeredBoss { SHAPE: this.shape, COLOR: -1, INDEPENDENT: true, - CONTROLLERS: [["spin", { independent: true, speed: 0.02 / c.runSpeed * (this.layerID % 2 ? -1 : 1) }]], + FACING_TYPE: ["spin", { speed: 0.02 / Config.runSpeed * (this.layerID % 2 ? -1 : 1) }], MAX_CHILDREN, GUNS: [], TURRETS: [], @@ -605,9 +732,171 @@ class LayeredBoss { } exports.LayeredBoss = LayeredBoss; -//unfinished lolo -exports.makeLabyrinthShape = (type) => { - let output = exports.dereference(type); - let downscale = Math.max(output.SHAPE, 3); - return output; +// Food facilitators +exports.makeRelic = (type, scale = 1, gem, SIZE, yBase = 8.25) => { + // Code by Damocles (https://discord.com/channels/366661839620407297/508125275675164673/1090010998053818488) + // Albeit heavily modified because the math in the original didn't work LOL + type = ensureIsClass(type); + let relicCasing = { + PARENT: 'genericEntity', + LABEL: 'Relic Casing', + LEVEL_CAP: 45, + COLOR: type.COLOR, + MIRROR_MASTER_ANGLE: true, + SHAPE: [[-0.4,-1],[0.4,-0.25],[0.4,0.25],[-0.4,1]].map(r => r.map(s => s * scale)) + }, relicBody = { + PARENT: 'genericEntity', + LABEL: 'Relic Mantle', + LEVEL_CAP: 45, + COLOR: type.COLOR, + MIRROR_MASTER_ANGLE: true, + SHAPE: type.SHAPE + }; + Class[Math.random().toString(36)] = relicCasing; + Class[Math.random().toString(36)] = relicBody; + let width = 6 * scale, + y = yBase + ((scale % 1) * 5), + isEgg = type.SHAPE == 0, + casings = isEgg ? 8 : type.SHAPE, + fraction = 360 / casings, + GUNS = [], + TURRETS = [{ POSITION: [32.5, 0, 0, 0, 0, 0], TYPE: relicBody }], + PARENT = type, + additionalAngle = type.SHAPE % 2 === 0 ? 0 : fraction / 2; + + for (let i = 0; i < casings; i++) { + let angle = i * fraction, + gunAngle = angle + additionalAngle; + if (isEgg) { + GUNS.push({ + POSITION: [4, width, 2.5, 12, 0, gunAngle, 0] + }); + TURRETS.push({ + POSITION: [8, -15, 0, angle, 0, 1], + TYPE: relicCasing + }); + } else { + GUNS.push({ + POSITION: [4, width, 2.5, 12, y, gunAngle, 0] + }); + GUNS.push({ + POSITION: [4, width, 2.5, 12, -y, gunAngle, 0] + }); + TURRETS.push({ + POSITION: [8, -15, y, angle, 0, 1], + TYPE: relicCasing + }); + TURRETS.push({ + POSITION: [8, -15, -y, angle, 0, 1], + TYPE: relicCasing + }); + } + } + + if (gem) { + TURRETS.push({ + POSITION: [8, 0, 0, 0, 0, 1], + TYPE: [gem, { MIRROR_MASTER_ANGLE: true }] + }); + } + + let out = { + PARENT, + LABEL: type.LABEL + ' Relic', + COLOR: "white", // This is the color of the floor, this makes it look hollow. + BODY: { + ACCELERATION: 0.001 + }, + CONTROLLERS: [], + VALUE: type.VALUE * 100_000, + GUNS, + TURRETS + }; + + if (SIZE) { + out.SIZE = SIZE; + } + + return out; +} + +exports.makeCrasher = type => ({ + PARENT: type, + COLOR: 'pink', + TYPE: 'crasher', + LABEL: 'Crasher ' + type.LABEL, + CONTROLLERS: ['nearestDifferentMaster', 'mapTargetToGoal'], + MOTION_TYPE: "motor", + FACING_TYPE: "smoothWithMotion", + HITS_OWN_TYPE: "hard", + HAS_NO_MASTER: true, + VALUE: type.VALUE * 5, + BODY: { + SPEED: 1 + 5 / Math.max(2, (type.PROPS.length ?? 0) + type.SHAPE), + HEALTH: Math.pow(type.BODY.HEALTH, 2/3), + DAMAGE: Math.pow(type.BODY.HEALTH, 1/3) * type.BODY.DAMAGE, + ACCELERATION: 5, + PUSHABILITY: 0.5, + DENSITY: 10 + }, + AI: { + NO_LEAD: true, + } +}); + +exports.makeRare = (type, level) => { + type = ensureIsClass(type); + return { + PARENT: "food", + LABEL: ["Shiny", "Legendary", "Shadow", "Rainbow", "Trans"][level] + " " + type.LABEL, + VALUE: [100, 500, 2000, 4000, 5000][level] * type.VALUE, + SHAPE: type.SHAPE, + SIZE: type.SIZE, + COLOR: ["lightGreen", "teal", "darkGrey", "rainbow", "trans"][level], + ALPHA: level == 2 ? 0.25 : 1, + BODY: { + DAMAGE: [1, 1, 2, 2.5, 2.5][level] * type.BODY.DAMAGE, + DENSITY: [1, 1, 2, 2.5, 2.5][level] * type.BODY.DENSITY, + HEALTH: [2, 4, 4, 6, 8][level] * type.BODY.HEALTH, + PENETRATION: [1.5, 1.5, 2, 2.5, 2.5][level] * type.BODY.PENETRATION, + ACCELERATION: type.BODY.ACCELERATION + }, + DRAW_HEALTH: true, + INTANGIBLE: type.INTANGIBLE, + GIVE_KILL_MESSAGE: true, + } +} + +exports.makeLaby = (type, level, baseScale = 1) => { + type = ensureIsClass(type); + let usableSHAPE = Math.max(type.SHAPE, 3), + downscale = Math.cos(Math.PI / usableSHAPE), + strengthMultiplier = 5 ** level; + return { + PARENT: "food", + LABEL: ["", "Beta ", "Alpha ", "Omega ", "Gamma ", "Delta "][level] + type.LABEL, + VALUE: type.VALUE * strengthMultiplier, + SHAPE: type.SHAPE, + SIZE: type.SIZE * baseScale / downscale ** level, + COLOR: type.COLOR, + ALPHA: type.ALPHA ?? 1, + BODY: { + DAMAGE: type.BODY.DAMAGE, + DENSITY: type.BODY.DENSITY, + HEALTH: type.BODY.HEALTH * strengthMultiplier, + PENETRATION: type.BODY.PENETRATION, + PUSHABILITY: (type.BODY.PUSHABILITY / (level + 1)) || 0, + ACCELERATION: type.BODY.ACCELERATION + }, + INTANGIBLE: type.INTANGIBLE, + VARIES_IN_SIZE: false, + DRAW_HEALTH: type.DRAW_HEALTH, + GIVE_KILL_MESSAGE: type.GIVE_KILL_MESSAGE || level > 1, + GUNS: type.GUNS ?? [], + TURRETS: type.TURRETS ?? [], + PROPS: Array(level).fill().map((_, i) => ({ + POSITION: [20 * downscale ** (i + 1), 0, 0, !(i & 1) ? 180 / usableSHAPE : 0, 1], + TYPE: [type, { COLOR: 'mirror' }] + })) + }; } \ No newline at end of file diff --git a/server/modules/definitions/groups/bosses.js b/server/modules/definitions/groups/bosses.js index e4ba2d6ca..82840bc3e 100644 --- a/server/modules/definitions/groups/bosses.js +++ b/server/modules/definitions/groups/bosses.js @@ -1,2943 +1,3435 @@ -const { combineStats, skillSet, makeAuto, addAura, LayeredBoss, makeDeco } = require('../facilitators.js'); -const { base, gunCalcNames, smshskl } = require('../constants.js'); -const g = require('../gunvals.js'); -require('./generics.js'); - -Class.miniboss = { - PARENT: "genericBoss", - CONTROLLERS: ["nearestDifferentMaster", "minion", "canRepel"], - AI: { NO_LEAD: true }, -}; -Class.ramMiniboss = { - PARENT: "genericBoss", - CONTROLLERS: ["nearestDifferentMaster", "canRepel", "mapTargetToGoal"], -}; - -// ELITE CRASHERS -Class.elite = { - PARENT: "miniboss", - LABEL: "Elite Crasher", - COLOR: "pink", - SHAPE: 3, - SIZE: 27, - VARIES_IN_SIZE: true, - VALUE: 15e4, - BODY: { - FOV: 1.25, - SPEED: 0.1 * base.SPEED, - HEALTH: 7 * base.HEALTH, - DAMAGE: 2.5 * base.DAMAGE, - }, -}; -Class.eliteDestroyer = { - PARENT: "elite", - UPGRADE_LABEL: "Elite Destroyer", - UPGRADE_COLOR: "pink", - GUNS: [ - { - POSITION: [5, 16, 1, 6, 0, 180, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.pounder, g.destroyer]), - TYPE: "bullet", - LABEL: "Devastator", - }, - }, { - POSITION: [5, 16, 1, 6, 0, 60, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.pounder, g.destroyer]), - TYPE: "bullet", - LABEL: "Devastator", - }, - }, { - POSITION: [5, 16, 1, 6, 0, -60, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.pounder, g.destroyer]), - TYPE: "bullet", - LABEL: "Devastator", - }, - }, - ], - TURRETS: [ - { - POSITION: [11, 0, 0, 180, 360, 0], - TYPE: ["crasherSpawner"], - }, { - POSITION: [11, 0, 0, 60, 360, 0], - TYPE: ["crasherSpawner"], - }, { - POSITION: [11, 0, 0, -60, 360, 0], - TYPE: ["crasherSpawner"], - }, { - POSITION: [11, 0, 0, 0, 360, 1], - TYPE: [ "bigauto4gun", { INDEPENDENT: true, COLOR: -1 } ], - }, - ], -}; -Class.eliteGunner = { - PARENT: "elite", - UPGRADE_LABEL: "Elite Gunner", - UPGRADE_COLOR: "pink", - FACING_TYPE: "toTarget", - GUNS: [ - { - POSITION: [14, 16, 1, 0, 0, 180, 0], - }, { - POSITION: [4, 16, 1.5, 14, 0, 180, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.hexaTrapper]), - TYPE: ["unsetPillbox", {MOTION_TYPE: "glide"}], - STAT_CALCULATOR: gunCalcNames.trap, - }, - }, { - POSITION: [6, 14, -2, 2, 0, 60, 0], - }, { - POSITION: [6, 14, -2, 2, 0, 300, 0], - }, - ], - AI: { NO_LEAD: false }, - TURRETS: [ - { - POSITION: [14, 8, 0, 60, 180, 0], - TYPE: ["auto4gun"], - }, { - POSITION: [14, 8, 0, 300, 180, 0], - TYPE: ["auto4gun"], - }, - ], -}; -Class.eliteSprayer = { - PARENT: "elite", - UPGRADE_LABEL: "Elite Sprayer", - UPGRADE_COLOR: "pink", - SKILL: [0, 9, 3, 9, 2, 9, 9, 9, 9, 0], - AI: { NO_LEAD: false }, - HAS_NO_RECOIL: true, - TURRETS: [ - { - /* SIZE X Y ANGLE ARC */ - POSITION: [6, 0, 0, 0, 360, 1], - TYPE: ["machineTripleTurret", { INDEPENDENT: true }], - }, { - POSITION: [9, 6, -5, 180, 130, 0], - TYPE: ["sprayer", { COLOR: "grey" }], - }, { - POSITION: [9, 6, 5, 180, 130, 0], - TYPE: ["sprayer", { COLOR: "grey" }], - }, { - POSITION: [9, 6, 5, 60, 130, 0], - TYPE: ["sprayer", { COLOR: "grey" }], - }, { - POSITION: [9, 6, -5, 60, 130, 0], - TYPE: ["sprayer", { COLOR: "grey" }], - }, { - POSITION: [9, 6, 5, -60, 130, 0], - TYPE: ["sprayer", { COLOR: "grey" }], - }, { - POSITION: [9, 6, -5, -60, 130, 0], - TYPE: ["sprayer", { COLOR: "grey" }], - }, - ], -}; -Class.eliteBattleship = { - PARENT: "elite", - UPGRADE_LABEL: "Elite Battleship", - UPGRADE_COLOR: "pink", - GUNS: [ - { - POSITION: [4, 6, 0.6, 7, -8, 60, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm, g.battleship]), - TYPE: "autoswarm", - STAT_CALCULATOR: gunCalcNames.swarm, - }, - }, { - POSITION: [4, 6, 0.6, 7, 0, 60, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm, g.battleship]), - TYPE: "autoswarm", - STAT_CALCULATOR: gunCalcNames.swarm, - }, - }, { - POSITION: [4, 6, 0.6, 7, 8, 60, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm, g.battleship]), - TYPE: "autoswarm", - STAT_CALCULATOR: gunCalcNames.swarm, - }, - }, { - POSITION: [4, 6, 0.6, 7, -8, 180, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm, g.battleship]), - TYPE: "autoswarm", - STAT_CALCULATOR: gunCalcNames.swarm, - }, - }, { - POSITION: [4, 6, 0.6, 7, 0, 180, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm, g.battleship]), - TYPE: "autoswarm", - STAT_CALCULATOR: gunCalcNames.swarm, - }, - }, { - POSITION: [4, 6, 0.6, 7, 8, 180, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm, g.battleship]), - TYPE: "autoswarm", - STAT_CALCULATOR: gunCalcNames.swarm, - }, - }, { - POSITION: [4, 6, 0.6, 7, -8, -60, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm, g.battleship]), - TYPE: "autoswarm", - STAT_CALCULATOR: gunCalcNames.swarm, - }, - }, { - POSITION: [4, 6, 0.6, 7, 0, -60, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm, g.battleship]), - TYPE: "autoswarm", - STAT_CALCULATOR: gunCalcNames.swarm, - }, - }, { - POSITION: [4, 6, 0.6, 7, 8, -60, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm, g.battleship]), - TYPE: "autoswarm", - STAT_CALCULATOR: gunCalcNames.swarm, - }, - }, - ], - TURRETS: [ - { - POSITION: [5, 7, 0, 0, 360, 1], - TYPE: [ "autoTankGun", { INDEPENDENT: true, COLOR: -1 } ], - }, { - POSITION: [5, 7, 0, 120, 360, 1], - TYPE: [ "autoTankGun", { INDEPENDENT: true, COLOR: -1 } ], - }, { - POSITION: [5, 7, 0, 240, 360, 1], - TYPE: [ "autoTankGun", { INDEPENDENT: true, COLOR: -1 } ], - }, - ], -}; -Class.eliteSpawner = { - PARENT: "elite", - UPGRADE_LABEL: "Elite Spawner", - UPGRADE_COLOR: "pink", - MAX_CHILDREN: 9, - AI: { STRAFE: false }, - GUNS: [ - { - POSITION: [11, 16, 1, 0, 0, 60, 0], - }, { - POSITION: [11, 16, 1, 0, 0, 180, 0], - }, { - POSITION: [11, 16, 1, 0, 0, 300, 0], - }, { - /*** LENGTH WIDTH ASPECT X Y ANGLE DELAY */ - POSITION: [2, 18, 1, 11, 0, 60, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.weak, g.weak, g.weak, { size: 0.5 }, {health: 0.1}]), - TYPE: ["sentrySwarm", {GIVE_KILL_MESSAGE: false}], - SYNCS_SKILLS: true, - AUTOFIRE: true, - STAT_CALCULATOR: gunCalcNames.drone, - }, - }, { - POSITION: [2, 18, 1, 11, 0, 180, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.weak, g.weak, g.weak, { size: 0.5 }, {health: 0.1}]), - TYPE: ["sentryTrap", {GIVE_KILL_MESSAGE: false}], - SYNCS_SKILLS: true, - AUTOFIRE: true, - STAT_CALCULATOR: gunCalcNames.drone, - }, - }, { - POSITION: [2, 18, 1, 11, 0, 300, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.weak, g.weak, g.weak, { size: 0.5 }, {health: 0.1}]), - TYPE: ["sentryGun", {GIVE_KILL_MESSAGE: false}], - SYNCS_SKILLS: true, - AUTOFIRE: true, - STAT_CALCULATOR: gunCalcNames.drone, - }, - }, - ], - TURRETS: [ - { - POSITION: [11, 0, 0, 0, 360, 1], - TYPE: ["auto4gun", { INDEPENDENT: false, COLOR: -1 }], - }, - ], -}; -Class.eliteTrapGuard = { - PARENT: "elite", - UPGRADE_LABEL: "Elite Trap Guard", - UPGRADE_COLOR: "pink", - AI: { STRAFE: false }, - GUNS: [], - TURRETS: [ - { - POSITION: [9.5, 0, 0, 0, 360, 1], - TYPE: "triTrapGuardTurret", - }, - ], -}; -for (let i = 0; i < 3; i++) { - Class.eliteTrapGuard.GUNS.push( - { - POSITION: [10.5, 6, 1, 0, 0, 120*i+60, 0], - }, { - POSITION: [3, 6, 1.7, 10.5, 0, 120*i+60, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap]), - TYPE: "trap", - STAT_CALCULATOR: gunCalcNames.trap, - }, - }, - ) - Class.eliteTrapGuard.TURRETS.push( - { - POSITION: [5, 8, -7, 120*i+60, 160, 0], - TYPE: ["autoTurret", { INDEPENDENT: false }], - }, { - POSITION: [5, 8, 7, 120*i+60, 160, 0], - TYPE: ["autoTurret", { INDEPENDENT: false }], - }, - ) -}; -Class.eliteSpinner = { - PARENT: "elite", - UPGRADE_LABEL: "Elite Spinner", - UPGRADE_COLOR: "pink", - AI: { STRAFE: false }, - FACING_TYPE: ["spin", {speed: 0.1}], - GUNS: [], - TURRETS: [ - { - POSITION: [9.5, 0, 0, 0, 360, 1], - TYPE: ["eliteSpinnerCyclone", {COLOR: -1}], - }, - ], -}; -for (let i = 0; i < 3; i++) { - Class.eliteSpinner.GUNS.push( - { - POSITION: [9.5, 2, 1, -1.5, 11.5, 120*i+10, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.gunner, { speed: 1.3, maxSpeed: 1.3 }]), - TYPE: "bullet", - }, - }, { - POSITION: [9.5, 2, 1, 3.5, 6.5, 120*i+10, 1/3], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.gunner, { speed: 1.3, maxSpeed: 1.3 }]), - TYPE: "bullet", - }, - }, { - POSITION: [9.5, 2, 1, 8.5, 1.5, 120*i+10, 2/3], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.gunner, { speed: 1.3, maxSpeed: 1.3 }]), - TYPE: "bullet", - }, - }, { - POSITION: [2, 20, 0.75, 8, 0, 120*i+60, 0], - }, - ) -}; - -// OLD ELITE -Class.oldEliteSprayer = { - PARENT: "elite", - UPGRADE_LABEL: "Elite Sprayer (Old)", - UPGRADE_COLOR: "pink", - AI: { NO_LEAD: false }, - TURRETS: [ - { - POSITION: [14, 6, 0, 180, 190, 0], - TYPE: [ "sprayer", { COLOR: -1 } ], - }, { - POSITION: [14, 6, 0, 60, 190, 0], - TYPE: [ "sprayer", { COLOR: -1 } ], - }, { - POSITION: [14, 6, 0, -60, 190, 0], - TYPE: [ "sprayer", { COLOR: -1 } ], - }, - ], -}; - -// Legionary Crasher -Class.legionaryCrasherTop = { - PARENT: "elite", - AI: { STRAFE: false, NO_LEAD: false }, - CONTROLLERS: [ ["spin", { independent: true, speed: -0.005 }] ], - INDEPENDENT: true, - GUNS: [], - TURRETS: [], -} -for (let i = 0; i < 3; i++) { - Class.legionaryCrasherTop.GUNS.push( - { - POSITION: [4, 9.5, 0.7, 7, 5, 120*i+60, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm, g.pounder, { speed: 3, maxSpeed: 1.7, size: 0.6, range: 2.8}]), - TYPE: [ "swarm", { INDEPENDENT: true } ], - STAT_CALCULATOR: gunCalcNames.swarm, - AUTOFIRE: true, - - }, - }, { - POSITION: [4, 9.5, 0.7, 7, -5, 120*i+60, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm, g.pounder, { speed: 3, maxSpeed: 1.7, size: 0.6, range: 2.8}]), - TYPE: [ "swarm", { INDEPENDENT: true } ], - STAT_CALCULATOR: gunCalcNames.swarm, - AUTOFIRE: true, - }, - }, - ) - Class.legionaryCrasherTop.TURRETS.push( - { - POSITION: [9.5, 10, 0, 120*i, 190, 0], - TYPE: "auto4gun", - }, - ) -} -Class.legionaryCrasher = { - PARENT: "elite", - LABEL: "Legionary Crasher", - UPGRADE_COLOR: "pink", - AI: { STRAFE: false, NO_LEAD: false }, - HAS_NO_RECOIL: true, - VALUE: 5e6, - SIZE: 75, - BODY: { - FOV: 1.5, - SPEED: 0.1 * base.SPEED, - HEALTH: 2000, - DAMAGE: 5 * base.DAMAGE, - }, - GUNS: [], - TURRETS: [ - { - POSITION: [12, 0, 0, 0, 360, 1], - TYPE: "legionaryCrasherTop", - } - ], -} -for (let i = 0; i < 3; i++) { - Class.legionaryCrasher.GUNS.push( - { - POSITION: [14.5, 13, 1, 0, 0, 120*i, 0], - }, { - POSITION: [3, 13, 1.7, 14.5, 0, 120*i, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.setTrap, g.pounder, g.destroyer, { speed: 2.5, size: 0.6, maxSpeed: 3 }]), - TYPE: "legionaryPillbox", - STAT_CALCULATOR: gunCalcNames.trap, - }, - }, - ) -} -for (let i = 0; i < 3; i++) { - Class.legionaryCrasher.GUNS.push( - { - POSITION: [5, 12, 1.6, -11, 0, 120*i, 0], - } - ) - Class.legionaryCrasher.TURRETS.push( - { - POSITION: [14, 8, 0, 120*i+60, 180, 0], - TYPE: [ "sprayer", { COLOR: -1, } ], - }, - ) -} - -Class.sprayerLegion = { - PARENT: "elite", - UPGRADE_LABEL: "Sprayer Legion", - UPGRADE_COLOR: "pink", - AI: { NO_LEAD: false }, - TURRETS: [ - { - POSITION: [14, 6, 0, 180, 190, 0], - TYPE: ["machineGun", {COLOR: -1}], - }, { - POSITION: [14, 6, 0, 60, 190, 0], - TYPE: ["machineGun", {COLOR: -1}], - }, { - POSITION: [14, 6, 0, -60, 190, 0], - TYPE: ["machineGun", {COLOR: -1}], - }, - ], -}; - -// STRANGE BOSSES -Class.sorcerer = { - PARENT: "miniboss", - LABEL: "Sorcerer", - DANGER: 7, - SHAPE: 0, - COLOR: "veryLightGrey", - UPGRADE_COLOR: "veryLightGrey", - SIZE: 26, - MAX_CHILDREN: 50, - VALUE: 2e5, - BODY: { - FOV: 0.5, - SPEED: 0.12 * base.SPEED, - HEALTH: 6 * base.HEALTH, - DAMAGE: 2 * base.DAMAGE, - }, - GUNS: Array(2).fill().map((_, i) => ({ - POSITION: [3.5, 8.65, 1.2, 8, 0, i * 180, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.summoner, g.machineGun, g.machineGunner, { size: 0.4, spray: 150, speed: 2, shudder: 1.75 }]), - TYPE: "minichip", - AUTOFIRE: true, - SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.necro, - WAIT_TO_CYCLE: true, - }, - })) -}; -Class.summoner = { - PARENT: "miniboss", - LABEL: "Summoner", - DANGER: 8, - SHAPE: 4, - COLOR: "gold", - UPGRADE_COLOR: "gold", - SIZE: 26, - MAX_CHILDREN: 28, - VALUE: 3e5, - BODY: { - FOV: 0.5, - SPEED: 0.1 * base.SPEED, - HEALTH: 7 * base.HEALTH, - DAMAGE: 2.6 * base.DAMAGE, - }, - GUNS: Array(4).fill().map((_, i) => ({ - POSITION: [3.5, 8.65, 1.2, 8, 0, i * 90, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.summoner, { size: 0.8 }]), - TYPE: ["sunchip"], - AUTOFIRE: true, - SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.necro, - WAIT_TO_CYCLE: true, - }, - })) -}; -Class.enchantress = { - PARENT: "miniboss", - LABEL: "Enchantress", - DANGER: 8, - SHAPE: 3.5, - COLOR: "orange", - UPGRADE_COLOR: "orange", - SIZE: 26, - MAX_CHILDREN: 28, - VALUE: 4e5, - BODY: { - FOV: 0.5, - SPEED: 0.09 * base.SPEED, - HEALTH: 10 * base.HEALTH, - DAMAGE: 3 * base.DAMAGE, - }, - GUNS: Array(3).fill().map((_, i) => ({ - POSITION: [3.5, 8.65, 1.2, 8, 0, i * 120, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.summoner, { size: 0.9 }]), - TYPE: "dorito", - AUTOFIRE: true, - SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.necro, - WAIT_TO_CYCLE: true, - }, - })) -}; -Class.exorcistor = { - PARENT: "miniboss", - LABEL: "Exorcistor", - DANGER: 8, - SHAPE: 5.5, - COLOR: "purple", - UPGRADE_COLOR: "purple", - SIZE: 26, - MAX_CHILDREN: 20, - VALUE: 5e5, - BODY: { - FOV: 0.5, - SPEED: 0.08 * base.SPEED, - HEALTH: 15 * base.HEALTH, - DAMAGE: 4 * base.DAMAGE, - }, - GUNS: Array(5).fill().map((_, i) => ({ - POSITION: [3.5, 8.65, 1.2, 8, 0, i * 72, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.summoner, g.destroyer]), - TYPE: "demonchip", - AUTOFIRE: true, - SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.necro, - WAIT_TO_CYCLE: true, - }, - })) -}; -Class.shaman = { - PARENT: "miniboss", - LABEL: "Shaman", - DANGER: 8, - SHAPE: 6, - COLOR: "hexagon", - UPGRADE_COLOR: "hexagon", - SIZE: 26, - MAX_CHILDREN: 20, - VALUE: 6e5, - BODY: { - FOV: 0.5, - SPEED: 0.07 * base.SPEED, - HEALTH: 20 * base.HEALTH, - DAMAGE: 5 * base.DAMAGE, - }, - GUNS: Array(6).fill().map((_, i) => ({ - POSITION: [3.5, 8.65, 1.2, 8, 0, i * 60, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.summoner, g.destroyer, { size: 1.1 }]), - TYPE: "realchip", - AUTOFIRE: true, - SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.necro, - WAIT_TO_CYCLE: true, - }, - })) -}; -Class.eliteSkimmer = { - PARENT: "elite", - LABEL: "Elite Skimmer", - COLOR: "orange", - UPGRADE_COLOR: "orange", - TURRETS: [ - { - POSITION: [15, 5, 0, 60, 170, 0], - TYPE: "skimmerTurret", - }, { - POSITION: [15, 5, 0, 180, 170, 0], - TYPE: "skimmerTurret", - }, { - POSITION: [15, 5, 0, 300, 170, 0], - TYPE: "skimmerTurret", - }, - ], -}; - -// Nesters -Class.nestKeeper = { - PARENT: "miniboss", - LABEL: "Nest Keeper", - COLOR: "purple", - UPGRADE_COLOR: "purple", - SHAPE: 5, - SIZE: 50, - BODY: { - FOV: 1.3, - SPEED: base.SPEED * 0.25, - HEALTH: base.HEALTH * 9, - SHIELD: base.SHIELD * 1.5, - REGEN: base.REGEN, - DAMAGE: base.DAMAGE * 2.5, - }, - MAX_CHILDREN: 15, - VALUE: 3e5, - GUNS: [ - { - POSITION: [3.5, 6.65, 1.2, 8, 0, 35, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.nestKeeper]), - TYPE: "drone", - AUTOFIRE: true, - LABEL: "Mega Crasher", - STAT_CALCULATOR: gunCalcNames.drone, - }, - }, { - POSITION: [3.5, 6.65, 1.2, 8, 0, -35, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.nestKeeper]), - TYPE: "drone", - AUTOFIRE: true, - LABEL: "Mega Crasher", - STAT_CALCULATOR: gunCalcNames.drone, - }, - }, { - POSITION: [3.5, 6.65, 1.2, 8, 0, 180, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.nestKeeper]), - TYPE: "drone", - AUTOFIRE: true, - LABEL: "Mega Crasher", - STAT_CALCULATOR: gunCalcNames.drone, - }, - }, { - POSITION: [3.5, 6.65, 1.2, 8, 0, 108, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.nestKeeper]), - TYPE: "drone", - AUTOFIRE: true, - LABEL: "Mega Crasher", - STAT_CALCULATOR: gunCalcNames.drone, - }, - }, { - POSITION: [3.5, 6.65, 1.2, 8, 0, -108, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.nestKeeper]), - TYPE: "drone", - AUTOFIRE: true, - LABEL: "Mega Crasher", - STAT_CALCULATOR: gunCalcNames.drone, - }, - }, - ], - TURRETS: [ - { - POSITION: [8, 9, 0, 72, 120, 0], - TYPE: [ "auto4gun", { INDEPENDENT: true, COLOR: -1 } ], - }, { - POSITION: [8, 9, 0, 0, 120, 0], - TYPE: [ "auto4gun", { INDEPENDENT: true, COLOR: -1 } ], - }, { - POSITION: [8, 9, 0, 144, 120, 0], - TYPE: [ "auto4gun", { INDEPENDENT: true, COLOR: -1 } ], - }, { - POSITION: [8, 9, 0, 216, 120, 0], - TYPE: [ "auto4gun", { INDEPENDENT: true, COLOR: -1 } ], - }, { - POSITION: [8, 9, 0, -72, 120, 0], - TYPE: [ "auto4gun", { INDEPENDENT: true, COLOR: -1 } ], - }, { - POSITION: [9, 0, 0, 0, 360, 1], - TYPE: [ "boomerTurret", { INDEPENDENT: true, COLOR: -1 } ], - }, - ], -}; -Class.nestWarden = { - PARENT: "miniboss", - LABEL: "Nest Warden", - COLOR: "purple", - UPGRADE_COLOR: "purple", - SHAPE: 5, - SIZE: 50, - BODY: { - FOV: 1.3, - SPEED: base.SPEED * 0.25, - HEALTH: base.HEALTH * 9, - SHIELD: base.SHIELD * 1.5, - REGEN: base.REGEN, - DAMAGE: base.DAMAGE * 2.5, - }, - VALUE: 3e5, - GUNS: [], - TURRETS: [ - { - POSITION: [9, 0, 0, 0, 360, 1], - TYPE: [ "barricadeTurret", { INDEPENDENT: true, COLOR: -1 } ], - }, - ], -}; -for(let i = 0; i < 5; i++) { - Class.nestWarden.GUNS.push( - { - POSITION: [10.7, 8, 1, 0, 0, 72*i+36, 0], - }, { - POSITION: [1.5, 8, 1.2, 10.7, 0, 72*i+36, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, { speed: 1.2 }, g.setTrap, g.constructor]), - TYPE: "unsetTrap", - STAT_CALCULATOR: gunCalcNames.block - }, - }, - ); - Class.nestWarden.TURRETS.push( - { - POSITION: [8, 9, 0, 72*i, 120, 0], - TYPE: [ "cruiserTurret", { INDEPENDENT: true, COLOR: -1 } ], - } - ); -}; -Class.nestGuardian = { - PARENT: "miniboss", - LABEL: "Nest Guardian", - COLOR: "purple", - UPGRADE_COLOR: "purple", - SHAPE: 5, - SIZE: 50, - BODY: { - FOV: 1.3, - SPEED: base.SPEED * 0.25, - HEALTH: base.HEALTH * 9, - SHIELD: base.SHIELD * 1.5, - REGEN: base.REGEN, - DAMAGE: base.DAMAGE * 2.5, - }, - VALUE: 3e5, - GUNS: [], - TURRETS: [ - { - POSITION: [9, 0, 0, 0, 360, 1], - TYPE: [ "twisterTurret", { INDEPENDENT: true, COLOR: -1 } ], - }, - ], -}; -for(let i = 0; i < 5; i++) { - Class.nestGuardian.GUNS.push( - { - POSITION: [5.5, 7, 1, 6, 0, 72*i+36, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.pounder, g.destroyer]), - TYPE: "bullet", - LABEL: "Devastator", - }, - }, - ); - Class.nestGuardian.TURRETS.push( - { - POSITION: [8, 9, 0, 72*i, 120, 0], - TYPE: [ "swarmerTurret", { INDEPENDENT: true, COLOR: -1 } ], - } - ); -}; - -// Rogues -Class.roguePalisade = { - PARENT: "miniboss", - LABEL: "Rogue Palisade", - COLOR: "darkGrey", - UPGRADE_COLOR: "darkGrey", - SHAPE: 6, - SIZE: 30, - VALUE: 5e5, - CONTROLLERS: ['nearestDifferentMaster', 'onlyAcceptInArc'], - BODY: { - FOV: 1.4, - SPEED: 0.05 * base.SPEED, - HEALTH: 16 * base.HEALTH, - SHIELD: 3 * base.SHIELD, - DAMAGE: 3 * base.DAMAGE, - }, - GUNS: [ - { POSITION: [4, 6, -1.6, 8, 0, 0, 0], PROPERTIES: { SHOOT_SETTINGS: combineStats([ g.factory, g.pounder, { reload: 2 }, { reload: 2 } ]), TYPE: ["minion", {INDEPENDENT: true}], STAT_CALCULATOR: gunCalcNames.drone, AUTOFIRE: true, MAX_CHILDREN: 3, SYNCS_SKILLS: true, WAIT_TO_CYCLE: true }}, - { POSITION: [4, 6, -1.6, 8, 0, 60, 0], PROPERTIES: { SHOOT_SETTINGS: combineStats([ g.factory, g.pounder, { reload: 2 }, { reload: 2 } ]), TYPE: ["minion", {INDEPENDENT: true}], STAT_CALCULATOR: gunCalcNames.drone, AUTOFIRE: true, MAX_CHILDREN: 3, SYNCS_SKILLS: true, WAIT_TO_CYCLE: true }}, - { POSITION: [4, 6, -1.6, 8, 0, 120, 0], PROPERTIES: { SHOOT_SETTINGS: combineStats([ g.factory, g.pounder, { reload: 2 }, { reload: 2 } ]), TYPE: ["minion", {INDEPENDENT: true}], STAT_CALCULATOR: gunCalcNames.drone, AUTOFIRE: true, MAX_CHILDREN: 3, SYNCS_SKILLS: true, WAIT_TO_CYCLE: true }}, - { POSITION: [4, 6, -1.6, 8, 0, 180, 0], PROPERTIES: { SHOOT_SETTINGS: combineStats([ g.factory, g.pounder, { reload: 2 }, { reload: 2 } ]), TYPE: ["minion", {INDEPENDENT: true}], STAT_CALCULATOR: gunCalcNames.drone, AUTOFIRE: true, MAX_CHILDREN: 3, SYNCS_SKILLS: true, WAIT_TO_CYCLE: true }}, - { POSITION: [4, 6, -1.6, 8, 0, 240, 0], PROPERTIES: { SHOOT_SETTINGS: combineStats([ g.factory, g.pounder, { reload: 2 }, { reload: 2 } ]), TYPE: ["minion", {INDEPENDENT: true}], STAT_CALCULATOR: gunCalcNames.drone, AUTOFIRE: true, MAX_CHILDREN: 3, SYNCS_SKILLS: true, WAIT_TO_CYCLE: true }}, - { POSITION: [4, 6, -1.6, 8, 0, 300, 0], PROPERTIES: { SHOOT_SETTINGS: combineStats([ g.factory, g.pounder, { reload: 2 }, { reload: 2 } ]), TYPE: ["minion", {INDEPENDENT: true}], STAT_CALCULATOR: gunCalcNames.drone, AUTOFIRE: true, MAX_CHILDREN: 3, SYNCS_SKILLS: true, WAIT_TO_CYCLE: true }}, - ], - TURRETS: [ - { POSITION: [5, 10, 0, 30, 110, 0], TYPE: "baseTrapTurret" }, - { POSITION: [5, 10, 0, 90, 110, 0], TYPE: "baseTrapTurret" }, - { POSITION: [5, 10, 0, 150, 110, 0], TYPE: "baseTrapTurret" }, - { POSITION: [5, 10, 0, 210, 110, 0], TYPE: "baseTrapTurret" }, - { POSITION: [5, 10, 0, 270, 110, 0], TYPE: "baseTrapTurret" }, - { POSITION: [5, 10, 0, 330, 110, 0], TYPE: "baseTrapTurret" }, - ], -}; -Class.rogueArmada = (() => { - let SHAPE = 7, - GUNS = [], - TURRETS = []; - for (let i = 0; i < SHAPE; i++) { - for (let j = 0; j < 8; j++) { - GUNS.push({ - POSITION: [8, 2 + Math.floor(j / 3), 1, 0, j / 2 - 2, (i + 0.5) * (360 / SHAPE), 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.shotgun, {damage: 3}]), - TYPE: j % SHAPE < 2 ? "bullet" : "casing" - } - }); - } - GUNS.push({ - POSITION: [8.5, 6, 1, 4, 0, (i + 0.5) * (360 / SHAPE), 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.shotgun, g.fake]), - TYPE: "casing" - } - }, { - POSITION: [7, 6, -1.6, 4, 0, (i + 0.5) * (360 / SHAPE), 0] - }); - } - for (let i = 0; i < SHAPE; i++) { - TURRETS.push({ - POSITION: [5, 10, 0, i * 360 / SHAPE, 160, 0], - TYPE: "shottrapTurret" - }); - } - return { - PARENT: "miniboss", - LABEL: 'Rogue Armada', - COLOR: "darkGrey", - UPGRADE_COLOR: "darkGrey", - SHAPE, - SIZE: 28, - VALUE: 500000, - BODY: { - FOV: 1.3, - SPEED: base.SPEED * 0.1, - HEALTH: base.HEALTH * 16, - SHIELD: base.SHIELD * 3, - REGEN: base.REGEN, - DAMAGE: base.DAMAGE * 3, - }, - GUNS, TURRETS - }; -})(); - -// Bob. -Class.bob = { - PARENT: "ramMiniboss", - LABEL: "Bob", - SHAPE: 0, - COLOR: "aqua", - UPGRADE_COLOR: "aqua", - SIZE: 18, - BODY: { - FOV: 2, - SPEED: 2 * base.SPEED, - HEALTH: 5 * base.HEALTH, - DAMAGE: 5 * base.DAMAGE, - REGEN: 8 * base.REGEN, - FOV: 0.5 * base.FOV, - DENSITY: 6 * base.DENSITY, - }, - CONTROLLERS: ["nearestDifferentMaster", "mapTargetToGoal"], - TURRETS: [ - { - POSITION: [21.5, 0, 0, 0, 360, 0], - TYPE: "smasherBody", - }, { - POSITION: [21.5, 0, 0, 30, 360, 0], - TYPE: "landmineBody", - }, { - POSITION: [23.75, 0, 0, 0, 360, 0], - TYPE: "spikeBody", - }, - ], -}; -Class.nemesis = { - PARENT: "bob", - LABEL: "Nemesis", - COLOR: "red", - UPGRADE_COLOR: "red", - BODY: { - REGEN: 1e5, - HEALTH: 1e6, - DENSITY: 30, - DAMAGE: 1e5, - FOV: 5, - }, -}; - -// DIEP BOSSES -Class.guardian = { - PARENT: "elite", - LABEL: "Guardian of the Pentagons", - UPGRADE_LABEL: "Guardian", - UPGRADE_COLOR: "pink", - FACING_TYPE: "toTarget", - GUNS: [ - { - POSITION: [4, 12, 1.4, 8, 0, 180, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm, { size: 0.5 }]), - TYPE: "swarm", - AUTOFIRE: true, - }, - }, - ], - AI: { NO_LEAD: false }, -}; -Class.defenderAutoTankGun = { - PARENT: "autoTankGun", - GUNS: [ - { - POSITION: [22, 10, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.autoTurret]), - TYPE: ["bullet", {COLOR: "yellow"}], - }, - }, - ], -}; -Class.defender = { - PARENT: "elite", - LABEL: "Defender", - COLOR: "orange", - UPGRADE_COLOR: "orange", - GUNS: [ - { - POSITION: [15, 7, 1, -3, 0, 60, 0], - }, { - POSITION: [3, 7, 1.7, 12, 0, 60, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.flankGuard]), - TYPE: ["trap", {COLOR: "yellow"}], - STAT_CALCULATOR: gunCalcNames.trap, - }, - }, { - POSITION: [15, 7, 1, -3, 0, 180, 0], - }, { - POSITION: [3, 7, 1.7, 12, 0, 180, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.flankGuard]), - TYPE: ["trap", {COLOR: "yellow"}], - STAT_CALCULATOR: gunCalcNames.trap, - }, - }, { - POSITION: [15, 7, 1, -3, 0, 300, 0], - }, { - POSITION: [3, 7, 1.7, 12, 0, 300, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.flankGuard]), - TYPE: ["trap", {COLOR: "yellow"}], - STAT_CALCULATOR: gunCalcNames.trap, - }, - }, - ], - TURRETS: [ - { - POSITION: [5, 7, 0, 0, 190, 1], - TYPE: "defenderAutoTankGun", - }, { - POSITION: [5, 7, 0, 120, 190, 1], - TYPE: "defenderAutoTankGun", - }, { - POSITION: [5, 7, 0, 240, 190, 1], - TYPE: "defenderAutoTankGun", - }, - ], - AI: { NO_LEAD: false }, -}; - -// CELESTIALS -Class.terrestrial = { - PARENT: "miniboss", - LABEL: "Terrestrial", - SKILL: [9, 9, 9, 9, 9, 9, 9, 9, 9, 9], - VALUE: 5e5, - SHAPE: 7, - SIZE: 35, - BODY: { - FOV: 1, - HEALTH: 1000, - SHIELD: 2, - REGEN: base.REGEN * 0.1, - SPEED: 0.75, - DAMAGE: 9, - }, -}; -Class.celestial = { - PARENT: "miniboss", - LABEL: "Celestial", - SKILL: [9, 9, 9, 9, 9, 9, 9, 9, 9, 9], - VALUE: 1e6, - SHAPE: 9, - SIZE: 45, - BODY: { - FOV: 1, - HEALTH: 1000, - SHIELD: 2, - REGEN: base.REGEN * 0.1, - SPEED: 0.75, - DAMAGE: 12, - }, -}; -Class.rogueCelestial = { - PARENT: "celestial", - LABEL: "Rogue Celestial", - COLOR: "darkGrey", -}; -Class.eternal = { - PARENT: "miniboss", - LABEL: "Eternal", - SKILL: [9, 9, 9, 9, 9, 9, 9, 9, 9, 9], - VALUE: 4e6, - SHAPE: 11, - SIZE: 90, - BODY: { - FOV: 1, - HEALTH: 3000, - SHIELD: 2, - REGEN: base.REGEN * 0.1, - SPEED: 0.75, - DAMAGE: 18, - }, -}; - -// Terrestrials -let ares = new LayeredBoss(null, "Ares", "terrestrial", 7, "purple", "terrestrialTrapTurret", 7, 5.5); -ares.addLayer({gun: { - POSITION: [3.75, 7, 1.2, 8, 0, null, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.summoner, g.destroyer, { speed: 0.5, maxSpeed: 0.5 }]), - TYPE: ["demonchip", { INDEPENDENT: true, }], - AUTOFIRE: true, - SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.necro, - WAIT_TO_CYCLE: true, - }, -}}, false, null, 18); -ares.addLayer({turret: { - POSITION: [10, 8.5, 0, null, 160, 0], - TYPE: ["protoSwarmerTurret", { INDEPENDENT: true }], -}}, true, 6.5); - -let gersemi = new LayeredBoss(null, "Gersemi", "terrestrial", 7, "lightGreen", "terrestrialTrapTurret", 7, 5.5); -gersemi.addLayer({turret: { - POSITION: [9, 8, 0, null, 160, 0], - TYPE: ["swarmTurret", { INDEPENDENT: true }], -}}); -gersemi.addLayer({turret: { - POSITION: [9.5, 7.5, 0, null, 160, 0], - TYPE: ["basicTurret", { INDEPENDENT: true }], -}}, true, 6.5); - -let ezekiel = new LayeredBoss(null, "Ezekiel", "terrestrial", 7, "orange", "terrestrialTrapTurret", 7, 5.5); -ezekiel.addLayer({gun: { - POSITION: [3.75, 7, 1.2, 8, 0, null, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.summoner, g.destroyer, { speed: 0.5, maxSpeed: 0.5 }]), - TYPE: ["dorito", { COLOR: "orange", INDEPENDENT: true, }], - AUTOFIRE: true, - SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.necro, - WAIT_TO_CYCLE: true, - }, -}}, true, null, 18); -ezekiel.addLayer({turret: { - POSITION: [10, 7.5, 0, null, 160, 0], - TYPE: ["skimmerTurret", { COLOR: "grey", INDEPENDENT: true }], -}}, true, 6.5) - -let eris = new LayeredBoss(null, "Eris", "terrestrial", 7, "pink", "terrestrialTrapTurret", 7, 5.5); -eris.addLayer({gun: { - POSITION: [3.75, 7, 1.2, 8, 0, null, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.factory, { size: 0.5 }]), - TYPE: ["minion", { INDEPENDENT: true, COLOR: "pink", HAS_NO_RECOIL: true }], - AUTOFIRE: true, - SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.necro, - WAIT_TO_CYCLE: true, - }, -}}, false, null, 14); -eris.addLayer({turret: { - POSITION: [10, 8.5, 0, null, 160, 0], - TYPE: ["rocketeerTurret", { INDEPENDENT: true }], -}}, true, 6.5); - -let selene = new LayeredBoss(null, "Selene", "terrestrial", 7, "gold", "terrestrialTrapTurret", 7, 5.5); -selene.addLayer({gun: { - POSITION: [3.75, 7, 1.2, 8, 0, null, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.summoner, g.destroyer, { speed: 0.5, maxSpeed: 0.5 }]), - TYPE: ["sunchip", { COLOR: "gold", INDEPENDENT: true }], - AUTOFIRE: true, - SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.necro, - WAIT_TO_CYCLE: true, - }, -}}, true, null, 18); -selene.addLayer({turret: { - POSITION: [10, 7.5, 0, null, 160, 0], - TYPE: ["hyperTwisterTurret", { INDEPENDENT: true }], -}}, true, 6.5); - -// PALADIN -let paladin = new LayeredBoss(null, "Paladin", "celestial", 9, "purple", "baseTrapTurret", 6.5, 5.5); -paladin.addLayer({gun: { - POSITION: [3.8, 6, 1.4, 8, 0, null, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.overseer]), - TYPE: ["demonchip", {INDEPENDENT: true}], - AUTOFIRE: true, - SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.drone, - WAIT_TO_CYCLE: true, - }, -}}, true, null, 16); -paladin.addLayer({turret: { - POSITION: [10, 7.5, 0, null, 160, 0], - TYPE: "swarmerTurret", -}}, true, 6); - -// FREYJA -let freyja = new LayeredBoss(null, "Freyja", "celestial", 9, "lightGreen", "baseTrapTurret", 6.5, 5.5); -freyja.addLayer({turret: { - POSITION: [8.5, 9, 0, null, 180, 0], - TYPE: "cruiserTurret", -}}); -freyja.addLayer({turret: { - POSITION: [10.6, 7.5, 0, null, 160, 0], - TYPE: "auto4gun", -}}, true, 6); - -// ZAPHKIEL -let zaphkiel = new LayeredBoss(null, "Zaphkiel", "celestial", 9, "orange", "baseTrapTurret", 6.5, 5.5); -zaphkiel.addLayer({gun: { - POSITION: [3.8, 6, 1.4, 8, 0, null, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.overseer]), - TYPE: ["drone", {INDEPENDENT: true,}], - AUTOFIRE: true, - SYNCS_SKILLS: true, - }, -}}, true, null, 16); -zaphkiel.addLayer({turret: { - POSITION: [10, 7.5, 0, null, 160, 0], - TYPE: ["skimmerTurret", {COLOR: "grey", INDEPENDENT: true}], -}}, true, 6); - -// NYX -let nyx = new LayeredBoss(null, "Nyx", "celestial", 9, "pink", "baseTrapTurret", 6.5, 5.5); -nyx.addLayer({gun: { - POSITION: [3.8, 7, -1.4, 8, 0, null, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.factory, { size: 0.5 }]), - TYPE: ["minion", {INDEPENDENT: true,}], - AUTOFIRE: true, - SYNCS_SKILLS: true, - }, -}}, true, null, 16); -nyx.addLayer({turret: { - POSITION: [10, 7.5, 0, null, 160, 0], - TYPE: "rocketeerTurret", -}}, true, 6); - -// THEIA -let theia = new LayeredBoss(null, "Theia", "celestial", 9, "gold", "baseTrapTurret", 6.5, 5.5); -theia.addLayer({gun: { - POSITION: [3.8, 6, 1.4, 8, 0, null, 1], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.sunchip, { size: 0.5 }]), - TYPE: ["summonerDrone", {INDEPENDENT: true}], - AUTOFIRE: true, - WAIT_TO_CYCLE: true, - SYNCS_SKILLS: true, - }, -}}, true, null, 35); -theia.addLayer({turret: { - POSITION: [10, 7.5, 0, null, 160, 0], - TYPE: ["twisterTurret", {COLOR: "grey"}], -}}, true, 6); - -// ATLAS -let atlas = new LayeredBoss(null, "Atlas", "celestial", 9, "purple", "baseTrapTurret", 6.5, 5.5); -atlas.addLayer({turret: { - POSITION: [7, 9, 0, null, 180, 0], - TYPE: "artilleryTurret", -}}); -atlas.addLayer({turret: { - POSITION: [10.5, 8, 0, null, 160, 0], - TYPE: "nailgunTurret", -}}, true, 6); - -// RHEA -let rhea = new LayeredBoss(null, "Rhea", "celestial", 9, "darkGrey", "baseTrapTurret", 6.5, 5.5); -rhea.addLayer({turret: { - POSITION: [8.5, 9, 0, null, 180, 0], - TYPE: "wrenchTurret", -}}); -rhea.addLayer({turret: { - POSITION: [10.5, 8, 0, null, 160, 0], - TYPE: "crowbarTurret", -}}, true, 6); - -// JULIUS -let julius = new LayeredBoss(null, "Julius", "celestial", 9, "darkGrey", "baseTrapTurret", 6.5, 5.5); -julius.addLayer({turret: { - POSITION: [8.5, 9, 0, null, 180, 0], - TYPE: "juliusLowerTurret", -}}); -julius.addLayer({turret: { - POSITION: [10.5, 8, 0, null, 160, 0], - TYPE: "launcherTurret", -}}, true, 6); - -// GENGHIS -let genghis = new LayeredBoss(null, "Genghis", "celestial", 9, "darkGrey", "baseTrapTurret", 6.5, 5.5); -genghis.addLayer({turret: { - POSITION: [8.5, 9, 0, null, 180, 0], - TYPE: "genghisLowerTurret", -}}); -genghis.addLayer({turret: { - POSITION: [10.5, 8, 0, null, 160, 0], - TYPE: "auto4gun", -}}, true, 6); - -// NAPOLEON -let napoleon = new LayeredBoss(null, "Napoleon", "celestial", 9, "darkGrey", "baseTrapTurret", 6.5, 5.5); -napoleon.addLayer({turret: { - POSITION: [8.5, 9, 0, null, 180, 0], - TYPE: "napoleonLowerTurret", -}}); -napoleon.addLayer({turret: { - POSITION: [10.5, 8, 0, null, 160, 0], - TYPE: "napoleonUpperTurret", -}}, true, 6) - -// Eternals -let kronos = new LayeredBoss(null, "Kronos", "eternal", 11, "veryLightGrey", "baseTrapTurret", 6, 5.5); -kronos.addLayer({turret: { - POSITION: [6.5, 9, 0, null, 160, 0], - TYPE: "kronosSkimmerTurret", -}}); -kronos.addLayer({turret: { - POSITION: [6.5, 9, 0, null, 160, 0], - TYPE: "carrierTurret", -}}, true, 4); -kronos.addLayer({turret: { - POSITION: [8.5, 9, 0, null, 160, 0], - TYPE: "tripletTurret", -}}, true, 4); - -let odin = new LayeredBoss(null, "Odin", "eternal", 11, "aqua", "baseTrapTurret", 4.5, 3.5); -odin.addLayer({gun: { - POSITION: [2.25, 3.25, -1.6, 9, 0, null, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.factory, { size: 0.5 }, g.pounder, {size: 1.7}]), - TYPE: ["gemDrone", {INDEPENDENT: true,}], - AUTOFIRE: true, - SYNCS_SKILLS: true, - }, -}}, true, null, 18); -odin.addLayer({turret: { - POSITION: [7, 8, 0, null, 160, 0], - TYPE: "autosmashTurret", -}}, true, 5.5); -odin.addLayer({turret: { - POSITION: [8, 9, 0, null, 160, 0], - TYPE: "gunnerCruiserTurret", -}}, true, 4.5); - -// Developer Bosses -Class.taureonCoreBase = { - SHAPE: 4, - COLOR: '#00A2E8' -}; -Class.taureonCore = { - PARENT: "genericTank", - LABEL: "Core Turret", - SHAPE: 4.5, - COLOR: '#99D9EA', - CONTROLLERS: ["nearestDifferentMaster", "onlyAcceptInArc"], - INDEPENDENT: true, - GUNS: [{ - POSITION: [10, 14, -0.5, 14, 0, 0, 0] - },{ - POSITION: [21, 15, -1.1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.destroyer, g.sniper]), - TYPE: "snake", - STAT_CALCULATOR: gunCalcNames.sustained - } - }], - TURRETS: [{ - POSITION: [20 * Math.SQRT2, 0, 0, 0, 0, 0], - TYPE: "taureonCoreBase" - }] -}; -Class.taureonBase = { - SHAPE: 4.5, - COLOR: '#161B54', - MIRROR_MASTER_ANGLE: true -}; -let d = 1/4; -Class.taureonStar = { - SHAPE: [[0,1],[d,d],[1,0],[d,-d],[0,-1],[-d,-d],[-1,0],[-d,d]], - COLOR: '#3F48CC', - MIRROR_MASTER_ANGLE: true -}; -Class.taureonRailgunTurret = { - PARENT: "genericTank", - COLOR: "grey", - LABEL: "Railgun Turret", - CONTROLLERS: ["nearestDifferentMaster", "onlyAcceptInArc"], - INDEPENDENT: true, - GUNS: [{ - POSITION: [20, 7, 1, 0, 0, 0, 0] - },{ - POSITION: [24, 5, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.destroyer, { speed: 5, penetration: 0.8 }]), - TYPE: "bullet" - } - },{ - POSITION: [5, 7.5, -1.6, 8, 0, 0, 0], - }] -}; -Class.taureonThruster = { - PARENT: "genericTank", - COLOR: "grey", - LABEL: "Thruster", - CONTROLLERS: ["onlyAcceptInArc"], - GUNS: [{ - POSITION: [14, 12, 1, 4, 0, 180, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.machineGun, g.thruster, { range: 0.175, reload: 0.25, recoil: 0.25 }]), - TYPE: ["bullet", { ALPHA: 0.5 }] - } - }, { - POSITION: [12, 12, 1.4, 4, 0, 180, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.machineGun, g.thruster, { range: 0.175, reload: 0.25, recoil: 0.25 }]), - TYPE: ["bullet", { ALPHA: 0.5 }] - }, - }] -}; -Class.taureonMissile = { - PARENT: "bullet", - LABEL: "Missile", - FACING_TYPE: "smoothToTarget", - CONTROLLERS: ["nearestDifferentMaster"], - INDEPENDENT: true, - BODY: { - ACCELERATION: 10, - FOV: base.FOV * 2 - }, - TURRETS: [{/** SIZE X Y ANGLE ARC */ - POSITION: [10, 0, 0, 0, 360, 1], - TYPE: ["genericTank", {COLOR: "grey"}], - }], - GUNS: [{/* LENGTH WIDTH ASPECT X Y ANGLE DELAY */ - POSITION: [6, 12, 1.4, 8, 0, 180, 0], - PROPERTIES: { - AUTOFIRE: true, - STAT_CALCULATOR: gunCalcNames.thruster, - SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, { reload: 0.25, range: 0.075 }]), - TYPE: ["bullet", { PERSISTS_AFTER_DEATH: true, ALPHA: 0.5 }] - } - },{ - POSITION: [10, 12, 0.8, 8, 0, 180, 0], - PROPERTIES: { - AUTOFIRE: true, - STAT_CALCULATOR: gunCalcNames.thruster, - SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, { reload: 0.25, range: 0.075 }]), - TYPE: ["bullet", { PERSISTS_AFTER_DEATH: true, ALPHA: 0.5 }] - } - },...Array(32).fill().map((_, i)=>({ - POSITION: [0, (i % 4) + 1, 0, 0, 0, 0, 9999], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.shotgun, { spray: 1e6, range: 0.5, shudder: 1.5, damage: 1 + (i % 4) }]), - TYPE: ["bullet", { PERSISTS_AFTER_DEATH: true }], - SHOOT_ON_DEATH: true - }, - }))] -}; -Class.taureonBoss = { - PARENT: "miniboss", - LABEL: "Diamond Marauder", - NAME: "Taureon", - COLOR: '#2B339B', - UPGRADE_COLOR: "spaceGem", - DANGER: 10, - SHAPE: 4.5, - SIZE: 50, - FACING_TYPE: "smoothToTarget", - UPGRADE_TOOLTIP: "With a powerful Gatling Gun on the front, Rocket Launchers as wings, movable Thrusters on the back, " + - "and equipped with Railgun Turrets, it perfectly excells at terminating those who feel its Wrath.\n" + - "An octahedral carbon robot, exclusively designed to eradicate opponents with sheer brutality alone.\n" + - '"NOW YOU FACE MY ULTIMATE CREATION."', - VALUE: 9e6, - BODY: { - FOV: 1, - SPEED: 0.5 * base.SPEED, - HEALTH: 20 * base.HEALTH, - DAMAGE: 3 * base.DAMAGE, - }, - TURRETS: [{ - POSITION: [23.3, 0, 0, 0, 0, 0], - TYPE: "taureonBase" - },{ - POSITION: [5, 10, 0, -45, 180, 0], - TYPE: "taureonRailgunTurret" - },{ - POSITION: [5, 10, 0, 45, 180, 0], - TYPE: "taureonRailgunTurret" - },{ - POSITION: [5, -10, -2, -45, 90, 0], - TYPE: "taureonThruster" - },{ - POSITION: [5, -10, 2, 45, 90, 0], - TYPE: "taureonThruster" - },{ - POSITION: [25, 0, 0, 0, 0, 1], - TYPE: "taureonStar" - },{ - POSITION: [5, 0, 0, 0, 360, 1], - TYPE: "taureonCore" - }], - GUNS: [...Array(6).fill().map((_, i) => ({ - POSITION: [18, 1.75, 1, 0, Math.cos(Math.PI * i / 3) * 2, 0, i / 6], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, { speed: 2, maxSpeed: 2, damage: 0.75, size: 0.8 }]), - TYPE: "bullet" - } - })),{ - POSITION: [4, 5, -0.5, 12, 0, -90, 0] - },{ - POSITION: [10, 5, -1.2, 5, 0, -90, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.sidewinder, g.destroyer, { shudder: 0.1, reload: 0.6, speed: 5, range: 2 }]), - TYPE: "taureonMissile", - STAT_CALCULATOR: gunCalcNames.sustained - } - },{ - POSITION: [4, 5, -0.5, 12, 0, 90, 0] - },{ - POSITION: [10, 5, -1.2, 5, 0, 90, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.sidewinder, g.destroyer, { shudder: 0.1, reload: 0.6, speed: 5, range: 2 }]), - TYPE: "taureonMissile", - STAT_CALCULATOR: gunCalcNames.sustained - } - },{ - POSITION: [5.5, 5, -1.5, 5, 0, -45, 0] - },{ - POSITION: [5.5, 5, -1.5, 5, 0, 45, 0] - },{ - POSITION: [2, 7, 1, 8, 0, 0, 0] - },{ - POSITION: [2, 7, 1, 14.5, 0, 0, 0] - }] -}; - -Class.zephiMiscDeco = makeDeco(4, "white") -Class.zephiMiscDeco2 = makeDeco(4, "black") -Class.zephiSunchip = makeAuto({ - PARENT: "drone", - SHAPE: 4, - HITS_OWN_TYPE: "hard", - BODY: { - FOV: 0.5, - }, - AI: { - BLIND: true, - FARMER: true, - }, - TURRETS: [{ - POSITION: [20 * Math.SQRT1_2, 0, 0, 45, 0, 1], - TYPE: ["overdriveDeco", { MIRROR_MASTER_ANGLE: true }] - },{ - POSITION: [20 * Math.SQRT1_2 ** 2, 0, 0, 0, 0, 1], - TYPE: ["shinySquare", { MIRROR_MASTER_ANGLE: true }] - }] -}, "Robo-Sunchip", {type: 'autoSmasherTurret', size: 6}) -Class.zephiEggchip = { - PARENT: "drone", - LABEL: "Guided Missile", - SHAPE: 0, - HITS_OWN_TYPE: "hard", - BODY: { - FOV: 0.5, - }, - AI: { - BLIND: true, - FARMER: true, - }, - GUNS: [ - { - POSITION: [14, 6, 1, 0, 0, 180, 0], - PROPERTIES: { - AUTOFIRE: true, - SHOOT_SETTINGS: combineStats([g.basic, g.skimmer, g.lowPower, { reload: 0.5, recoil: 1.35, speed: 1.3, maxSpeed: 1.3 }]), - TYPE: ["bullet", { COLOR: "black", PERSISTS_AFTER_DEATH: true }], - STAT_CALCULATOR: gunCalcNames.thruster, - }, - }, - ], - TURRETS: [{ - POSITION: [10, 0, 0, 45, 0, 1], - TYPE: "gem" - }] -} -Class.zephiGearOuter = makeDeco('M 0.5 0.0929 V -0.0908 L 0.3875 -0.1096 C 0.3792 -0.1409 0.3667 -0.1701 0.3521 -0.1952 L 0.4187 -0.2871 L 0.2896 -0.4186 L 0.1958 -0.3539 C 0.1687 -0.3685 0.1396 -0.381 0.1104 -0.3894 L 0.0917 -0.5 H -0.0917 L -0.1104 -0.3873 C -0.1417 -0.3789 -0.1688 -0.3664 -0.1958 -0.3518 L -0.2875 -0.4165 L -0.4188 -0.2871 L -0.3521 -0.1952 C -0.3667 -0.1681 -0.3792 -0.1388 -0.3875 -0.1075 L -0.5 -0.0908 V 0.0929 L -0.3875 0.1117 C -0.3792 0.143 -0.3667 0.1701 -0.3521 0.1973 L -0.4188 0.2912 L -0.2896 0.4207 L -0.1958 0.3539 C -0.1688 0.3685 -0.1396 0.381 -0.1083 0.3894 L -0.0896 0.5 H 0.0938 L 0.1125 0.3873 C 0.1417 0.3789 0.1708 0.3664 0.1979 0.3518 L 0.2917 0.4186 L 0.4208 0.2891 L 0.3542 0.1952 C 0.3688 0.1681 0.3812 0.1409 0.3896 0.1096 L 0.5 0.0929 Z M 0.3333 0 C 0.3333 0.1841 0.1841 0.3333 0 0.3333 C -0.1841 0.3333 -0.3333 0.1841 -0.3333 0 C -0.3333 -0.1841 -0.1841 -0.3333 0 -0.3333 C 0.1841 -0.3333 0.3333 -0.1841 0.3333 0 Z', '#7F7F7F') -Class.zephiGearOuter.CONTROLLERS = [["spin", { independent: true }]] -Class.zephiGearOuter.BORDERLESS = true -Class.zephiGearCentre = makeDeco(0, '#1F1F1F') -Class.zephiGearCentre.CONTROLLERS = [["spin", { independent: true }]] -Class.zephiGearCentre.BORDERLESS = true -Class.zephiGearRed = makeDeco('M -0.2667 0 C -0.2667 0.0074 -0.2664 0.0147 -0.2658 0.022 C -0.2651 0.0293 -0.2642 0.0366 -0.263 0.0439 C -0.2618 0.0511 -0.2603 0.0583 -0.2585 0.0655 C -0.2567 0.0726 -0.2546 0.0796 -0.2522 0.0866 C -0.2498 0.0935 -0.2472 0.1004 -0.2442 0.1071 C -0.2412 0.1139 -0.238 0.1205 -0.2345 0.1269 C -0.231 0.1334 -0.2273 0.1397 -0.2232 0.1459 C -0.2192 0.152 -0.2149 0.158 -0.2104 0.1638 C -0.2059 0.1696 -0.2012 0.1752 -0.1962 0.1806 C -0.1912 0.186 -0.186 0.1912 -0.1806 0.1962 C -0.1752 0.2012 -0.1696 0.2059 -0.1638 0.2104 C -0.158 0.215 -0.152 0.2192 -0.1458 0.2232 C -0.1397 0.2273 -0.1334 0.231 -0.1269 0.2345 C -0.1204 0.238 -0.1138 0.2413 -0.1071 0.2442 C -0.1032 0.2458 -0.1 0.2436 -0.1 0.2393 V -0.2393 C -0.1 -0.2436 -0.1032 -0.2458 -0.1071 -0.2442 C -0.1138 -0.2413 -0.1204 -0.238 -0.1269 -0.2345 C -0.1334 -0.231 -0.1397 -0.2273 -0.1458 -0.2232 C -0.152 -0.2192 -0.158 -0.215 -0.1638 -0.2104 C -0.1696 -0.2059 -0.1752 -0.2012 -0.1806 -0.1962 C -0.186 -0.1912 -0.1912 -0.186 -0.1962 -0.1806 C -0.2012 -0.1752 -0.2059 -0.1696 -0.2104 -0.1638 C -0.2149 -0.158 -0.2192 -0.152 -0.2232 -0.1458 C -0.2273 -0.1397 -0.231 -0.1334 -0.2345 -0.1269 C -0.238 -0.1205 -0.2412 -0.1138 -0.2442 -0.1071 C -0.2472 -0.1004 -0.2498 -0.0935 -0.2522 -0.0866 C -0.2546 -0.0796 -0.2567 -0.0726 -0.2585 -0.0655 C -0.2603 -0.0583 -0.2618 -0.0511 -0.263 -0.0439 C -0.2642 -0.0366 -0.2651 -0.0293 -0.2658 -0.022 C -0.2664 -0.0147 -0.2667 -0.0073 -0.2667 0 Z', '#FF1F1F') -Class.zephiGearRed.CONTROLLERS = [["spin", { independent: true }]] -Class.zephiGearRed.BORDERLESS = true -Class.zephiGearGreen = makeDeco('M 0.0771 -0.2552 C 0.0743 -0.2561 0.0691 -0.2576 0.0657 -0.2585 L 0.0607 -0.2597 C 0.0571 -0.2605 0.0514 -0.2617 0.0479 -0.2623 L 0.0428 -0.2632 C 0.0392 -0.2638 0.0334 -0.2646 0.0299 -0.265 L 0.0247 -0.2655 C 0.0211 -0.2659 0.0153 -0.2662 0.0117 -0.2664 L 0.0066 -0.2666 C 0.003 -0.2667 -0.0029 -0.2667 -0.0065 -0.2666 L -0.0116 -0.2664 C -0.0153 -0.2662 -0.0211 -0.2659 -0.0247 -0.2655 L -0.0298 -0.265 C -0.0334 -0.2646 -0.0392 -0.2638 -0.0427 -0.2632 L -0.0478 -0.2623 C -0.0514 -0.2617 -0.0571 -0.2605 -0.0606 -0.2597 L -0.0656 -0.2585 C -0.0691 -0.2576 -0.0747 -0.256 -0.0782 -0.2549 C -0.081 -0.254 -0.0833 -0.2502 -0.0833 -0.2466 V 0.2466 C -0.0833 0.2502 -0.0805 0.2541 -0.0771 0.2552 C -0.0743 0.2561 -0.0691 0.2576 -0.0656 0.2585 L -0.0606 0.2597 C -0.0571 0.2605 -0.0514 0.2617 -0.0478 0.2623 L -0.0427 0.2632 C -0.0392 0.2638 -0.0334 0.2646 -0.0298 0.265 L -0.0247 0.2655 C -0.0211 0.2659 -0.0153 0.2663 -0.0116 0.2664 L -0.0065 0.2666 C -0.0029 0.2667 0.003 0.2667 0.0066 0.2666 L 0.0117 0.2664 C 0.0153 0.2663 0.0211 0.2659 0.0247 0.2655 L 0.0299 0.265 C 0.0334 0.2646 0.0392 0.2638 0.0428 0.2632 L 0.0479 0.2623 C 0.0514 0.2617 0.0571 0.2605 0.0607 0.2597 L 0.0657 0.2585 C 0.0691 0.2576 0.0748 0.256 0.0782 0.2549 C 0.0811 0.254 0.0834 0.2502 0.0834 0.2466 V -0.2466 C 0.0834 -0.2502 0.0806 -0.2541 0.0771 -0.2552 Z', '#1FDF1F') -Class.zephiGearGreen.CONTROLLERS = [["spin", { independent: true }]] -Class.zephiGearGreen.BORDERLESS = true -Class.zephiGearBlue = makeDeco('M -0.2667 0 C -0.2667 0.0074 -0.2664 0.0147 -0.2658 0.022 C -0.2651 0.0293 -0.2642 0.0366 -0.263 0.0439 C -0.2618 0.0511 -0.2603 0.0583 -0.2585 0.0655 C -0.2567 0.0726 -0.2546 0.0796 -0.2522 0.0866 C -0.2498 0.0935 -0.2472 0.1004 -0.2442 0.1071 C -0.2412 0.1139 -0.238 0.1205 -0.2345 0.1269 C -0.231 0.1334 -0.2273 0.1397 -0.2232 0.1459 C -0.2192 0.152 -0.2149 0.158 -0.2104 0.1638 C -0.2059 0.1696 -0.2012 0.1752 -0.1962 0.1806 C -0.1912 0.186 -0.186 0.1912 -0.1806 0.1962 C -0.1752 0.2012 -0.1696 0.2059 -0.1638 0.2104 C -0.158 0.215 -0.152 0.2192 -0.1458 0.2232 C -0.1397 0.2273 -0.1334 0.231 -0.1269 0.2345 C -0.1204 0.238 -0.1138 0.2413 -0.1071 0.2442 C -0.1032 0.2458 -0.1 0.2436 -0.1 0.2393 V -0.2393 C -0.1 -0.2436 -0.1032 -0.2458 -0.1071 -0.2442 C -0.1138 -0.2413 -0.1204 -0.238 -0.1269 -0.2345 C -0.1334 -0.231 -0.1397 -0.2273 -0.1458 -0.2232 C -0.152 -0.2192 -0.158 -0.215 -0.1638 -0.2104 C -0.1696 -0.2059 -0.1752 -0.2012 -0.1806 -0.1962 C -0.186 -0.1912 -0.1912 -0.186 -0.1962 -0.1806 C -0.2012 -0.1752 -0.2059 -0.1696 -0.2104 -0.1638 C -0.2149 -0.158 -0.2192 -0.152 -0.2232 -0.1458 C -0.2273 -0.1397 -0.231 -0.1334 -0.2345 -0.1269 C -0.238 -0.1205 -0.2412 -0.1138 -0.2442 -0.1071 C -0.2472 -0.1004 -0.2498 -0.0935 -0.2522 -0.0866 C -0.2546 -0.0796 -0.2567 -0.0726 -0.2585 -0.0655 C -0.2603 -0.0583 -0.2618 -0.0511 -0.263 -0.0439 C -0.2642 -0.0366 -0.2651 -0.0293 -0.2658 -0.022 C -0.2664 -0.0147 -0.2667 -0.0073 -0.2667 0 Z', '#1F7FDF') -Class.zephiGearBlue.CONTROLLERS = [["spin", { independent: true }]] -Class.zephiGearBlue.BORDERLESS = true -Class.zephiBoss = { - PARENT: "miniboss", - LABEL: "Shiny Mecha-Thaumaturge", - NAME: "Zephi", - DANGER: 10, - SHAPE: 4, - COLOR: "lightGreen", - UPGRADE_COLOR: "lightGreen", - SIZE: 50, - VALUE: 5e6, - SKILL: skillSet({ - rld: 1, - dam: 1, - pen: 1, - str: 1, - spd: 1, - atk: 1, - hlt: 1, - shi: 1, - rgn: 1, - mob: 1, - }), - BODY: { - FOV: 0.75, - SPEED: 0.05 * base.SPEED, - HEALTH: 15 * base.HEALTH, - DAMAGE: 5 * base.DAMAGE, - }, - UPGRADE_TOOLTIP: "Good luck.", - GUNS: Array(4).fill().map((_, i) => ([{ - POSITION: [2.5, 3, 1.2, 8, 5, i * 90, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.summoner, g.pounder, { speed: 2.5 }, g.machineGun, { spray: 50, speed: 1.25, shudder: 1.25 }]), - TYPE: ["zephiEggchip", {COLOR: "black"}], - MAX_CHILDREN: 8, - AUTOFIRE: true, - SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.necro, - WAIT_TO_CYCLE: true, - COLOR: "black", - } - },{ - POSITION: [2.5, 3, 1.2, 8, -5, i * 90, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.summoner, g.pounder, { speed: 2.5 }, g.machineGun, { spray: 150, speed: 1.25, shudder: 1.25 }]), - TYPE: ["zephiEggchip", {COLOR: "black"}], - MAX_CHILDREN: 8, - AUTOFIRE: true, - SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.necro, - WAIT_TO_CYCLE: true, - COLOR: "black", - } - },{ - POSITION: [3.5, 8.65, 1.2, 8, 0, i * 90, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.summoner, g.destroyer, g.destroyer, { speed: 2.5 }, { maxSpeed: 3 }]), - TYPE: ["zephiSunchip", {COLOR: "black"}], - MAX_CHILDREN: 4, - AUTOFIRE: true, - SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.necro, - WAIT_TO_CYCLE: true - } - }])).flat(), - TURRETS: [{ - POSITION: [16 * Math.SQRT1_2, 0, 0, 0, 360, 2], - TYPE: "zephiGearOuter" - },{ - POSITION: [5.375 * Math.SQRT1_2, 0, 0, 0, 360, 2], - TYPE: "zephiGearCentre" - },{ - POSITION: [16 * Math.SQRT1_2, 0, 0, 0, 360, 2], - TYPE: "zephiGearRed" - },{ - POSITION: [16 * Math.SQRT1_2, 0, 0, 0, 360, 2], - TYPE: "zephiGearGreen" - },{ - POSITION: [16 * Math.SQRT1_2, 0, 0, 180, 360, 2], - TYPE: "zephiGearBlue" - },{ - POSITION: [20 * Math.SQRT1_2, 0, 0, 45, 0, 1], - TYPE: "overdriveDeco" - },{ - POSITION: [20 * Math.SQRT1_2 ** 2, 0, 0, 0, 0, 1], - TYPE: "zephiMiscDeco2" - },{ - POSITION: [20 * Math.SQRT1_2 ** 3, 0, 0, 45, 0, 1], - TYPE: "zephiMiscDeco" - }] -}; - -Class.dogeiscutBody = { - PARENT: "genericTank", - COLOR: "grey", - SHAPE: [[1,0],[-0.7,0.7],[-0.35,0],[-0.7,-0.7]] -} -Class.dogeiscutTurret = { - PARENT: "genericTank", - COLOR: "grey", - GUNS: [ { - POSITION: [ 50, 5, 2.5, 0, 0, 0, 0, ], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.assassin, g.minigun, {reload: 0.1}]), - TYPE: "bullet", - }, - }, { - POSITION: [ 18, 8, -2, 0, 0, 0, 0, ], - }, - ], - TURRETS: [ - { - POSITION: [16, 0, 0, 0, 360, 1], - TYPE: ["genericTank", { MIRROR_MASTER_ANGLE: true, COLOR: "#f6c6a2"}], - }, - { - POSITION: [12, 0, 0, 0, 360, 1], - TYPE: ["genericTank", { MIRROR_MASTER_ANGLE: true, COLOR: "pink"}], - }, - ] -} -function createDogeiscutMissileTurret(color) { - return { - PARENT: "genericTank", - COLOR: "grey", - GUNS: [ { - POSITION: [ 15, 8, 2.5, 0, 0, 180, 0, ], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([ - g.basic, - g.skimmer, - { reload: 0.5 }, - g.lowPower, - { recoil: 1.35 }, - { speed: 1.3, maxSpeed: 1.3 }, - { speed: 1.3, maxSpeed: 1.3 }, - {reload: 0.15, recoil: 1, range: 0.1}]), - TYPE: ["bullet", - { - PERSISTS_AFTER_DEATH: true, - COLOR: color - }, - ], - AUTOFIRE: true, - STAT_CALCULATOR: gunCalcNames.thruster, - }, - }, - ], - } -} -function createDogeiscutMissile(color) { - return { - PARENT: "bullet", - LABEL: color + " Missile", - COLOR: color, - GUNS: [...Array(11).fill().map((_, i)=>({ - POSITION: [0, 8, 0, 0, 0, ((360) / 11)*i, 9999], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.shotgun, g.noSpread, { recoil: 0, range: 0.4, damage: 2.5, density: 30 }]), - TYPE: ["bullet", { PERSISTS_AFTER_DEATH: true, COLOR: color }], - SHOOT_ON_DEATH: true, - }, - }))], - TURRETS: [ - { - POSITION: [16, 0, 0, 0, 360, 1], - TYPE: ["dogeiscutMissileTurret_" + color], - }, - { - POSITION: [12, 0, 0, 0, 360, 1], - TYPE: ["genericTank", {COLOR: "grey"}], - } - ] - } -} -Class.dogeiscutMissileTurret_red = createDogeiscutMissileTurret('red') -Class.dogeiscutMissile_red = createDogeiscutMissile('red') -Class.dogeiscutMissileTurret_orange = createDogeiscutMissileTurret('orange') -Class.dogeiscutMissile_orange = createDogeiscutMissile('orange') -Class.dogeiscutMissileTurret_yellow = createDogeiscutMissileTurret('yellow') -Class.dogeiscutMissile_yellow = createDogeiscutMissile('yellow') -Class.dogeiscutMissileTurret_green = createDogeiscutMissileTurret('green') -Class.dogeiscutMissile_green = createDogeiscutMissile('green') -Class.dogeiscutMissileTurret_cyan = createDogeiscutMissileTurret('cyan') -Class.dogeiscutMissile_cyan = createDogeiscutMissile('cyan') -Class.dogeiscutMissileTurret_blue = createDogeiscutMissileTurret('blue') -Class.dogeiscutMissile_blue = createDogeiscutMissile('blue') -Class.dogeiscutMissileTurret_purple = createDogeiscutMissileTurret('purple') -Class.dogeiscutMissile_purple = createDogeiscutMissile('purple') -Class.dogeiscutBomb = { - PARENT: "trap", - LABEL: "Bomb", - SHAPE: 0, - GUNS: [...Array(32).fill().map((_, i)=>({ - POSITION: [0, 8, 0, 0, 0, ((360) / 32)*i, 9999], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.shotgun, g.noSpread, { recoil: 0, range: 0.4, damage: 2.5, size: 0.5}]), - TYPE: ["bullet", { PERSISTS_AFTER_DEATH: true }], - SHOOT_ON_DEATH: true, - }, - })),...Array(10).fill().map((_,i)=>({ - POSITION: [12, 3.5, 1, 0, 0, (360/10)*i, (i%3)/3], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([ - g.basic, - g.twin, - g.gunner, - g.cyclone, - {reload: 3} - ]), - TYPE: "bullet", - AUTOFIRE: true, - }, - })) - ], - TURRETS: [ - { - POSITION: [8, 0, 0, 0, 360, 1], - TYPE: ["genericTank", {COLOR: "grey"}], - } - ] - } -Class.dogeiscutBoss = { - PARENT: "miniboss", - LABEL: "DOG", - NAME: "DogeisCut", - DANGER: 10, - FACING_TYPE: "smoothToTarget", - SHAPE: [[1,0],[-0.7,0.7],[-0.35,0],[-0.7,-0.7]], - COLOR: "yellow", - UPGRADE_COLOR: "yellow", - SIZE: 50, - VALUE: 5e6, - BODY: { - FOV: 0.75, - SPEED: 0.25 * base.SPEED, - HEALTH: 14 * base.HEALTH, - DAMAGE: 4 * base.DAMAGE, - }, - GUNS: [ { - POSITION: [ 6, 8, 1.5, 3, 0, 180, 0, ], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.destroyer, g.annihilator, {size: 1, reload: 3, recoil: 5}]), - TYPE: ["dogeiscutBomb"], - STAT_CALCULATOR: gunCalcNames.sustained, - } - }, { - POSITION: [ 4, 4, 1.5, 3, 0, 180, 0, ], - PROPERTIES: { - COLOR: "black" - } - }, - - { - POSITION: [ 1, 2, 1, 4, -8, 68, 0, ], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.sidewinder, {speed: 3, range: 0.8, reload: 4}]), - TYPE: ["dogeiscutMissile_red"], - STAT_CALCULATOR: gunCalcNames.sustained, - COLOR: 'red' - } - }, { - POSITION: [ 1, 2, 1, 4, -5.333, 68, 1/7, ], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.sidewinder, {speed: 3, range: 0.8, reload: 4}]), - TYPE: ["dogeiscutMissile_orange"], - STAT_CALCULATOR: gunCalcNames.sustained, - COLOR: 'orange' - } - }, { - POSITION: [ 1, 2, 1, 4, -2.666, 68, (1/7)*2, ], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.sidewinder, {speed: 3, range: 0.8, reload: 4}]), - TYPE: ["dogeiscutMissile_yellow"], - STAT_CALCULATOR: gunCalcNames.sustained, - COLOR: 'yellow' - } - }, { - POSITION: [ 1, 2, 1, 4, 0, 68, (1/7)*3, ], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.sidewinder, {speed: 3, range: 0.8, reload: 4}]), - TYPE: ["dogeiscutMissile_green"], - STAT_CALCULATOR: gunCalcNames.sustained, - COLOR: 'green' - } - }, { - POSITION: [ 1, 2, 1, 4, 2.666, 68, (1/7)*4, ], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.sidewinder, {speed: 3, range: 0.8, reload: 4}]), - TYPE: ["dogeiscutMissile_cyan"], - STAT_CALCULATOR: gunCalcNames.sustained, - COLOR: 'cyan' - } - }, { - POSITION: [ 1, 2, 1, 4, 5.333, 68, (1/7)*5, ], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.sidewinder, {speed: 3, range: 0.8, reload: 4}]), - TYPE: ["dogeiscutMissile_blue"], - STAT_CALCULATOR: gunCalcNames.sustained, - COLOR: 'blue' - } - }, { - POSITION: [ 1, 2, 1, 4, 8, 68, (1/7)*6, ], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.sidewinder, {speed: 3, range: 0.8, reload: 4}]), - TYPE: ["dogeiscutMissile_purple"], - STAT_CALCULATOR: gunCalcNames.sustained, - COLOR: 'purple' - } - }, - - - { - POSITION: [ 1, 2, 1, 4, 8, -68, 0, ], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.sidewinder, {speed: 3, range: 0.8, reload: 4}]), - TYPE: ["dogeiscutMissile_red"], - STAT_CALCULATOR: gunCalcNames.sustained, - COLOR: 'red' - } - }, { - POSITION: [ 1, 2, 1, 4, 5.333, -68, 1/7, ], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.sidewinder, {speed: 3, range: 0.8, reload: 4}]), - TYPE: ["dogeiscutMissile_orange"], - STAT_CALCULATOR: gunCalcNames.sustained, - COLOR: 'orange' - } - }, { - POSITION: [ 1, 2, 1, 4, 2.666, -68, (1/7)*2, ], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.sidewinder, {speed: 3, range: 0.8, reload: 4}]), - TYPE: ["dogeiscutMissile_yellow"], - STAT_CALCULATOR: gunCalcNames.sustained, - COLOR: 'yellow' - } - }, { - POSITION: [ 1, 2, 1, 4, 0, -68, (1/7)*3, ], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.sidewinder, {speed: 3, range: 0.8, reload: 4}]), - TYPE: ["dogeiscutMissile_green"], - STAT_CALCULATOR: gunCalcNames.sustained, - COLOR: 'green' - } - }, { - POSITION: [ 1, 2, 1, 4, -2.666, -68, (1/7)*4, ], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.sidewinder, {speed: 3, range: 0.8, reload: 4}]), - TYPE: ["dogeiscutMissile_cyan"], - STAT_CALCULATOR: gunCalcNames.sustained, - COLOR: 'cyan' - } - }, { - POSITION: [ 1, 2, 1, 4, -5.333, -68, (1/7)*5, ], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.sidewinder, {speed: 3, range: 0.8, reload: 4}]), - TYPE: ["dogeiscutMissile_blue"], - STAT_CALCULATOR: gunCalcNames.sustained, - COLOR: 'blue' - } - }, { - POSITION: [ 1, 2, 1, 4, -8, -68, (1/7)*6, ], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.sidewinder, {speed: 3, range: 0.8, reload: 4}]), - TYPE: ["dogeiscutMissile_purple"], - STAT_CALCULATOR: gunCalcNames.sustained, - COLOR: 'purple' - } - }, - ], - TURRETS: [ - { - POSITION: [16, 0, 0, 0, 360, 1], - TYPE: ["dogeiscutBody", { MIRROR_MASTER_ANGLE: true, COLOR: "#f6c6a2"}], - }, - { - POSITION: [12, 0, 0, 0, 360, 1], - TYPE: ["dogeiscutBody", { MIRROR_MASTER_ANGLE: true, COLOR: "pink"}], - }, - { - POSITION: [5, 0, 0, 0, 360, 1], - TYPE: ["dogeiscutTurret", { INDEPENDENT: true, CONTROLLERS: ["nearestDifferentMaster"], COLOR: "yellow" }], - }, - { - POSITION: [1, 10.5, 0, 0, 360, 0], - TYPE: ["genericTank", {COLOR: "black"}], - }, - ] -} -Class.trplnrBossAuraBulletAura = addAura(1, 0.8) -Class.trplnrBossAuraBullet = { - PARENT: 'genericTank', - LABEL: 'Nest', - SHAPE: -4, - PERSISTS_AFTER_DEATH: true, - BODY: { - HEALTH: 100, - }, - SIZE: 25, - COLOR: '#F49EFF', - GLOW: { - STRENGTH: 25, - COLOR: 'mirror', - ALPHA: 1 - }, - DRAW_HEALTH: true, - GUNS: (() => { - let output = [] - for (let i = 0; i < 4; i++) { - output.push({ - POSITION: { ANGLE: (360/4)*i, ASPECT: -0.35, X: -5 }, - PROPERTIES: { - COLOR: 'white', - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, { size: 0.8 }, {reload: 1.6, damage: 1.5}]), - TYPE: 'autoswarm', - AUTOFIRE: true, - }, - }) - } - return output - })(), - TURRETS: [ - { - POSITION: {SIZE: 10, LAYER: 1}, - TYPE: "trplnrBossAuraBulletAura" - } - ] -} -const trplnrBossDecor = { - COLOR: '#F49EFF', - UPGRADE_COLOR: "lavender", - LABEL: 'Lavender', - NAME: 'Trioplane', - SHAPE: 3, - SIZE: 25, - VALUE: 5e7, - DANGER: 10, - GLOW: { - RADIUS: 15, - COLOR: 'mirror', - ALPHA: 1, - RECURSION: 5 - }, - PROPS: [{ - POSITION: { SIZE: 25 ** Math.SQRT1_2, ANGLE: 180, LAYER: 1 }, - TYPE: ['triangle', { COLOR: 'black', MIRROR_MASTER_ANGLE: true }] - }, { - POSITION: { SIZE: 25 ** Math.SQRT1_2, LAYER: 1 }, - TYPE: ['triangle', { COLOR: -1, MIRROR_MASTER_ANGLE: true }] - }, { - POSITION: { SIZE: 25 }, - TYPE: ['triangle', { COLOR: 'black', MIRROR_MASTER_ANGLE: true }] - }], -} -Class.trplnrBoss = { - PARENT: "miniboss", - ...trplnrBossDecor, - UPGRADE_TOOLTIP: "\"Heck, even The Guardians are afraid of him, \n" + - "They usually call him the The Light, Victory, Death and Ruler of the Pentagon Race a.k.a Lvndr. \n" + - "We don't know where his teleportation powers came from, \n" + - "He was secretive of it. \n" + - "Though some say there was an old script found at the Neutrality Point \n" + - "at the middle of the nest when it still existed, It had some \n" + - "sort of drawing of a tank going through walls, and this thing that said '6@D M0|)3 \n" + - "Nest Reseachers still haven't been able to decipher it though. \n" + - "One day, The Neutrality Point left and on that same day, \n" + - "A sentry's child went missing, \n" + - "Coincidence? I think not.\"", - BODY: { - HEALTH: 500, - }, - ON: [ - { - event: 'fire', - handler: ({ body, gun }) => { - if (gun.identifier != 'onHandler') return - const messages = [ - 'Attack my little swarms!', - 'Deploying, Attack swarms', - 'You really think you can defeat me? Heres a little challenge for you.', - 'This thing is really gonna annoy you HAHA!', - 'I don\'t know what to say uhhh, die i guess.' - ] - sockets.broadcast(messages[Math.floor(Math.random() * messages.length)]) - sockets.broadcast('Lavender will turn into `BULL3T HELL F0rM`, Run!') - for (let i = 0; i < 24; i++) { - i < 12 ? - setTimeout(() => { body.SIZE /= 1.1; body.alpha /= 1.2 }, i * 50) - : - setTimeout(() => { body.SIZE *= 1.1; body.alpha *= 1.2 }, i * 50) - } - setTimeout(() => { - let range = 500 - let whereToGoX = Math.random() > 0.5 ? Math.floor(Math.random() * -range) : Math.floor(Math.random() * range) - let whereToGoY = Math.random() > 0.5 ? Math.floor(Math.random() * -range) : Math.floor(Math.random() * range) - body.x += whereToGoX - body.y += whereToGoY - }, 12 * 50); - setTimeout(() => body.define('trplnrBossBulletHellForm'), 24 * 50) - } - } - ], - GUNS: [], - GUNS: (() => { - let output = [] - for (let i = 0; i<2; i++) { - output.push({ - POSITION: { WIDTH: 10, X: -5, ASPECT: -0.7, ANGLE: ((360 / 3) * i) - 180 }, - PROPERTIES: { - COLOR: 'white', - SHOOT_SETTINGS: combineStats([g.basic, {reload: 100}]), - TYPE: "trplnrBossAuraBullet", - INDEPENDENT_CHILDREN: true, - } - }) - } - output.push({ - POSITION: { WIDTH: 10, X: -5, ASPECT: -0.7, ANGLE: ((360 / 3) * 2) - 180 }, - PROPERTIES: { - COLOR: 'white', - SHOOT_SETTINGS: combineStats([g.basic, {reload: 100}]), - TYPE: "trplnrBossAuraBullet", - INDEPENDENT_CHILDREN: true, - IDENTIFIER: 'onHandler', - ALPHA: 0, - } - }) - for (let i = 0; i < 3; i++) { - output.push({ - POSITION: { WIDTH: 5, ASPECT: -0.7, ANGLE: ((360 / 3) * i) - 180 }, - PROPERTIES: { - COLOR: 'black' - } - }) - output.push({ - POSITION: { WIDTH: 5, HEIGHT: 5, X: -30, ASPECT: 0, ANGLE: ((360 / 3) * i) - 180 }, - PROPERTIES: { - COLOR: 'black' - } - }, { - POSITION: { WIDTH: 5, HEIGHT: 5, X: -25, ASPECT: 0, ANGLE: ((360 / 3) * i) - 180 }, - PROPERTIES: { - COLOR: 'white' - } - }) - } - return output - })() -} - -Class.trplnrBossBulletHellFormPentagonsAuraBullet = { - PARENT: 'bullet', - PERSISTS_AFTER_DEATH: true, - TURRETS: [{ - POSITION: {SIZE: 13, LAYER: 1}, - TYPE: "trplnrBossAuraBulletAura" - }] -} - -Class.trplnrBossBulletHellFormPentagons = { - PARENT: 'bullet', - LABEL: 'Pentagon', - SHAPE: -5, - PROPS: [{ - POSITION: { SIZE: 40 ** Math.SQRT1_2, ANGLE: 180, LAYER: 1 }, - TYPE: ['pentagon', {COLOR: 'black', MIRROR_MASTER_ANGLE: true}] - }], - GUNS: (() => { - let output = [] - for (let i = 0; i < 5; i++) { - output.push({ - POSITION: { WIDTH: 10, HEIGHT: 10, ANGLE: ((360/5)*i) - 180, DELAY: 11.5 }, - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, {reload: 0.4}]), - TYPE: 'trplnrBossBulletHellFormPentagonsAuraBullet', - AUTOFIRE: true, - COLOR: 'white', - } - }) - } - return output - })() -} -Class.trplnrBossBulletHellForm = { - PARENT: "miniboss", - ...trplnrBossDecor, - LABEL: 'Lavender - Bullet Hell Form', - BODY: { - HEALTH: 500, - }, - ON: [ - { - event: "fire", - handler: ({ body, masterStore, gun }) => { - if (gun.identifier != 'onHandler') return - masterStore.shotsFired ??= 0 - masterStore.shotsFired++ - - for (let i = 0; i < 24; i++) { - i < 12 ? - setTimeout(() => { body.SIZE /= 1.1; body.alpha /= 1.2 }, i * 50) - : - setTimeout(() => { body.SIZE *= 1.1; body.alpha *= 1.2 }, i * 50) - } - setTimeout(() => { - let range = 500 - let whereToGoX = Math.random() > 0.5 ? Math.floor(Math.random() * -range) : Math.floor(Math.random() * range) - let whereToGoY = Math.random() > 0.5 ? Math.floor(Math.random() * -range) : Math.floor(Math.random() * range) - body.x += whereToGoX - body.y += whereToGoY - }, 12 * 50) - - if (masterStore.shotsFired > 5) { - body.define('trplnrBossVulnerableForm') - const messages = [ - 'I\'m a little tired right now', - 'Ouch my leg!', - 'i sleep', - 'Bruh my keyboard isn\'t working', - 'Omg bruh I chose the wrong form' - ] - sockets.broadcast(messages[Math.floor(Math.random() * messages.length)]) - sockets.broadcast('Lavender is in its `VULN3RABLE F0RM`, Attack!') - } - } - } - ], - GUNS: [], - GUNS: (() => { - let output = [] - for (let i = 0; i<3; i++) { - output.push({ - POSITION: { WIDTH: 15, HEIGHT: 5, ANGLE: ((360 / 3) * i)-180, ASPECT: 0, X: -25 }, - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.destroyer, g.annihilator, { reload: 1 }]), - TYPE: 'trplnrBossBulletHellFormPentagonsAuraBullet', - COLOR: 'black' - } - }, { - POSITION: { WIDTH: 15, HEIGHT: 5, ANGLE: ((360 / 3) * i)-180, ASPECT: 0, X: -20 }, - PROPERTIES: { - COLOR: 'white' - } - }, { - POSITION: { WIDTH: 10, HEIGHT: 5, ASPECT: 1.5, ANGLE: ((360 / 3) * i) - 180 }, - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.destroyer, g.annihilator, { reload: 3 }]), - TYPE: 'trplnrBossBulletHellFormPentagons', - COLOR: 'white' - } - }, { - POSITION: { WIDTH: 8, HEIGHT: 3, X: -1, ASPECT: 1.5, ANGLE: ((360 / 3) * i) - 180 }, - PROPERTIES: { - COLOR: 'pureWhite', - } - }, { - POSITION: { WIDTH: 5, HEIGHT: 10, X: 5, ASPECT: 0.2, ANGLE: ((360 / 3) * i) - 180 }, - PROPERTIES: { - COLOR: -1, - } - }) - } - output.push({ - POSITION: { WIDTH: 0, HEIGHT: 0 }, - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.destroyer, g.annihilator, { reload: 2 }, g.fake]), - TYPE: 'bullet', - IDENTIFIER: 'onHandler', - ALPHA: 0 - } - }) - return output - })() -} -Class.trplnrBossVulnerableForm = { - PARENT: "miniboss", - ...trplnrBossDecor, - LABEL: 'Lavender - Vulnerable Form', - BODY: { - HEALTH: 500, - SPEED: 0.1 - }, - ON: [ - { - event: "tick", - handler: ({ body }) => { - body.store.ticks ??= 0 - body.store.ticks++ - const spawnCrashers = body.store.ticks % 3 == 0 - const spawnSentries = body.store.ticks % 60 == 0 - const sentries = ["sentrySwarm", "sentryGun", "sentryTrap"] - if (spawnCrashers) new Entity(body, body).define("crasher") - if (spawnSentries) new Entity(body, body).define(sentries[Math.floor(Math.random() * sentries.length)]) - } - }, - { - event: "fire", - handler: ({ body, gun }) => { - if (gun.identifier != 'onHandler') return - setTimeout(() => { - body.define('trplnrBoss') - sockets.broadcast('im awake') - }, 15000) - setTimeout(() => sockets.broadcast('Lavender will activate in 10 seconds and turn into S4nctuary F0rM'), 5000) - } - } - ], - GUNS: [{ - POSITION: {LENGTH: 0, WIDTH: 0}, - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, {reload: 500}]), - TYPE: 'bullet', - AUTOFIRE: true, - IDENTIFIER: 'onHandler', - ALPHA: 0 - } - }] -} - -Class.frostAuraSmall = { - PARENT: "aura", - LAYER: 30, - FACING_TYPE: ["spin", {speed: -0.04}], - BORDERLESS: true, - SHAPE: "M 1 0 L 0.715 0.519 L 0.309 0.951 L -0.273 0.84 L -0.809 0.588 L -0.883 0 L -0.809 -0.588 L -0.273 -0.84 L 0.309 -0.951 L 0.715 -0.519 L 1 0", - TURRETS: [{ - POSITION: [20, 0, 0, 0, 0, 1], - TYPE: 'frostAuraSmallOutline' - }] -} -Class.frostAuraSmallOutline = { - PARENT: "aura", - MIRROR_MASTER_ANGLE: true, - DRAW_FILL: false, - SHAPE: "M 1 0 L 0.715 0.519 L 0.309 0.951 L -0.273 0.84 L -0.809 0.588 L -0.883 0 L -0.809 -0.588 L -0.273 -0.84 L 0.309 -0.951 L 0.715 -0.519 L 1 0" + - "L 0.309 0.951 L -0.809 0.588 L -0.809 -0.588 L 0.309 -0.951 L 1 0" + - "L 0 0 L 0.309 0.951 M 0 0 L -0.809 0.588 M 0 0 L -0.809 -0.588 M 0 0 L 0.309 -0.951", -} -Class.frostAuraLarge = { - PARENT: "aura", - LAYER: 30, - FACING_TYPE: ["spin", {speed: -0.04}], - BORDERLESS: true, - SHAPE: "M 1 0 L 0.988 0.156 L 0.951 0.309 L 0.891 0.454 L 0.809 0.588 L 0.707 0.707 L 0.588 0.809 L 0.454 0.891 L 0.309 0.951 L 0.156 0.988 L 0 1 L -0.156 0.988 L -0.309 0.951 L -0.454 0.891 L -0.588 0.809 L -0.707 0.707 L -0.809 0.588 L -0.891 0.454 L -0.951 0.309 L -0.988 0.156 L -1 0 L -0.988 -0.156 L -0.951 -0.309 L -0.891 -0.454 L -0.809 -0.588 L -0.707 -0.707 L -0.588 -0.809 L -0.454 -0.891 L -0.309 -0.951 L -0.156 -0.988 L 0 -1 L 0.156 -0.988 L 0.309 -0.951 L 0.454 -0.891 L 0.588 -0.809 L 0.707 -0.707 L 0.809 -0.588 L 0.891 -0.454 L 0.951 -0.309 L 0.988 -0.156 L 1 0", - TURRETS: [{ - POSITION: [20, 0, 0, 0, 0, 1], - TYPE: 'frostAuraLargeOutline' - }] -} -Class.frostAuraLargeOutline = { - PARENT: "aura", - MIRROR_MASTER_ANGLE: true, - DRAW_FILL: false, - SHAPE: "M 1 0 L 0.988 0.156 L 0.951 0.309 L 0.891 0.454 L 0.809 0.588 L 0.707 0.707 L 0.588 0.809 L 0.454 0.891 L 0.309 0.951 L 0.156 0.988 L 0 1 L -0.156 0.988 L -0.309 0.951 L -0.454 0.891 L -0.588 0.809 L -0.707 0.707 L -0.809 0.588 L -0.891 0.454 L -0.951 0.309 L -0.988 0.156 L -1 0 L -0.988 -0.156 L -0.951 -0.309 L -0.891 -0.454 L -0.809 -0.588 L -0.707 -0.707 L -0.588 -0.809 L -0.454 -0.891 L -0.309 -0.951 L -0.156 -0.988 L 0 -1 L 0.156 -0.988 L 0.309 -0.951 L 0.454 -0.891 L 0.588 -0.809 L 0.707 -0.707 L 0.809 -0.588 L 0.891 -0.454 L 0.951 -0.309 L 0.988 -0.156 L 1 0" + - "M 0.988 -0.156 L 0.988 0.156 L 0.891 0.454 L 0.707 0.707 L 0.454 0.891 L 0.156 0.988 L -0.156 0.988 L -0.454 0.891 L -0.707 0.707 L -0.891 0.454 L -0.988 0.156 L -0.988 -0.156 L -0.891 -0.454 L -0.707 -0.707 L -0.454 -0.891 L -0.156 -0.988 L 0.156 -0.988 L 0.454 -0.891 L 0.707 -0.707 L 0.891 -0.454 L 0.988 -0.156 L 0.949 0" + - "L 0.988 0.156 L 0.891 0.256 L 0.891 0.454 L 0.739 0.537 L 0.707 0.707 L 0.519 0.769 L 0.454 0.891 L 0.293 0.902 L 0.156 0.988 L 0.032 0.927 L -0.156 0.988 L -0.282 0.869 L -0.454 0.891 L -0.571 0.731 L -0.707 0.707 L -0.768 0.558 L -0.891 0.454 L -0.871 0.317 L -0.988 0.156 L -0.914 0 L -0.988 -0.156 L -0.871 -0.317 L -0.891 -0.454 L -0.768 -0.558 L -0.707 -0.707 L -0.571 -0.731 L -0.454 -0.891 L -0.282 -0.869 L -0.156 -0.988 L 0.032 -0.927 L 0.156 -0.988 L 0.293 -0.902 L 0.454 -0.891 L 0.519 -0.769 L 0.707 -0.707 L 0.739 -0.537 L 0.891 -0.454 L 0.891 -0.256 L 0.988 -0.156 L 0.949 0" + - "L 0.891 0.256 L 0.739 0.537 L 0.519 0.769 L 0.293 0.902 L 0.032 0.927 L -0.282 0.869 L -0.571 0.731 L -0.768 0.558 L -0.871 0.317 L -0.914 0 L -0.871 -0.317 L -0.768 -0.558 L -0.571 -0.731 L -0.282 -0.869 L 0.032 -0.927 L 0.293 -0.902 L 0.519 -0.769 L 0.739 -0.537 L 0.891 -0.256 L 0.949 0" + - "M 0.834 0 L 0.891 0.256 L 0.704 0.291 L 0.739 0.537 L 0.495 0.579 L 0.519 0.769 L 0.258 0.793 L 0.032 0.927 L -0.06 0.759 L -0.282 0.869 L -0.398 0.649 L -0.571 0.731 L -0.674 0.49 L -0.871 0.317 L -0.741 0.178 L -0.914 0 L -0.741 -0.178 L -0.871 -0.317 L -0.674 -0.49 L -0.571 -0.731 L -0.398 -0.649 L -0.282 -0.869 L -0.06 -0.759 L 0.032 -0.927 L 0.258 -0.793 L 0.519 -0.769 L 0.495 -0.579 L 0.739 -0.537 L 0.704 -0.291 L 0.891 -0.256 L 0.834 0" + - "L 0.704 0.291 L 0.495 0.579 L 0.258 0.793 L -0.06 0.759 L -0.398 0.649 L -0.674 0.49 L -0.741 0.178 L -0.741 -0.178 L -0.674 -0.49 L -0.398 -0.649 L -0.06 -0.759 L 0.258 -0.793 L 0.495 -0.579 L 0.704 -0.291 L 0.834 0" + - "M 0.592 0 L 0.704 0.291 L 0.413 0.3 L 0.495 0.579 L 0.183 0.563 L -0.06 0.759 L -0.158 0.485 L -0.398 0.649 L -0.479 0.348 L -0.741 0.178 L -0.51 0 L -0.741 -0.178 L -0.479 -0.348 L -0.398 -0.649 L -0.158 -0.485 L -0.06 -0.759 L 0.183 -0.563 L 0.495 -0.579 L 0.413 -0.3 L 0.704 -0.291 L 0.592 0" + - "L 0.413 0.3 L 0.183 0.563 L -0.158 0.485 L -0.479 0.348 L -0.51 0 L -0.479 -0.348 L -0.158 -0.485 L 0.183 -0.563 L 0.413 -0.3 L 0.592 0" + - "M 0.292 0 L 0.413 0.3 L 0.09 0.277 L -0.158 0.485 L -0.236 0.171 L -0.51 0 L -0.236 -0.171 L -0.158 -0.485 L 0.09 -0.277 L 0.413 -0.3 L 0.292 0 L 0.09 0.277" + - "L -0.236 0.171 L -0.236 -0.171 L 0.09 -0.277 L 0.292 0 M 0 0 L 0.949 0" + - "M 0 0 L 0.293 0.902 M 0 0 L -0.768 0.558 M 0 0 L -0.768 -0.558 M 0 0 L 0.293 -0.902", -} -Class.frostAuraSymbol = { - PARENT: "genericTank", - CONTROLLERS: [["spin", { speed: -0.04 }]], - INDEPENDENT: true, - BORDERLESS: true, - COLOR: 'teal', - SHAPE: "M 1 0 L 0.797 0.46 L 0.5 0.866 L 0 0.92 L -0.5 0.866 L -0.797 0.46 L -1 0 L -0.797 -0.46 L -0.5 -0.866 L 0 -0.92 L 0.5 -0.866 L 0.797 -0.46 L 1 0 Z", - TURRETS: [{ - POSITION: [20, 0, 0, 0, 0, 1], - TYPE: 'frostAuraSymbolOutline' - }] -} -Class.frostAuraSymbolOutline = { - PARENT: "genericTank", - MIRROR_MASTER_ANGLE: true, - DRAW_FILL: false, - SHAPE: "M 1 0 L 0.797 0.46 L 0.5 0.866 L 0 0.92 L -0.5 0.866 L -0.797 0.46 L -1 0 L -0.797 -0.46 L -0.5 -0.866 L 0 -0.92 L 0.5 -0.866 L 0.797 -0.46 L 1 0 Z" + - "M 0.52 0.3 L 0.52 -0.3 L 0.797 -0.46 M 0.52 -0.3 L 0 -0.6 L 0 -0.92 M 0 -0.6 L -0.52 -0.3 L -0.797 -0.46 M -0.52 -0.3 L -0.52 0.3 L -0.797 0.46 M -0.52 0.3 L 0 0.6 L 0 0.92 M 0 0.6 L 0.52 0.3 L 0.797 0.46" -} - -function addIcosphereAura(damageFactor = 1, sizeFactor = 1, opacity = 0.3, auraSize = "Medium") { - let auraType = "frostAura" + auraSize; - return { - PARENT: "genericTank", - INDEPENDENT: true, - LABEL: "", - COLOR: 17, - GUNS: [ - { - POSITION: [0, 20, 1, 0, 0, 0, 0,], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.aura, { size: sizeFactor, damage: damageFactor }]), - TYPE: [auraType, {ALPHA: opacity}], - MAX_CHILDREN: 1, - AUTOFIRE: true, - SYNCS_SKILLS: true, - }, - }, - ], - TURRETS: [ - { - POSITION: [20, 0, 0, 0, 360, 1], - TYPE: "frostAuraSymbol" - }, - ] - }; -} -Class.frostAuraBlockTop = { - SHAPE: "M -1.3 -0.15 L -1.3 0.15 L -0.3 0.3 L -0.15 1.3 L 0.15 1.3 L 0.3 0.3 L 1.3 0.15 L 1.3 -0.15 L 0.3 -0.3 L 0.15 -1.3 L -0.15 -1.3 L -0.3 -0.3 Z", - COLOR: { BASE: 17, BRIGHTNESS_SHIFT: 5 }, - MIRROR_MASTER_ANGLE: true, -} -Class.frostAuraBlockTurret = { - PARENT: "genericTank", - INDEPENDENT: true, - COLOR: 17, - CONTROLLERS: ["nearestDifferentMaster"], - LABEL: "", - BODY: { - FOV: 2, - }, - HAS_NO_RECOIL: true, - GUNS: [ - { - POSITION: [18, 15, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.minionGun, g.turret, g.power, g.autoTurret, g.fake]), - TYPE: "bullet", - COLOR: {BASE: 17, BRIGHTNESS_SHIFT: -7.5} - }, - }, { - POSITION: [23, 11, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.minionGun, g.turret, g.power, g.autoTurret, {density: 0.2}]), - TYPE: "bullet", - COLOR: {BASE: -1, BRIGHTNESS_SHIFT: -10, SATURATION_SHIFT: 0.6} - }, - }, { - POSITION: [15, 13, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.minionGun, g.turret, g.power, g.autoTurret, g.fake]), - TYPE: "bullet", - COLOR: {BASE: 17, BRIGHTNESS_SHIFT: 7.5} - }, - }, - ], -} -Class.frostAuraBlockAura = addIcosphereAura(0.25, 1.6, 0.15, "Small"); -Class.frostAuraBlock = { - PARENT: 'unsetTrap', - TURRETS: [ - { - POSITION: [20, 0, 0, 45, 0, 1], - TYPE: 'frostAuraBlockTop' - }, { - POSITION: [11, 0, 0, 0, 360, 1], - TYPE: 'frostAuraBlockTurret' - }, { - POSITION: [10, 0, 0, 0, 360, 1], - TYPE: 'frostAuraBlockAura' - } - ] -} -Class.frostBossBigAura = addIcosphereAura(1.5, 1.45, 0.3, "Large"); - -Class.frostBossAutoTurret = { - PARENT: "autoTankGun", - INDEPENDENT: true, - COLOR: 17, - GUNS: [ - { - POSITION: [17, 14, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.autoTurret, {recoil: 0.1}, g.fake]), - TYPE: "bullet", - COLOR: {BASE: 17, BRIGHTNESS_SHIFT: -7.5} - }, - }, { - POSITION: [22, 10, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.autoTurret, {recoil: 0.1}]), - TYPE: "bullet", - COLOR: {BASE: -1, BRIGHTNESS_SHIFT: -10, SATURATION_SHIFT: 0.6} - }, - }, { - POSITION: [14, 12, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.autoTurret, {recoil: 0.1}, g.fake]), - TYPE: "bullet", - COLOR: {BASE: 17, BRIGHTNESS_SHIFT: 7.5} - }, - }, - ], - TURRETS: [ - { - POSITION: [13, 0, 0, 0, 0, 1], - TYPE: ["egg", {COLOR: -1, BORDERLESS: true}], - }, - ], -} - -Class.frostBossBaseDeco = { - SHAPE: "M -1.1 0 L -0.956 0.292 L -0.669 0.205 L -0.669 -0.205 L -0.956 -0.292 Z" + - "M -0.55 0.952 L -0.225 0.974 L -0.157 0.682 L -0.512 0.477 L -0.731 0.682 Z" + - "M -0.55 -0.952 L -0.225 -0.974 L -0.157 -0.682 L -0.512 -0.477 L -0.731 -0.682 Z" + - "M 0.55 0.952 L 0.225 0.974 L 0.157 0.682 L 0.512 0.477 L 0.731 0.682 Z" + - "M 0.55 -0.952 L 0.225 -0.974 L 0.157 -0.682 L 0.512 -0.477 L 0.731 -0.682 Z" + - "M 1.1 0 L 0.956 0.292 L 0.669 0.205 L 0.669 -0.205 L 0.956 -0.292 Z", - COLOR: { BASE: 17, BRIGHTNESS_SHIFT: 2.5 }, - MIRROR_MASTER_ANGLE: true, - GUNS: Array(6).fill().flatMap((_, i) => ([ - { - POSITION: [1.75, 3, -0.75, 7.5, 0, 60 * i, 0], - PROPERTIES: { COLOR: { BASE: -1, BRIGHTNESS_SHIFT: 2.5, SATURATION_SHIFT: 0.9 }, DRAW_ABOVE: true }, - }, { - POSITION: [1, 9, 0, 8.5, 0, 60 * i + 30, 0], - PROPERTIES: { COLOR: { BASE: -1, BRIGHTNESS_SHIFT: 10, SATURATION_SHIFT: 1.15 } }, - }, - ])) -} - -const trebuchetStats = [g.basic, g.sniper, g.predator, g.predator, g.predator, g.predator, {speed: 0.93, maxSpeed: 0.93, reload: 1.7, health: 1.7, damage: 1.4, size: 2}]; -const hielamanStats = [g.trap, g.setTrap, g.hexaTrapper, {reload: 2.4, health: 3.2, range: 1.2}]; -Class.frostBoss = { - PARENT: 'miniboss', - LABEL: 'Extrasolar', - NAME: 'Frostbyte', - FACING_TYPE: 'toTarget', - SHAPE: 6, - COLOR: "aqua", - UPGRADE_COLOR: "aqua", - SIZE: 31, - DANGER: 12, - VALUE: 888888, - UPGRADE_TOOLTIP: "\"When the golden rays of sun shine through this world's\n" + - "darkened skies and looming clouds, the legend of the warrior\n" + - "and his eternal blade will finally come to fruition.\"", - BODY: { - SPEED: base.SPEED * 0.6, - HEALTH: base.HEALTH * 11, - SHIELD: base.SHIELD * 7, - REGEN: base.REGEN * 2.5, - FOV: base.FOV * 1.4, - RESIST: base.RESIST * 1.2, - DENSITY: base.DENSITY * 7.5, - }, - GUNS: [ - ...Array(6).fill().flatMap((_, i) => ({ - // Speed - POSITION: [8, 14.5, 0.001, 9.5, 0, 60*i, 0], - PROPERTIES: {COLOR: 9}, - })), - ...Array(3).fill().flatMap((_, i) => ([ - { // Heavy Snipers - POSITION: [26.5, 9.5, 1, 0, 0, 120 * i, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats(trebuchetStats), - TYPE: "bullet", - COLOR: { BASE: -1, BRIGHTNESS_SHIFT: -15, SATURATION_SHIFT: 0.6 }, - }, - }, { - POSITION: [24, 6.65, -1.3, 0, 0, 120 * i, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([...trebuchetStats, g.fake]), - TYPE: "bullet", - COLOR: { BASE: -1, BRIGHTNESS_SHIFT: -5, SATURATION_SHIFT: 0.6 }, - BORDERLESS: true - }, - }, { - POSITION: [19.5, 3.8, -1.4, 0, 0, 120 * i, 0], - PROPERTIES: { COLOR: { BASE: 17, BRIGHTNESS_SHIFT: 10 } }, - }, { - POSITION: [4, 11.5, 1, 19.5, 0, 120 * i, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([...trebuchetStats, g.fake]), - TYPE: "bullet", - COLOR: { BASE: -1, BRIGHTNESS_SHIFT: -5, SATURATION_SHIFT: 0.6 }, - }, - }, { - POSITION: [2, 12, 1, 20.5, 0, 120 * i, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([...trebuchetStats, g.fake]), - TYPE: "bullet", - COLOR: { BASE: 17, BRIGHTNESS_SHIFT: 2.5 }, - }, - }, - { // Aura Blocks - POSITION: [15, 9, 1, 0, 0, 120 * i + 60, 0], - PROPERTIES: {COLOR: {BASE: -1, BRIGHTNESS_SHIFT: -15, SATURATION_SHIFT: 0.6}} - }, { - POSITION: [4, 7.5, -1.6, 9, 0, 120 * i + 60, 0], - PROPERTIES: {COLOR: {BASE: 17, BRIGHTNESS_SHIFT: 7.5}} - }, { - POSITION: [15, 5.4, -0.1, 0, 0, 120 * i + 60, 0], - PROPERTIES: {COLOR: {BASE: -1, BRIGHTNESS_SHIFT: -5, SATURATION_SHIFT: 0.75}} - }, { - POSITION: [3, 9, 1.6, 15, 0, 120 * i + 60, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats(hielamanStats), - TYPE: 'frostAuraBlock', - STAT_CALCULATOR: gunCalcNames.trap, - COLOR: {BASE: -1, BRIGHTNESS_SHIFT: -15, SATURATION_SHIFT: 0.6} - }, - }, { - POSITION: [2, 7, 1.6, 16, 0, 120 * i + 60, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([...hielamanStats, g.fake]), - TYPE: 'bullet', - COLOR: {BASE: 17, BRIGHTNESS_SHIFT: 7.5} - }, - }, - ])), - ], - TURRETS: [ - ...Array(6).fill().flatMap((_, i) => ([ - { - POSITION: [2.95, 8.55, 0, 60 * i + 30, 180, 2], - TYPE: "frostBossAutoTurret", - }, - ])), - { - POSITION: [8.55, 0, 0, 0, 360, 2], - TYPE: "frostBossBigAura", - }, - ], - PROPS: [ - { - POSITION: [12, 0, 0, 180, 1], - TYPE: ["hexagon", {COLOR: {BASE: -1, BRIGHTNESS_SHIFT: 7.5}}], - }, { - POSITION: [20, 0, 0, 0, 1], - TYPE: ["frostBossBaseDeco"], - }, - ] -} - -const divide = 1000; -const arraySize = 10; -const colorArray = []; -const damageMultiplayer = 3.5; -const reloadMultiplayer = 2; -for (let i = 0; i < arraySize; i++) { - const rgb = Math.round(255 * i / (arraySize - 1)); - colorArray.push('#' + ((1 << 24) + (rgb << 16) + (rgb << 8) + rgb).toString(16).slice(1)); -} -class io_nearestDifferentMaster2 extends ioTypes.nearestDifferentMaster { - constructor(body, opts = {}) { - super(body); - this.lookAtDanger = opts.lookAtDanger ?? true; - this.firingAtMe = opts.firingAtMe ?? false; - this.timeout = opts.timeout || 90; - } - buildList(range) { - // Establish whom we judge in reference to - let mostDangerous = 0, - keepTarget = false; - // Filter through everybody... - let out = entities.filter(e => - // Only look at those within our view, and our parent's view, not dead, not invisible, not our kind, not a bullet/trap/block etc - this.validate(e, this.body, this.body.master.master, range * range, range * range * 4 / 3) - ).filter((e) => { - // Only look at those within range and arc (more expensive, so we only do it on the few) - if (this.body.firingArc == null || this.body.aiSettings.view360 || Math.abs(util.angleDifference(util.getDirection(this.body, e), this.body.firingArc[0])) < this.body.firingArc[1]) { - mostDangerous = Math.max(e.dangerValue, mostDangerous); - return true; - } - }).filter((e) => { - // Even more expensive - return !this.wouldHitWall(this.body, e); - }).filter((e) => { - // Only return the highest tier of danger - if (!this.lookAtDanger) return true; - if (this.body.aiSettings.farm || e.dangerValue === mostDangerous) { - if (this.targetLock && e.id === this.targetLock.id) keepTarget = true; - return true; - } - }); - // Reset target if it's not in there - if (!keepTarget) this.targetLock = undefined; - return out; - } - think(input) { - // Override target lock upon other commands - if (input.main || input.alt || this.body.master.autoOverride) { - this.targetLock = undefined; - return {}; - } - // Otherwise, consider how fast we can either move to ram it or shoot at a potiential target. - let tracking = this.body.topSpeed, - damageRef = (this.body.bond == null) ? this.body : this.body.bond, - range = this.body.fov; - // Use whether we have functional guns to decide - for (let i = 0; i < this.body.guns.length; i++) { - if (this.body.guns[i].canShoot && !this.body.aiSettings.SKYNET) { - let v = this.body.guns[i].getTracking(); - if (v.speed == 0 || v.range == 0) continue; - tracking = v.speed; - range = Math.min(range, (v.speed || 1.5) * (v.range < (this.body.size * 2) ? this.body.fov : v.range)); - break; - } - } - if (!Number.isFinite(tracking)) { - tracking = this.body.topSpeed + .01; - } - if (!Number.isFinite(range)) { - range = 640 * this.body.FOV; - } - // Check if my target's alive - if (this.targetLock && ( - !this.validate(this.targetLock, this.body, this.body.master.master, range * range, range * range * 4 / 3) || - this.wouldHitWall(this.body, this.targetLock) // Very expensive - )) { - this.targetLock = undefined; - this.tick = 100; - } - // Think damn hard - if (this.tick++ > 15 * c.runSpeed) { - this.tick = 0; - this.validTargets = this.buildList(range); - // Ditch our old target if it's invalid - if (this.targetLock && this.validTargets.indexOf(this.targetLock) === -1) { - this.targetLock = undefined; - } - // Lock new target if we still don't have one. - if (this.targetLock == null && this.validTargets.length) { - this.targetLock = (this.validTargets.length === 1) ? this.validTargets[0] : nearest(this.validTargets, { - x: this.body.x, - y: this.body.y - }); - this.tick = -this.timeout; - } - } - // Lock onto whoever's shooting me. - if (this.firingAtMe && damageRef.collisionArray.length && damageRef.health.display() < this.oldHealth) { - this.oldHealth = damageRef.health.display(); - if (this.validTargets.indexOf(damageRef.collisionArray[0]) === -1) { - let a = (damageRef.collisionArray[0].master.id === -1) - ? damageRef.collisionArray[0].source - : damageRef.collisionArray[0].master; - if ( - this.body.firingArc == null || - this.body.aiSettings.view360 || - Math.abs(util.angleDifference(util.getDirection(this.body, a), this.body.firingArc[0])) < this.body.firingArc[1] - ) { - this.targetLock = a; - this.tick = -(this.timeout * 5); - } - } - } - // Consider how fast it's moving and shoot at it - if (this.targetLock != null) { - let radial = this.targetLock.velocity; - let diff = { - x: this.targetLock.x - this.body.x, - y: this.targetLock.y - this.body.y, - } - /// Refresh lead time - if (this.tick % 4 === 0) { - this.lead = 0 - // Find lead time (or don't) - if (!this.body.aiSettings.chase) { - let toi = timeOfImpact(diff, radial, tracking) - this.lead = toi - } - } - if (!Number.isFinite(this.lead)) { - this.lead = 0; - } - if (!this.accountForMovement) this.lead = 0; - // And return our aim - return { - target: { - x: diff.x + this.lead * radial.x, - y: diff.y + this.lead * radial.y, - }, - fire: true, - main: true - }; - } - return {}; - } -} -ioTypes.nearestDifferentMaster2 = io_nearestDifferentMaster2; -Class.toothlessBase = { - PARENT: "genericTank", - LABEL: "NightFury", - UPGRADE_TOOLTIP: "A power league...", - GLOW: { - RADIUS: 2, - COLOR: 42, - ALPHA: 0.6, - RECURSION: 6, - }, - BODY: { - SPEED: 0.8 * base.SPEED, - FOV: 1.5 * base.FOV, - HEALTH: 6 * base.HEALTH, - DAMAGE: 2 * base.DAMAGE, - }, - LEVEL_CAP: 45, - EXTRA_SKILL: 78, // 120 - 42 - SHAPE: 3, - VALUE: 30e+3, - SIZE: 24, - COLOR: "purple", - SKILL_CAP: Array(10).fill(smshskl + 3), - LEVEL_SKILL_POINT_FUNCTION: level => { - if (level < 2) return 0; - if (level <= 40) return 1; - if (level <= 45 && level & 1 == 1) return 1; - return 0; - }, -} -Class.toothlessBossTurret = { - PARENT: "genericTank", - LABEL: "", - BODY: { - FOV: 2, - }, - CONTROLLERS: [ - "onlyAcceptInArc", - [ "nearestDifferentMaster2", { lookAtDanger: false, firingAtMe: true, timeout: 10 } ], - ], - COLOR: "grey", - GUNS: [ - { - POSITION: [32, 8, 1, 0, 0, 0, 0.4], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.assassin, { - pen: 0.8, - health: 0.6, - damage: 0.6, - recoil: 0, - }]), - TYPE: "bullet", - }, - }, - ], - ON: [{ - event: "fire", - handler: ({ body }) => { - const master = body.master; - body._damage ??= []; - body._reload ??= []; - - if (!body._loaded) { - let _temp = 0; - master._maxPower ??= 0; - - body.guns.forEach((gun, i) => { - body._damage[i] = gun.settings.damage; - body._reload[i] = gun.settings.reload; - - _temp += (body._damage[i] * 3) / body._damage[i]; - _temp += body._reload[i] / (body._reload[i] / 3); - _temp /= 2; - }); - - _temp /= body.guns.length; - - master._maxPower += (_temp - 1) * divide * 2; - if (master._maxPower > _temp) master._maxPower /= 2; - - body._loaded = true; - } - - if (master._mode) { - master._power -= 1; - if (master._power < 1) { - master._mode = 0; - master.color.base = 14; - } - } - - if (!master._oldPower) return; - const power = master._oldPower / (divide * 2) + 1; - - body.guns.forEach((gun, i) => { - let _1 = body._damage[i] * (master._mode ? power : 1); - let _2 = body._reload[i] / (master._mode ? power : 1); - let max_damage = body._damage[i] * damageMultiplayer; - let min_reload = body._reload[i] / reloadMultiplayer; - - gun.settings.damage = _1 > max_damage ? max_damage : _1; - gun.settings.reload = _2 < min_reload ? min_reload : _2; - }); - }, - }], -}; -Class.toothlessBossDeco = { - PARENT: "genericTank", - LABEL: "", - SHAPE: 3, - SIZE: 10, - ON: [{ - event: "tick", - handler: ({ body }) => { - const master = body.master; - if (master._maxPower) - body.color.base = colorArray[ - Math.floor(master._power / (master._maxPower / arraySize)) > arraySize - 1 - ? arraySize - 1 - : Math.floor(master._power / (master._maxPower / arraySize) - ) - ]; - }, - }], -}; -Class.toothlessBoss = { - PARENT: "toothlessBase", - UPGRADE_COLOR: "magenta", - TURRETS: [{ - POSITION: { SIZE: 15, LAYER: 1 }, - TYPE: ["toothlessBossDeco", { MIRROR_MASTER_ANGLE: true }], - }, { - POSITION: { SIZE: 23 }, - TYPE: ["triangle", { COLOR: "black", MIRROR_MASTER_ANGLE: true }], - }], - GUNS: [{ - POSITION: { LENGTH: 0, WIDTH: 0 }, - PROPERTIES: { - SHOOT_SETTINGS: combineStats([ g.basic, { - range: 0.1, - speed: 0.1, - maxSpeed: 0.1, - recoil: 0, - }]), - TYPE: "bullet", - ALT_FIRE: true, - }, - }], - ON: [{ - event: "altFire", - handler: ({ body }) => { - if (!body._power || body._mode) return; - const power = Math.floor(body._power); - - if (power >= 1) { - body.sendMessage(`Your power level ${power}`); - body._oldPower = body._power; - body._mode = 1; - body.color.base = 5; - } - }, - }, { - event: "kill", - handler: ({ body, entity }) => { - body._power ??= 0; - body._mode ??= 0; - if (!body._mode) body._power += (entity.skill.score / divide) ** 0.8; - }, - }], -} -for (let b = 0; b < 3; b++) - Class.toothlessBoss.TURRETS.push({ - POSITION: [8, 6, -5.6, 120 * b + 180, 180, 0], - TYPE: "toothlessBossTurret", - }, { - POSITION: [8, 6, 5.6, 120 * b + 180, 180, 0], - TYPE: "toothlessBossTurret", - }); +const { combineStats, skillSet, makeAuto, addAura, LayeredBoss, makeDeco, weaponArray, setTurretProjectileRecoil } = require('../facilitators.js'); +const { base, smshskl } = require('../constants.js'); +const g = require('../gunvals.js'); +require('./generics.js'); +require('./tanks.js'); +require('./turrets.js'); + +Class.miniboss = { + PARENT: "genericBoss", + CONTROLLERS: ["nearestDifferentMaster", "minion", "canRepel"], + AI: { NO_LEAD: true }, +} +Class.ramMiniboss = { + PARENT: "genericBoss", + CONTROLLERS: ["nearestDifferentMaster", "canRepel", "mapTargetToGoal"], +} + +// ELITE CRASHERS +Class.elite = { + PARENT: "miniboss", + LABEL: "Elite Crasher", + COLOR: "pink", + SHAPE: 3, + SIZE: 27, + VALUE: 15e4, + BODY: { + FOV: 1.25, + SPEED: 0.15 * base.SPEED, + HEALTH: 7 * base.HEALTH, + DAMAGE: 2.5 * base.DAMAGE, + REGEN: 0.5 * base.REGEN, + }, +} +Class.eliteDestroyer = { + PARENT: "elite", + UPGRADE_LABEL: "Elite Destroyer", + UPGRADE_COLOR: "pink", + GUNS: weaponArray({ + POSITION: [5, 16, 1, 6, 0, 60, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.pounder, g.destroyer]), + TYPE: "bullet", + LABEL: "Devastator", + }, + }, 3), + TURRETS: [ + ...weaponArray({ + POSITION: [11, 0, 0, 60, 360, 0], + TYPE: "crasherSpawner", + }, 3), + { + POSITION: [11, 0, 0, 0, 360, 1], + TYPE: [ "bigauto4gun", { INDEPENDENT: true, COLOR: -1 } ], + }, + ], +} +Class.eliteGunner = { + PARENT: "elite", + UPGRADE_LABEL: "Elite Gunner", + UPGRADE_COLOR: "pink", + FACING_TYPE: "toTarget", + AI: { NO_LEAD: false }, + GUNS: [ + { + POSITION: [14, 16, 1, 0, 0, 180, 0], + }, { + POSITION: [4, 16, 1.5, 14, 0, 180, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, g.setTrap, g.pounder, {speed: 1.5, range: 0.3}]), + TYPE: "unsetPillbox", + STAT_CALCULATOR: "trap", + }, + }, { + POSITION: [6, 14, -2, 2, 0, 60, 0], + }, { + POSITION: [6, 14, -2, 2, 0, 300, 0], + }, + ], + TURRETS: [ + { + POSITION: [14, 8, 0, 60, 180, 0], + TYPE: "auto4gun", + }, { + POSITION: [14, 8, 0, 300, 180, 0], + TYPE: "auto4gun", + }, + ], +} +Class.eliteSprayer = { + PARENT: "elite", + UPGRADE_LABEL: "Elite Sprayer", + UPGRADE_COLOR: "pink", + SKILL: [0, 9, 3, 9, 2, 9, 9, 9, 9, 0], + AI: { NO_LEAD: false }, + HAS_NO_RECOIL: true, + TURRETS: [ + { + POSITION: [6, 0, 0, 0, 360, 1], + TYPE: ["machineTripleTurret", { INDEPENDENT: true }], + }, + ...weaponArray([ + { + POSITION: [9, 6, -5, 60, 130, 0], + TYPE: ["sprayer", { COLOR: "grey", GUN_STAT_SCALE: {damage: 0.9, resist: 0.95} }], + }, { + POSITION: [9, 6, 5, 60, 130, 0], + TYPE: ["sprayer", { COLOR: "grey", GUN_STAT_SCALE: {damage: 0.9, resist: 0.95} }], + }, + ], 3) + ], +} +Class.eliteBattleship = { + PARENT: "elite", + UPGRADE_LABEL: "Elite Battleship", + UPGRADE_COLOR: "pink", + GUNS: weaponArray([ + { + POSITION: [4, 6, 0.6, 7, -8, 60, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.swarm, g.battleship, {speed: 0.95, maxSpeed: 0.95, health: 1.1, resist: 1.05}]), + TYPE: "autoswarm", + STAT_CALCULATOR: "swarm", + }, + }, { + POSITION: [4, 6, 0.6, 7, 0, 60, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.swarm, g.battleship, {speed: 0.95, maxSpeed: 0.95, health: 1.1, resist: 1.05}]), + TYPE: "autoswarm", + STAT_CALCULATOR: "swarm", + }, + }, { + POSITION: [4, 6, 0.6, 7, 8, 60, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.swarm, g.battleship, {speed: 0.95, maxSpeed: 0.95, health: 1.1, resist: 1.05}]), + TYPE: "autoswarm", + STAT_CALCULATOR: "swarm", + }, + }, + ], 3), + TURRETS: weaponArray({ + POSITION: [5, 7, 0, 0, 360, 1], + TYPE: [ "autoTankGun", { INDEPENDENT: true, COLOR: -1 } ], + }, 3) +} +Class.eliteSpawner = { + PARENT: "elite", + UPGRADE_LABEL: "Elite Spawner", + UPGRADE_COLOR: "pink", + MAX_CHILDREN: 9, + AI: { STRAFE: false }, + GUNS: [ + { + POSITION: [11, 16, 1, 0, 0, 60, 0], + }, { + POSITION: [11, 16, 1, 0, 0, 180, 0], + }, { + POSITION: [11, 16, 1, 0, 0, 300, 0], + }, { + POSITION: [2, 18, 1, 11, 0, 60, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, {reload: 2, size: 0.5, speed: 0.6, maxSpeed: 0.6, heath: 1.35}]), + TYPE: "sentrySwarmMinion", + SYNCS_SKILLS: true, + AUTOFIRE: true, + STAT_CALCULATOR: "drone", + }, + }, { + POSITION: [2, 18, 1, 11, 0, 180, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, {reload: 2, size: 0.5, speed: 0.6, maxSpeed: 0.6, heath: 1.35}]), + TYPE: "sentryTrapMinion", + SYNCS_SKILLS: true, + AUTOFIRE: true, + STAT_CALCULATOR: "drone", + }, + }, { + POSITION: [2, 18, 1, 11, 0, 300, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, {reload: 2, size: 0.5, speed: 0.6, maxSpeed: 0.6, heath: 1.35}]), + TYPE: "sentryGunMinion", + SYNCS_SKILLS: true, + AUTOFIRE: true, + STAT_CALCULATOR: "drone", + }, + }, + ], + TURRETS: [ + { + POSITION: [11, 0, 0, 0, 360, 1], + TYPE: ["auto4gun", { INDEPENDENT: false, COLOR: -1 }], + }, + ], +} +Class.eliteTrapGuard = { + PARENT: "elite", + UPGRADE_LABEL: "Elite Trap Guard", + UPGRADE_COLOR: "pink", + AI: { STRAFE: false }, + GUNS: weaponArray([ + { + POSITION: [10.5, 6, 1, 0, 0, 60, 0], + }, { + POSITION: [3, 6, 1.7, 10.5, 0, 60, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, {speed: 1.1, maxSpeed: 1.1, reload: 1.5, damage: 1.6}]), + TYPE: "trap", + STAT_CALCULATOR: "trap", + }, + }, + ], 3), + TURRETS: [ + { + POSITION: [9.5, 0, 0, 0, 360, 1], + TYPE: "triTrapGuardTurret", + }, + ...weaponArray([ + { + POSITION: [5, 8, -7, 60, 160, 0], + TYPE: ["autoTurret", { INDEPENDENT: false, GUN_STAT_SCALE: {health: 1.1} }], + }, { + POSITION: [5, 8, 7, 60, 160, 0], + TYPE: ["autoTurret", { INDEPENDENT: false, GUN_STAT_SCALE: {health: 1.1} }], + }, + ], 3) + ], +} +Class.eliteSpinner = { + PARENT: "elite", + UPGRADE_LABEL: "Elite Spinner", + UPGRADE_COLOR: "pink", + AI: { STRAFE: false }, + FACING_TYPE: ["spin", {speed: 0.08}], + GUNS: weaponArray([ + { + POSITION: [9.5, 2, 1, -1.5, 11.5, 10, 2/3], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.gunner, { speed: 1.5, maxSpeed: 1.25 }]), + TYPE: "bullet", + }, + }, { + POSITION: [9.5, 2, 1, 3.5, 6.5, 10, 1/3], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.gunner, { speed: 1.5, maxSpeed: 1.25 }]), + TYPE: "bullet", + }, + }, { + POSITION: [9.5, 2, 1, 8.5, 1.5, 10, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.gunner, { speed: 1.5, maxSpeed: 1.25 }]), + TYPE: "bullet", + }, + }, { + POSITION: [2, 20, 0.75, 8, 0, 60, 0], + }, + ], 3), + TURRETS: [ + { + POSITION: [9.5, 0, 0, 0, 360, 1], + TYPE: ["eliteSpinnerCyclone", {COLOR: -1}], + }, + ], +} + +// OLD ELITE +Class.oldEliteSprayer = { + PARENT: "elite", + UPGRADE_LABEL: "Elite Sprayer (Old)", + UPGRADE_COLOR: "pink", + AI: { NO_LEAD: false }, + TURRETS: weaponArray({ + POSITION: [14, 6, 0, 60, 190, 0], + TYPE: [ "sprayer", { COLOR: -1 } ], + }, 3) +}; + +// Legions +Class.destroyerLegion = { + PARENT: "elite", + UPGRADE_LABEL: "Destroyer Legion", + UPGRADE_COLOR: "pink", + AI: { NO_LEAD: false }, + SIZE: 30, + BODY: { + HEALTH: 8 * base.HEALTH, + }, + GUNS: weaponArray({ + POSITION: [5, 16, 1, 6, 0, 60, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.pounder, g.destroyer, {health: 1.1}]), + TYPE: "bullet", + LABEL: "Devastator", + }, + }, 3), + TURRETS: [ + ...weaponArray({ + POSITION: [11, 0, 0, 60, 360, 0], + TYPE: ["crasherSpawner", {GUN_STAT_SCALE: {health: 1.1}}], + }, 3), + { + POSITION: [11, 0, 0, 0, 360, 1], + TYPE: [ "bigauto4gun", { GUN_STAT_SCALE: {health: 1.1}, INDEPENDENT: true, COLOR: -1 } ], + }, + ], +} +Class.gunnerLegion = { + PARENT: "elite", + UPGRADE_LABEL: "Gunner Legion", + UPGRADE_COLOR: "pink", + FACING_TYPE: "toTarget", + AI: { NO_LEAD: false }, + SIZE: 30, + BODY: { + HEALTH: 8 * base.HEALTH, + }, + GUNS: [ + { + POSITION: [14, 16, 1, 0, 0, 180, 0], + }, { + POSITION: [4, 16, 1.5, 14, 0, 180, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, g.setTrap, g.pounder, {health: 1.1, speed: 1.5, range: 0.3}]), + TYPE: "unsetPillbox", + STAT_CALCULATOR: "trap", + }, + }, { + POSITION: [6, 14, -2, 2, 0, 60, 0], + }, { + POSITION: [6, 14, -2, 2, 0, 300, 0], + }, + ], + TURRETS: [ + { + POSITION: [14, 8, 0, 60, 180, 0], + TYPE: ["auto4gun", {GUN_STAT_SCALE: {health: 1.15}}], + }, { + POSITION: [14, 8, 0, 300, 180, 0], + TYPE: ["auto4gun", {GUN_STAT_SCALE: {health: 1.15}}], + }, + ], +} +Class.sprayerLegion = { + PARENT: "elite", + UPGRADE_LABEL: "Sprayer Legion", + UPGRADE_COLOR: "pink", + AI: { NO_LEAD: false }, + SIZE: 30, + SKILL: [0, 9, 3, 9, 2, 9, 9, 9, 9, 0], + HAS_NO_RECOIL: true, + BODY: { + HEALTH: 8 * base.HEALTH, + }, + TURRETS: weaponArray({ + POSITION: [14, 6, 0, 60, 190, 0], + TYPE: ["machineGun", {GUN_STAT_SCALE: {health: 1.1, damage: 1.2, speed: 1.2, resist: 1.05}, COLOR: -1}], + }, 3) +} +Class.battleshipLegion = { + PARENT: "elite", + UPGRADE_LABEL: "Battleship Legion", + UPGRADE_COLOR: "pink", + AI: { NO_LEAD: false }, + SIZE: 30, + BODY: { + HEALTH: 8 * base.HEALTH, + }, + GUNS: weaponArray([ + { + POSITION: [4, 6, 0.6, 7, -8, 60, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.swarm, g.battleship, {speed: 1.05, maxSpeed: 1.05, health: 1.2, resist: 1.1}]), + TYPE: "autoswarm", + STAT_CALCULATOR: "swarm", + }, + }, { + POSITION: [4, 6, 0.6, 7, 0, 60, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.swarm, g.battleship, {speed: 1.05, maxSpeed: 1.05, health: 1.2, resist: 1.1}]), + TYPE: "autoswarm", + STAT_CALCULATOR: "swarm", + }, + }, { + POSITION: [4, 6, 0.6, 7, 8, 60, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.swarm, g.battleship, {speed: 1.05, maxSpeed: 1.05, health: 1.2, resist: 1.1}]), + TYPE: "autoswarm", + STAT_CALCULATOR: "swarm", + }, + }, + ], 3), + TURRETS: weaponArray({ + POSITION: [5, 7, 0, 0, 360, 1], + TYPE: [ "autoTankGun", { GUN_STAT_SCALE: {health: 1.1}, INDEPENDENT: true, COLOR: -1 } ], + }, 3) +} +Class.spawnerLegion = { + PARENT: "elite", + UPGRADE_LABEL: "Spawner Legion", + UPGRADE_COLOR: "pink", + AI: { NO_LEAD: false }, + SIZE: 30, + BODY: { + HEALTH: 8 * base.HEALTH, + }, + GUNS: [ + { + POSITION: [11, 16, 1, 0, 0, 60, 0], + }, { + POSITION: [11, 16, 1, 0, 0, 180, 0], + }, { + POSITION: [11, 16, 1, 0, 0, 300, 0], + }, { + POSITION: [2, 18, 1, 11, 0, 60, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, {reload: 2, size: 0.5, speed: 0.65, maxSpeed: 0.65, heath: 1.5}]), + TYPE: "sentrySwarmMinion", + SYNCS_SKILLS: true, + AUTOFIRE: true, + STAT_CALCULATOR: "drone", + }, + }, { + POSITION: [2, 18, 1, 11, 0, 180, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, {reload: 2, size: 0.5, speed: 0.65, maxSpeed: 0.65, heath: 1.5}]), + TYPE: "sentryTrapMinion", + SYNCS_SKILLS: true, + AUTOFIRE: true, + STAT_CALCULATOR: "drone", + }, + }, { + POSITION: [2, 18, 1, 11, 0, 300, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, {reload: 2, size: 0.5, speed: 0.65, maxSpeed: 0.65, heath: 1.5}]), + TYPE: "sentryGunMinion", + SYNCS_SKILLS: true, + AUTOFIRE: true, + STAT_CALCULATOR: "drone", + }, + }, + ], + TURRETS: [ + { + POSITION: [11, 0, 0, 0, 360, 1], + TYPE: ["auto4gun", { GUN_STAT_SCALE: {health: 1.15}, INDEPENDENT: false, COLOR: -1 }], + }, + ], +} + +// Legionary Crasher +Class.legionaryCrasherTop = { + PARENT: "elite", + AI: { STRAFE: false, NO_LEAD: false }, + CONTROLLERS: [ ["spin", { independent: true, speed: -0.005 }] ], + INDEPENDENT: true, + GUNS: weaponArray([ + { + POSITION: [4, 9.5, 0.7, 7, 5, 60, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.swarm, g.pounder, { speed: 2, maxSpeed: 1.7, size: 0.6, range: 2.8}]), + TYPE: [ "swarm", { INDEPENDENT: true } ], + STAT_CALCULATOR: "swarm", + AUTOFIRE: true, + + }, + }, { + POSITION: [4, 9.5, 0.7, 7, -5, 60, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.swarm, g.pounder, { speed: 2, maxSpeed: 1.7, size: 0.6, range: 2.8}]), + TYPE: [ "swarm", { INDEPENDENT: true } ], + STAT_CALCULATOR: "swarm", + AUTOFIRE: true, + }, + }, + ], 3), + TURRETS: weaponArray({ + POSITION: [9.5, 10, 0, 0, 190, 0], + TYPE: ["auto4gun", {GUN_STAT_SCALE: {damage: 1.4, health: 1.1, speed: 1.2, maxSpeed: 1.2, resist: 1.1, range: 1.3}}], + }, 3), +} +Class.legionaryCrasherSpawner = { + PARENT: 'genericTank', + SHAPE: "", + INDEPENDENT: true, + GUNS: [{ + POSITION: [0, 10, 0, 0, 0, 0, 10], + PROPERTIES: { + TYPE: 'destroyerLegion', + SHOOT_SETTINGS: combineStats([{reload: 0.1}]), + INDEPENDENT_CHILDREN: true, + MAX_CHILDREN: 3, + IDENTIFIER: 1, + AUTOFIRE: true, + } + }], + ON: [{ + event: "fire", + handler: ({ gun }) => { + gun.setBulletType(["destroyerLegion", "gunnerLegion", "sprayerLegion", "battleshipLegion", "spawnerLegion"][gun.identifier++ % 5]); + } + }], +} +Class.legionaryCrasher = { + PARENT: "elite", + LABEL: "Legionary Crasher", + UPGRADE_COLOR: "pink", + AI: { STRAFE: false, NO_LEAD: false }, + HAS_NO_RECOIL: true, + VALUE: 5e6, + SIZE: 75, + BODY: { + FOV: 1.5, + SPEED: 0.1 * base.SPEED, + HEALTH: 2000, + DAMAGE: 5 * base.DAMAGE, + }, + GUNS: [ + ...weaponArray([ + { + POSITION: [14.5, 13, 1, 0, 0, 0, 0], + }, { + POSITION: [3, 13, 1.7, 14.5, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, g.setTrap, g.pounder, { reload: 2, speed: 2, size: 0.65, maxSpeed: 2, range: 0.65 }]), + TYPE: "legionaryPillbox", + STAT_CALCULATOR: "trap", + }, + }, + ], 3), + ...weaponArray({ + POSITION: [5, 12, 1.6, -11, 0, 0, 0], + }, 3), + ], + TURRETS: [ + { + POSITION: [12, 0, 0, 0, 360, 1], + TYPE: "legionaryCrasherTop", + }, + ...weaponArray({ + POSITION: [14, 8, 0, 60, 180, 0], + TYPE: [ "sprayer", { GUN_STAT_SCALE: {speed: 1.3, health: 1.5, damage: 1.4, resist: 1.2}, COLOR: -1 } ], + }, 3), + { + POSITION: [12, 0, 0, 0, 0, 0], + TYPE: 'legionaryCrasherSpawner' + } + ], +} + +// STRANGE BOSSES +Class.sorcerer = { + PARENT: "miniboss", + LABEL: "Sorcerer", + DANGER: 7, + SHAPE: 0, + COLOR: "veryLightGrey", + UPGRADE_COLOR: "veryLightGrey", + SIZE: 26, + MAX_CHILDREN: 50, + VALUE: 2e5, + BODY: { + FOV: 0.5, + SPEED: 0.12 * base.SPEED, + HEALTH: 6 * base.HEALTH, + DAMAGE: 2 * base.DAMAGE, + }, + GUNS: weaponArray({ + POSITION: [3.5, 8.65, 1.2, 8, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, g.summoner, g.machineGun, g.machineGunner, { damage: 1.8, size: 0.4, spray: 150, speed: 2, shudder: 1.75 }]), + TYPE: "minichip", + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "drone", + WAIT_TO_CYCLE: true, + }, + }, 2) +}; +Class.summoner = { + PARENT: "miniboss", + LABEL: "Summoner", + DANGER: 8, + SHAPE: 4, + COLOR: "gold", + UPGRADE_COLOR: "gold", + SIZE: 26, + MAX_CHILDREN: 28, + VALUE: 3e5, + BODY: { + FOV: 0.5, + SPEED: 0.1 * base.SPEED, + HEALTH: 7 * base.HEALTH, + DAMAGE: 2.6 * base.DAMAGE, + }, + GUNS: weaponArray({ + POSITION: [3.5, 8.65, 1.2, 8, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, g.summoner, { size: 0.8 }]), + TYPE: "summonerDrone", + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "drone", + WAIT_TO_CYCLE: true, + }, + }, 4) +}; +Class.enchantress = { + PARENT: "miniboss", + LABEL: "Enchantress", + DANGER: 8, + SHAPE: 3.5, + COLOR: "orange", + UPGRADE_COLOR: "orange", + SIZE: 26, + MAX_CHILDREN: 28, + VALUE: 4e5, + BODY: { + FOV: 0.5, + SPEED: 0.09 * base.SPEED, + HEALTH: 10 * base.HEALTH, + DAMAGE: 3 * base.DAMAGE, + }, + GUNS: weaponArray({ + POSITION: [3.5, 8.65, 1.2, 8, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, g.summoner, { size: 0.9, damage: 1.1 }]), + TYPE: "dorito", + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "drone", + WAIT_TO_CYCLE: true, + }, + }, 3) +}; +Class.exorcistor = { + PARENT: "miniboss", + LABEL: "Exorcistor", + DANGER: 8, + SHAPE: 5.5, + COLOR: "purple", + UPGRADE_COLOR: "purple", + SIZE: 26, + MAX_CHILDREN: 20, + VALUE: 5e5, + BODY: { + FOV: 0.5, + SPEED: 0.08 * base.SPEED, + HEALTH: 15 * base.HEALTH, + DAMAGE: 4 * base.DAMAGE, + }, + GUNS: weaponArray({ + POSITION: [3.5, 8.65, 1.2, 8, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, g.summoner, g.destroyer, {maxSpeed: 1.2}]), + TYPE: "demonchip", + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "drone", + WAIT_TO_CYCLE: true, + }, + }, 5) +}; +Class.shaman = { + PARENT: "miniboss", + LABEL: "Shaman", + DANGER: 8, + SHAPE: 6, + COLOR: "hexagon", + UPGRADE_COLOR: "hexagon", + SIZE: 26, + MAX_CHILDREN: 20, + VALUE: 6e5, + BODY: { + FOV: 0.5, + SPEED: 0.07 * base.SPEED, + HEALTH: 20 * base.HEALTH, + DAMAGE: 5 * base.DAMAGE, + }, + GUNS: weaponArray({ + POSITION: [3.5, 8.65, 1.2, 8, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, g.summoner, g.destroyer, { size: 1.1, maxSpeed: 1.2, damage: 1.1 }]), + TYPE: "realchip", + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "drone", + WAIT_TO_CYCLE: true, + }, + }, 6) +}; +Class.eliteSkimmer = { + PARENT: "elite", + LABEL: "Elite Skimmer", + COLOR: "orange", + UPGRADE_COLOR: "orange", + TURRETS: weaponArray({ + POSITION: [15, 5, 0, 60, 170, 0], + TYPE: "skimmerTurret", + }, 3) +}; + +// Nesters +Class.nestKeeper = { + PARENT: "miniboss", + LABEL: "Nest Keeper", + COLOR: "purple", + UPGRADE_COLOR: "purple", + SHAPE: 5, + SIZE: 50, + BODY: { + FOV: 1.3, + SPEED: base.SPEED * 0.25, + HEALTH: base.HEALTH * 9, + SHIELD: base.SHIELD * 1.5, + REGEN: base.REGEN, + DAMAGE: base.DAMAGE * 2.5, + }, + MAX_CHILDREN: 15, + VALUE: 3e5, + GUNS: weaponArray({ + POSITION: [3.5, 6.65, 1.2, 8, 0, 36, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, g.nestKeeper]), + TYPE: "drone", + AUTOFIRE: true, + LABEL: "Mega Crasher", + STAT_CALCULATOR: "drone", + }, + }, 5), + TURRETS: [ + ...weaponArray({ + POSITION: [8, 9, 0, 0, 120, 0], + TYPE: [ "auto4gun", { INDEPENDENT: true, COLOR: -1 } ], + }, 5), + { + POSITION: [9, 0, 0, 0, 360, 1], + TYPE: [ "boomerTurret", { INDEPENDENT: true, COLOR: -1 } ], + }, + ], +}; +Class.nestWarden = { + PARENT: "miniboss", + LABEL: "Nest Warden", + COLOR: "purple", + UPGRADE_COLOR: "purple", + SHAPE: 5, + SIZE: 50, + BODY: { + FOV: 1.3, + SPEED: base.SPEED * 0.25, + HEALTH: base.HEALTH * 9, + SHIELD: base.SHIELD * 1.5, + REGEN: base.REGEN, + DAMAGE: base.DAMAGE * 2.5, + }, + VALUE: 3e5, + GUNS: weaponArray([ + { + POSITION: [10.7, 8, 1, 0, 0, 36, 0], + }, { + POSITION: [1.5, 8, 1.2, 10.7, 0, 36, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, { speed: 1.2 }, g.setTrap, g.constructor]), + TYPE: "unsetTrap", + STAT_CALCULATOR: "block" + }, + } + ], 5), + TURRETS: [ + { + POSITION: [9, 0, 0, 0, 360, 1], + TYPE: [ "barricadeTurret", { INDEPENDENT: true, COLOR: -1 } ], + }, + ...weaponArray({ + POSITION: [8, 9, 0, 0, 120, 0], + TYPE: [ "cruiserTurret", { INDEPENDENT: true, COLOR: -1 } ], + }, 5) + ], +} +Class.nestGuardian = { + PARENT: "miniboss", + LABEL: "Nest Guardian", + COLOR: "purple", + UPGRADE_COLOR: "purple", + SHAPE: 5, + SIZE: 50, + BODY: { + FOV: 1.3, + SPEED: base.SPEED * 0.25, + HEALTH: base.HEALTH * 9, + SHIELD: base.SHIELD * 1.5, + REGEN: base.REGEN, + DAMAGE: base.DAMAGE * 2.5, + }, + VALUE: 3e5, + GUNS: weaponArray({ + POSITION: [5.5, 7, 1, 6, 0, 36, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.pounder, g.destroyer]), + TYPE: "bullet", + LABEL: "Devastator", + }, + }, 5), + TURRETS: [ + { + POSITION: [9, 0, 0, 0, 360, 1], + TYPE: [ "twisterTurret", { INDEPENDENT: true, COLOR: -1 } ], + }, + ...weaponArray({ + POSITION: [8, 9, 0, 0, 120, 0], + TYPE: [ "swarmerTurret", { INDEPENDENT: true, COLOR: -1 } ], + }, 5) + ], +} + +// Rogues +Class.roguePalisade = { + PARENT: "miniboss", + LABEL: "Rogue Palisade", + COLOR: "darkGrey", + UPGRADE_COLOR: "darkGrey", + SHAPE: 6, + SIZE: 30, + VALUE: 5e5, + CONTROLLERS: ['nearestDifferentMaster', 'onlyAcceptInArc'], + BODY: { + FOV: 1.4, + SPEED: 0.05 * base.SPEED, + HEALTH: 16 * base.HEALTH, + SHIELD: 3 * base.SHIELD, + DAMAGE: 3 * base.DAMAGE, + }, + GUNS: weaponArray({ + POSITION: [4, 6, -1.6, 8, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([ g.factory, g.pounder, { reload: 2, damage: 0.7, density: 0.6 }]), + TYPE: ["minion", {INDEPENDENT: true}], + STAT_CALCULATOR: "drone", + AUTOFIRE: true, + MAX_CHILDREN: 3, + SYNCS_SKILLS: true, + WAIT_TO_CYCLE: true + } + }, 6), + TURRETS: weaponArray({ + POSITION: [5, 10, 0, 30, 110, 0], + TYPE: ["baseTrapTurret", {GUN_STAT_SCALE: {health: 0.7, damage: 0.8}}] + }, 6) +}; +Class.rogueArmada = { + PARENT: "miniboss", + LABEL: 'Rogue Armada', + COLOR: "darkGrey", + UPGRADE_COLOR: "darkGrey", + SHAPE: 7, + SIZE: 28, + VALUE: 500000, + BODY: { + FOV: 1.3, + SPEED: base.SPEED * 0.1, + HEALTH: base.HEALTH * 16, + SHIELD: base.SHIELD * 3, + REGEN: base.REGEN, + DAMAGE: base.DAMAGE * 3, + }, + GUNS: weaponArray([ + { + POSITION: [8, 2, 1, 0, -2, 360 / 14, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.shotgun, g.pounder, {reload: 2, damage: 1.5, health: 1.5, resist: 1.25}]), + TYPE: "casing" + } + }, { + POSITION: [8, 2, 1, 0, -1.5, 360 / 14, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.shotgun, g.pounder, {reload: 2, damage: 1.5, health: 1.5, resist: 1.25}]), + TYPE: "casing" + } + }, { + POSITION: [8, 2, 1, 0, -1, 360 / 14, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.shotgun, g.pounder, {reload: 2, damage: 1.5, health: 1.5, resist: 1.25}]), + TYPE: "bullet" + } + }, { + POSITION: [8, 3, 1, 0, 0.5, 360 / 14, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.shotgun, g.pounder, {reload: 2, damage: 1.5, health: 1.5, resist: 1.25}]), + TYPE: "bullet" + } + }, { + POSITION: [8, 3, 1, 0, 0, 360 / 14, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.shotgun, g.pounder, {reload: 2, damage: 1.5, health: 1.5, resist: 1.25}]), + TYPE: "bullet" + } + }, { + POSITION: [8, 3, 1, 0, 0.5, 360 / 14, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.shotgun, g.pounder, {reload: 2, damage: 1.5, health: 1.5, resist: 1.25}]), + TYPE: "bullet" + } + }, { + POSITION: [8, 4, 1, 0, 1, 360 / 14, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.shotgun, g.pounder, {reload: 2, damage: 1.5, health: 1.5, resist: 1.25}]), + TYPE: "bullet" + } + }, { + POSITION: [8, 4, 1, 0, 1.5, 360 / 14, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.shotgun, g.pounder, {reload: 2, damage: 1.5, health: 1.5, resist: 1.25}]), + TYPE: "casing" + } + }, { + POSITION: [8.5, 6, 1, 4, 0, 360 / 14, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.shotgun, g.pounder, {reload: 2}, g.fake]), + TYPE: "casing" + } + }, { + POSITION: [7, 6, -1.6, 4, 0, 360 / 14, 0] + } + ], 7), + TURRETS: weaponArray({ + POSITION: [5, 10, 0, 0, 110, 0], + TYPE: "shottrapTurret" + }, 7), +} + +// Bob. +Class.bob = { + PARENT: "ramMiniboss", + LABEL: "Bob", + SHAPE: 0, + COLOR: "aqua", + UPGRADE_COLOR: "aqua", + SIZE: 18, + BODY: { + FOV: 2, + SPEED: 2 * base.SPEED, + HEALTH: 5 * base.HEALTH, + DAMAGE: 5 * base.DAMAGE, + REGEN: 8 * base.REGEN, + FOV: 0.5 * base.FOV, + DENSITY: 6 * base.DENSITY, + }, + CONTROLLERS: ["nearestDifferentMaster", "mapTargetToGoal"], + TURRETS: [ + { + POSITION: [21.5, 0, 0, 0, 360, 0], + TYPE: "smasherBody", + }, { + POSITION: [21.5, 0, 0, 30, 360, 0], + TYPE: "landmineBody", + }, { + POSITION: [23.75, 0, 0, 0, 360, 0], + TYPE: "spikeBody", + }, + ], +}; +Class.nemesis = { + PARENT: "bob", + LABEL: "Nemesis", + COLOR: "red", + UPGRADE_COLOR: "red", + BODY: { + REGEN: 1e5, + HEALTH: 1e6, + DENSITY: 30, + DAMAGE: 1e5, + FOV: 5, + }, +}; + +// DIEP BOSSES +Class.guardian = { + PARENT: "elite", + LABEL: "Guardian of the Pentagons", + UPGRADE_LABEL: "Guardian", + UPGRADE_COLOR: "pink", + FACING_TYPE: "toTarget", + GUNS: [ + { + POSITION: [4, 12, 1.4, 8, 0, 180, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.swarm, { size: 0.5 }]), + TYPE: "swarm", + AUTOFIRE: true, + }, + }, + ], + AI: { NO_LEAD: false }, +}; +Class.defenderAutoTankGun = { + PARENT: "autoTankGun", + GUNS: [ + { + POSITION: [22, 10, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.autoTurret]), + TYPE: ["bullet", {COLOR: "yellow"}], + }, + }, + ], +}; +Class.defender = { + PARENT: "elite", + LABEL: "Defender", + COLOR: "orange", + UPGRADE_COLOR: "orange", + GUNS: weaponArray([ + { + POSITION: [15, 7, 1, -3, 0, 60, 0], + }, { + POSITION: [3, 7, 1.7, 12, 0, 60, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, g.flankGuard, {reload: 1.33, damage: 2.5}]), + TYPE: ["trap", {COLOR: "yellow"}], + STAT_CALCULATOR: "trap", + }, + }, + ], 3), + TURRETS: weaponArray({ + POSITION: [5, 7, 0, 0, 190, 1], + TYPE: "defenderAutoTankGun", + }, 3), + AI: { NO_LEAD: false }, +}; + +// CELESTIALS +Class.terrestrial = { + PARENT: "miniboss", + LABEL: "Terrestrial", + SKILL: [9, 9, 9, 9, 9, 9, 9, 9, 9, 9], + VALUE: 5e5, + SHAPE: 7, + SIZE: 35, + CONTROLLERS: [["minion", {orbit: 170}]], + BODY: { + FOV: 1, + HEALTH: 1000, + SHIELD: 50, + REGEN: base.REGEN * 0.1, + SPEED: base.SPEED * 0.3, + DAMAGE: 9, + }, +}; +Class.celestial = { + PARENT: "miniboss", + LABEL: "Celestial", + SKILL: [9, 9, 9, 9, 9, 9, 9, 9, 9, 9], + VALUE: 1e6, + SHAPE: 9, + SIZE: 45, + CONTROLLERS: [["minion", {orbit: 200}]], + BODY: { + FOV: 1, + HEALTH: 1500, + SHIELD: 75, + REGEN: base.REGEN * 0.1, + SPEED: base.SPEED * 0.2, + DAMAGE: 12, + }, +}; +Class.rogueCelestial = { + PARENT: "celestial", + LABEL: "Rogue Celestial", + COLOR: "darkGrey", +}; +Class.eternal = { + PARENT: "miniboss", + LABEL: "Eternal", + SKILL: [9, 9, 9, 9, 9, 9, 9, 9, 9, 9], + VALUE: 4e6, + SHAPE: 11, + SIZE: 90, + CONTROLLERS: [["minion", {orbit: 240}]], + BODY: { + FOV: 1, + HEALTH: 3000, + SHIELD: 150, + REGEN: base.REGEN * 0.1, + SPEED: base.SPEED * 0.15, + DAMAGE: 18, + }, +}; + +// Terrestrials +let ares = new LayeredBoss(null, "Ares", "terrestrial", 7, "purple", "terrestrialTrapTurret", 7, 5.5); +ares.addLayer({gun: { + POSITION: [3.75, 7, 1.2, 8, 0, null, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, g.summoner, g.destroyer, {health: 1.2, damage: 1.1, resist: 1.1, density: 1.5, maxSpeed: 1.25}]), + TYPE: ["demonchip", { INDEPENDENT: true }], + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "drone", + WAIT_TO_CYCLE: true, + }, +}}, false, null, 18); +ares.addLayer({turret: { + POSITION: [10, 8.5, 0, null, 160, 0], + TYPE: ["protoSwarmerTurret", { INDEPENDENT: true }], +}}, true, 6.5); + +let gersemi = new LayeredBoss(null, "Gersemi", "terrestrial", 7, "lightGreen", "terrestrialTrapTurret", 7, 5.5); +gersemi.addLayer({turret: { + POSITION: [9, 8, 0, null, 160, 0], + TYPE: ["swarmTurret", { INDEPENDENT: true, GUN_STAT_SCALE: {health: 1.7, damage: 1.2} }], +}}); +gersemi.addLayer({turret: { + POSITION: [9.5, 7.5, 0, null, 160, 0], + TYPE: ["basicTurret", { INDEPENDENT: true, GUN_STAT_SCALE: {health: 1.8, damage: 1.3} }], +}}, true, 6.5); + +let ezekiel = new LayeredBoss(null, "Ezekiel", "terrestrial", 7, "orange", "terrestrialTrapTurret", 7, 5.5); +ezekiel.addLayer({gun: { + POSITION: [3.75, 7, 1.2, 8, 0, null, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, g.summoner, g.destroyer, {health: 1.2, damage: 1.1, resist: 1.1, density: 1.5, maxSpeed: 1.25}]), + TYPE: ["dorito", { COLOR: "orange", INDEPENDENT: true }], + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "drone", + WAIT_TO_CYCLE: true, + }, +}}, true, null, 18); +ezekiel.addLayer({turret: { + POSITION: [10, 7.5, 0, null, 160, 0], + TYPE: [setTurretProjectileRecoil("skimmerTurret", 0.5), { COLOR: "grey", INDEPENDENT: true, GUN_STAT_SCALE: {maxSpeed: 0.5} }], +}}, true, 6.5) + +let eris = new LayeredBoss(null, "Eris", "terrestrial", 7, "pink", "terrestrialTrapTurret", 7, 5.5); +eris.addLayer({gun: { + POSITION: [3.75, 7, 1.2, 8, 0, null, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.factory, { size: 0.7, maxSpeed: 0.85, damage: 0.8 }]), + TYPE: ["minion", { INDEPENDENT: true, COLOR: "pink" }], + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "drone", + WAIT_TO_CYCLE: true, + }, +}}, false, null, 14); +eris.addLayer({turret: { + POSITION: [10, 8.5, 0, null, 160, 0], + TYPE: [setTurretProjectileRecoil("rocketeerTurret", 0.43), { INDEPENDENT: true, GUN_STAT_SCALE: {maxSpeed: 0.43} }], +}}, true, 6.5); + +let selene = new LayeredBoss(null, "Selene", "terrestrial", 7, "gold", "terrestrialTrapTurret", 7, 5.5); +selene.addLayer({gun: { + POSITION: [3.75, 7, 1.2, 8, 0, null, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, g.summoner, g.destroyer, {health: 1.2, damage: 1.1, resist: 1.1, density: 1.5, maxSpeed: 1.25}]), + TYPE: ["summonerDrone", { COLOR: "gold", INDEPENDENT: true }], + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "drone", + WAIT_TO_CYCLE: true, + }, +}}, true, null, 18); +selene.addLayer({turret: { + POSITION: [10, 7.5, 0, null, 160, 0], + TYPE: ["hyperTwisterTurret", { INDEPENDENT: true }], +}}, true, 6.5); + +// PALADIN +let paladin = new LayeredBoss(null, "Paladin", "celestial", 9, "purple", "baseTrapTurret", 6.5, 5.5); +paladin.addLayer({gun: { + POSITION: [3.8, 6, 1.4, 8, 0, null, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, g.summoner, g.destroyer, {health: 1.4, damage: 1.4, resist: 1.2, density: 1.8, maxSpeed: 1.325}]), + TYPE: ["demonchip", {INDEPENDENT: true}], + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "drone", + WAIT_TO_CYCLE: true, + }, +}}, true, null, 16); +paladin.addLayer({turret: { + POSITION: [10, 7.5, 0, null, 160, 0], + TYPE: ["swarmerTurret", {GUN_STAT_SCALE: {speed: 1.45, maxSpeed: 0.5, health: 1.3, range: 1.3}}], +}}, true, 6); + +// FREYJA +let freyja = new LayeredBoss(null, "Freyja", "celestial", 9, "lightGreen", "baseTrapTurret", 6.5, 5.5); +freyja.addLayer({turret: { + POSITION: [8.5, 9, 0, null, 180, 0], + TYPE: ["cruiserTurret", {GUN_STAT_SCALE: {health: 1.2, damage: 1.3, speed: 1.1, maxSpeed: 1.1, resist: 1.05}}], +}}); +freyja.addLayer({turret: { + POSITION: [10.6, 7.5, 0, null, 160, 0], + TYPE: ["auto4gun", {GUN_STAT_SCALE: {health: 1.2, damage: 1.2, speed: 1.15, maxSpeed: 0.9, resist: 1.2}}], +}}, true, 6); + +// ZAPHKIEL +let zaphkiel = new LayeredBoss(null, "Zaphkiel", "celestial", 9, "orange", "baseTrapTurret", 6.5, 5.5); +zaphkiel.addLayer({gun: { + POSITION: [3.8, 6, 1.4, 8, 0, null, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, g.summoner, g.destroyer, {health: 1.4, damage: 1.4, resist: 1.2, density: 1.8, maxSpeed: 1.325}]), + TYPE: ["dorito", {INDEPENDENT: true}], + AUTOFIRE: true, + SYNCS_SKILLS: true, + }, +}}, true, null, 16); +zaphkiel.addLayer({turret: { + POSITION: [10, 7.5, 0, null, 160, 0], + TYPE: [setTurretProjectileRecoil("skimmerTurret", 0.65), {COLOR: "grey", INDEPENDENT: true, GUN_STAT_SCALE: {maxSpeed: 0.65}}], +}}, true, 6); + +// NYX +let nyx = new LayeredBoss(null, "Nyx", "celestial", 9, "pink", "baseTrapTurret", 6.5, 5.5); +nyx.addLayer({gun: { + POSITION: [3.8, 7, -1.4, 8, 0, null, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.factory, { size: 0.7, maxSpeed: 0.85, damage: 0.8 }]), + TYPE: ["minion", {INDEPENDENT: true,}], + AUTOFIRE: true, + SYNCS_SKILLS: true, + }, +}}, true, null, 16); +nyx.addLayer({turret: { + POSITION: [10, 7.5, 0, null, 160, 0], + TYPE: [setTurretProjectileRecoil("rocketeerTurret", 0.5), { INDEPENDENT: true, GUN_STAT_SCALE: {maxSpeed: 0.5} }], +}}, true, 6); + +// THEIA +let theia = new LayeredBoss(null, "Theia", "celestial", 9, "gold", "baseTrapTurret", 6.5, 5.5); +theia.addLayer({gun: { + POSITION: [3.8, 6, 1.4, 8, 0, null, 1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, g.summoner, g.destroyer, {health: 1.4, damage: 1.4, resist: 1.2, density: 1.8, maxSpeed: 1.325}]), + TYPE: ["summonerDrone", {INDEPENDENT: true}], + AUTOFIRE: true, + WAIT_TO_CYCLE: true, + SYNCS_SKILLS: true, + }, +}}, true, null, 35); +theia.addLayer({turret: { + POSITION: [10, 7.5, 0, null, 160, 0], + TYPE: ["twisterTurret", {INDEPENDENT: true, COLOR: "grey", GUN_STAT_SCALE: {health: 1.3, damage: 1.1, resist: 1.2, speed: 1.1, maxSpeed: 0.8}}], +}}, true, 6); + +// ATLAS +let atlas = new LayeredBoss(null, "Atlas", "celestial", 9, "purple", "baseTrapTurret", 6.5, 5.5); +atlas.addLayer({turret: { + POSITION: [7, 9, 0, null, 180, 0], + TYPE: "artilleryTurret", +}}); +atlas.addLayer({turret: { + POSITION: [10.5, 8, 0, null, 160, 0], + TYPE: ["nailgunTurret", {GUN_STAT_SCALE: {speed: 1.1, maxSpeed: 1.1, resist: 1.3}}], +}}, true, 6); + +// RHEA +let rhea = new LayeredBoss(null, "Rhea", "celestial", 9, "darkGrey", "baseTrapTurret", 6.5, 5.5); +rhea.addLayer({turret: { + POSITION: [8.5, 9, 0, null, 180, 0], + TYPE: "wrenchTurret", +}}); +rhea.addLayer({turret: { + POSITION: [10.5, 8, 0, null, 160, 0], + TYPE: "crowbarTurret", +}}, true, 6); + +// JULIUS +let julius = new LayeredBoss(null, "Julius", "celestial", 9, "darkGrey", "baseTrapTurret", 6.5, 5.5); +julius.addLayer({turret: { + POSITION: [8.5, 9, 0, null, 180, 0], + TYPE: "juliusLowerTurret", +}}); +julius.addLayer({turret: { + POSITION: [10.5, 8, 0, null, 160, 0], + TYPE: [setTurretProjectileRecoil("launcherTurret", 0.82), {GUN_STAT_SCALE: {health: 1.3, damage: 1.3, maxSpeed: 0.82}}], +}}, true, 6); + +// GENGHIS +let genghis = new LayeredBoss(null, "Genghis", "celestial", 9, "darkGrey", "baseTrapTurret", 6.5, 5.5); +genghis.addLayer({turret: { + POSITION: [8.5, 9, 0, null, 180, 0], + TYPE: "genghisLowerTurret", +}}); +genghis.addLayer({turret: { + POSITION: [10.5, 8, 0, null, 160, 0], + TYPE: ["auto4gun", {GUN_STAT_SCALE: {speed: 1.2, maxSpeed: 0.85, health: 1.15, damage: 1.2, resist: 1.2}}], +}}, true, 6); + +// NAPOLEON +let napoleon = new LayeredBoss(null, "Napoleon", "celestial", 9, "darkGrey", "baseTrapTurret", 6.5, 5.5); +napoleon.addLayer({turret: { + POSITION: [8.5, 9, 0, null, 180, 0], + TYPE: "napoleonLowerTurret", +}}); +napoleon.addLayer({turret: { + POSITION: [10.5, 8, 0, null, 160, 0], + TYPE: "napoleonUpperTurret", +}}, true, 6) + +// Eternals +let kronos = new LayeredBoss(null, "Kronos", "eternal", 11, "veryLightGrey", "baseTrapTurret", 6, 5.5); +kronos.addLayer({turret: { + POSITION: [6.5, 9, 0, null, 160, 0], + TYPE: "kronosSkimmerTurret", +}}); +kronos.addLayer({turret: { + POSITION: [6.5, 9, 0, null, 160, 0], + TYPE: ["carrierTurret", {GUN_STAT_SCALE: g.battleship}], +}}, true, 4); +kronos.addLayer({turret: { + POSITION: [8.5, 9, 0, null, 160, 0], + TYPE: ["tripletTurret", {GUN_STAT_SCALE: {health: 1.15, damage: 1.1, resist: 1.3, speed: 1.1, maxSpeed: 0.9}}], +}}, true, 4); + +let odin = new LayeredBoss(null, "Odin", "eternal", 11, "aqua", "baseTrapTurret", 4.5, 3.5); +odin.addLayer({gun: { + POSITION: [2.25, 3.25, -1.6, 9, 0, null, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, g.summoner, g.pounder, g.destroyer, {speed: 1.25, maxSpeed: 1.25}]), + TYPE: ["realchip", {INDEPENDENT: true, DRAW_HEALTH: true, COLOR: 'hexagon'}], + AUTOFIRE: true, + SYNCS_SKILLS: true, + }, +}}, true, null, 18); +odin.addLayer({turret: { + POSITION: [7, 8, 0, null, 160, 0], + TYPE: "autoSmasherLauncherTurret", +}}, true, 5.5); +odin.addLayer({turret: { + POSITION: [8, 9, 0, null, 160, 0], + TYPE: "gunnerCruiserTurret", +}}, true, 4.5); + +// Developer Bosses +Class.taureonCoreBase = { + SHAPE: 4, + COLOR: '#00A2E8' +}; +Class.taureonCore = { + PARENT: "genericTank", + LABEL: "Core Turret", + SHAPE: 4.5, + COLOR: '#99D9EA', + CONTROLLERS: ["nearestDifferentMaster", "onlyAcceptInArc"], + INDEPENDENT: true, + GUNS: [{ + POSITION: [10, 14, -0.5, 14, 0, 0, 0] + },{ + POSITION: [21, 15, -1.1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.destroyer, g.sniper]), + TYPE: "snakeOld", + STAT_CALCULATOR: "sustained" + } + }], + TURRETS: [{ + POSITION: [20 * Math.SQRT2, 0, 0, 0, 0, 0], + TYPE: "taureonCoreBase" + }] +}; +Class.taureonBase = { + SHAPE: 4.5, + COLOR: '#161B54', + MIRROR_MASTER_ANGLE: true +}; +let d = 1/4; +Class.taureonStar = { + SHAPE: [[0,1],[d,d],[1,0],[d,-d],[0,-1],[-d,-d],[-1,0],[-d,d]], + COLOR: '#3F48CC', + MIRROR_MASTER_ANGLE: true +}; +Class.taureonRailgunTurret = { + PARENT: "genericTank", + COLOR: "grey", + LABEL: "Railgun Turret", + CONTROLLERS: ["nearestDifferentMaster", "onlyAcceptInArc"], + INDEPENDENT: true, + GUNS: [{ + POSITION: [20, 7, 1, 0, 0, 0, 0] + },{ + POSITION: [24, 5, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.destroyer, { speed: 5, penetration: 0.8 }]), + TYPE: "bullet" + } + },{ + POSITION: [5, 7.5, -1.6, 8, 0, 0, 0], + }] +}; +Class.taureonThruster = { + PARENT: "genericTank", + COLOR: "grey", + LABEL: "Thruster", + CONTROLLERS: ["onlyAcceptInArc"], + GUNS: [{ + POSITION: [14, 12, 1, 4, 0, 180, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.machineGun, g.thruster, { range: 0.175, reload: 0.25, recoil: 0.25 }]), + TYPE: ["bullet", { ALPHA: 0.5 }] + } + }, { + POSITION: [12, 12, 1.4, 4, 0, 180, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.machineGun, g.thruster, { range: 0.175, reload: 0.25, recoil: 0.25 }]), + TYPE: ["bullet", { ALPHA: 0.5 }] + }, + }] +}; +Class.taureonMissile = { + PARENT: "bullet", + LABEL: "Missile", + FACING_TYPE: "smoothToTarget", + CONTROLLERS: ["nearestDifferentMaster"], + INDEPENDENT: true, + BODY: { + ACCELERATION: 10, + FOV: base.FOV * 2 + }, + TURRETS: [{ + POSITION: [10, 0, 0, 0, 360, 1], + TYPE: ["genericTank", {COLOR: "grey"}], + }], + GUNS: [{ + POSITION: [6, 12, 1.4, 8, 0, 180, 0], + PROPERTIES: { + AUTOFIRE: true, + STAT_CALCULATOR: "thruster", + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, { reload: 0.25, range: 0.075 }]), + TYPE: ["bullet", { PERSISTS_AFTER_DEATH: true, ALPHA: 0.5 }] + } + },{ + POSITION: [10, 12, 0.8, 8, 0, 180, 0], + PROPERTIES: { + AUTOFIRE: true, + STAT_CALCULATOR: "thruster", + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, { reload: 0.25, range: 0.075 }]), + TYPE: ["bullet", { PERSISTS_AFTER_DEATH: true, ALPHA: 0.5 }] + } + },...Array(32).fill().map((_, i)=>({ + POSITION: [0, (i % 4) + 1, 0, 0, 0, 0, 9999], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.shotgun, { spray: 1e6, range: 0.5, shudder: 1.5, damage: 1 + (i % 4) }]), + TYPE: ["bullet", { PERSISTS_AFTER_DEATH: true }], + SHOOT_ON_DEATH: true + }, + }))] +}; +Class.taureonBoss = { + PARENT: "miniboss", + LABEL: "Diamond Marauder", + NAME: "Taureon", + COLOR: '#2B339B', + UPGRADE_COLOR: "spaceGem", + DANGER: 10, + SHAPE: 4.5, + SIZE: 50, + FACING_TYPE: "smoothToTarget", + UPGRADE_TOOLTIP: "With a powerful Gatling Gun on the front, Rocket Launchers as wings, movable Thrusters on the back, " + + "and equipped with Railgun Turrets, it perfectly excells at terminating those who feel its Wrath.\n" + + "An octahedral carbon robot, exclusively designed to eradicate opponents with sheer brutality alone.\n" + + '"NOW YOU FACE MY ULTIMATE CREATION."', + VALUE: 9e6, + BODY: { + FOV: 1, + SPEED: 0.5 * base.SPEED, + HEALTH: 20 * base.HEALTH, + DAMAGE: 3 * base.DAMAGE, + }, + TURRETS: [{ + POSITION: [23.3, 0, 0, 0, 0, 0], + TYPE: "taureonBase" + },{ + POSITION: [5, 10, 0, -45, 180, 0], + TYPE: "taureonRailgunTurret" + },{ + POSITION: [5, 10, 0, 45, 180, 0], + TYPE: "taureonRailgunTurret" + },{ + POSITION: [5, -10, -2, -45, 90, 0], + TYPE: "taureonThruster" + },{ + POSITION: [5, -10, 2, 45, 90, 0], + TYPE: "taureonThruster" + },{ + POSITION: [25, 0, 0, 0, 0, 1], + TYPE: "taureonStar" + },{ + POSITION: [5, 0, 0, 0, 360, 1], + TYPE: "taureonCore" + }], + GUNS: [...Array(6).fill().map((_, i) => ({ + POSITION: [18, 1.75, 1, 0, Math.cos(Math.PI * i / 3) * 2, 0, i / 6], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, { speed: 2, maxSpeed: 2, damage: 0.75, size: 0.8 }]), + TYPE: "bullet" + } + })),{ + POSITION: [4, 5, -0.5, 12, 0, -90, 0] + },{ + POSITION: [10, 5, -1.2, 5, 0, -90, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.sidewinder, g.destroyer, { shudder: 0.1, reload: 0.6, speed: 5, range: 2 }]), + TYPE: "taureonMissile", + STAT_CALCULATOR: "sustained" + } + },{ + POSITION: [4, 5, -0.5, 12, 0, 90, 0] + },{ + POSITION: [10, 5, -1.2, 5, 0, 90, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.sidewinder, g.destroyer, { shudder: 0.1, reload: 0.6, speed: 5, range: 2 }]), + TYPE: "taureonMissile", + STAT_CALCULATOR: "sustained" + } + },{ + POSITION: [5.5, 5, -1.5, 5, 0, -45, 0] + },{ + POSITION: [5.5, 5, -1.5, 5, 0, 45, 0] + },{ + POSITION: [2, 7, 1, 8, 0, 0, 0] + },{ + POSITION: [2, 7, 1, 14.5, 0, 0, 0] + }] +}; + +Class.zephiMiscDeco = makeDeco(4, "white") +Class.zephiMiscDeco2 = makeDeco(4, "black") +Class.zephiSunchip = makeAuto({ + PARENT: "drone", + SHAPE: 4, + HITS_OWN_TYPE: "hard", + BODY: { + FOV: 0.5, + }, + AI: { + BLIND: true, + FARMER: true, + }, + TURRETS: [{ + POSITION: [20 * Math.SQRT1_2, 0, 0, 45, 0, 1], + TYPE: ["overdriveDeco", { MIRROR_MASTER_ANGLE: true }] + },{ + POSITION: [20 * Math.SQRT1_2 ** 2, 0, 0, 0, 0, 1], + TYPE: ["shinySquare", { MIRROR_MASTER_ANGLE: true }] + }] +}, "Robo-Sunchip", {type: 'autoSmasherTurret', size: 6}) +Class.zephiEggchip = { + PARENT: "drone", + LABEL: "Guided Missile", + SHAPE: 0, + HITS_OWN_TYPE: "hard", + BODY: { + FOV: 0.5, + }, + AI: { + BLIND: true, + FARMER: true, + }, + GUNS: [ + { + POSITION: [14, 6, 1, 0, 0, 180, 0], + PROPERTIES: { + AUTOFIRE: true, + SHOOT_SETTINGS: combineStats([g.basic, g.skimmer, g.lowPower, { reload: 0.5, recoil: 1.35, speed: 1.3, maxSpeed: 1.3 }]), + TYPE: ["bullet", { COLOR: "black", PERSISTS_AFTER_DEATH: true }], + STAT_CALCULATOR: "thruster", + }, + }, + ], + TURRETS: [{ + POSITION: [10, 0, 0, 45, 0, 1], + TYPE: "gem" + }] +} +Class.zephiGearOuter = makeDeco('M 0.5 0.0929 V -0.0908 L 0.3875 -0.1096 C 0.3792 -0.1409 0.3667 -0.1701 0.3521 -0.1952 L 0.4187 -0.2871 L 0.2896 -0.4186 L 0.1958 -0.3539 C 0.1687 -0.3685 0.1396 -0.381 0.1104 -0.3894 L 0.0917 -0.5 H -0.0917 L -0.1104 -0.3873 C -0.1417 -0.3789 -0.1688 -0.3664 -0.1958 -0.3518 L -0.2875 -0.4165 L -0.4188 -0.2871 L -0.3521 -0.1952 C -0.3667 -0.1681 -0.3792 -0.1388 -0.3875 -0.1075 L -0.5 -0.0908 V 0.0929 L -0.3875 0.1117 C -0.3792 0.143 -0.3667 0.1701 -0.3521 0.1973 L -0.4188 0.2912 L -0.2896 0.4207 L -0.1958 0.3539 C -0.1688 0.3685 -0.1396 0.381 -0.1083 0.3894 L -0.0896 0.5 H 0.0938 L 0.1125 0.3873 C 0.1417 0.3789 0.1708 0.3664 0.1979 0.3518 L 0.2917 0.4186 L 0.4208 0.2891 L 0.3542 0.1952 C 0.3688 0.1681 0.3812 0.1409 0.3896 0.1096 L 0.5 0.0929 Z M 0.3333 0 C 0.3333 0.1841 0.1841 0.3333 0 0.3333 C -0.1841 0.3333 -0.3333 0.1841 -0.3333 0 C -0.3333 -0.1841 -0.1841 -0.3333 0 -0.3333 C 0.1841 -0.3333 0.3333 -0.1841 0.3333 0 Z', '#7F7F7F') +Class.zephiGearOuter.CONTROLLERS = [["spin", { independent: true }]] +Class.zephiGearOuter.BORDERLESS = true +Class.zephiGearCentre = makeDeco(0, '#1F1F1F') +Class.zephiGearCentre.CONTROLLERS = [["spin", { independent: true }]] +Class.zephiGearCentre.BORDERLESS = true +Class.zephiGearRed = makeDeco('M -0.2667 0 C -0.2667 0.0074 -0.2664 0.0147 -0.2658 0.022 C -0.2651 0.0293 -0.2642 0.0366 -0.263 0.0439 C -0.2618 0.0511 -0.2603 0.0583 -0.2585 0.0655 C -0.2567 0.0726 -0.2546 0.0796 -0.2522 0.0866 C -0.2498 0.0935 -0.2472 0.1004 -0.2442 0.1071 C -0.2412 0.1139 -0.238 0.1205 -0.2345 0.1269 C -0.231 0.1334 -0.2273 0.1397 -0.2232 0.1459 C -0.2192 0.152 -0.2149 0.158 -0.2104 0.1638 C -0.2059 0.1696 -0.2012 0.1752 -0.1962 0.1806 C -0.1912 0.186 -0.186 0.1912 -0.1806 0.1962 C -0.1752 0.2012 -0.1696 0.2059 -0.1638 0.2104 C -0.158 0.215 -0.152 0.2192 -0.1458 0.2232 C -0.1397 0.2273 -0.1334 0.231 -0.1269 0.2345 C -0.1204 0.238 -0.1138 0.2413 -0.1071 0.2442 C -0.1032 0.2458 -0.1 0.2436 -0.1 0.2393 V -0.2393 C -0.1 -0.2436 -0.1032 -0.2458 -0.1071 -0.2442 C -0.1138 -0.2413 -0.1204 -0.238 -0.1269 -0.2345 C -0.1334 -0.231 -0.1397 -0.2273 -0.1458 -0.2232 C -0.152 -0.2192 -0.158 -0.215 -0.1638 -0.2104 C -0.1696 -0.2059 -0.1752 -0.2012 -0.1806 -0.1962 C -0.186 -0.1912 -0.1912 -0.186 -0.1962 -0.1806 C -0.2012 -0.1752 -0.2059 -0.1696 -0.2104 -0.1638 C -0.2149 -0.158 -0.2192 -0.152 -0.2232 -0.1458 C -0.2273 -0.1397 -0.231 -0.1334 -0.2345 -0.1269 C -0.238 -0.1205 -0.2412 -0.1138 -0.2442 -0.1071 C -0.2472 -0.1004 -0.2498 -0.0935 -0.2522 -0.0866 C -0.2546 -0.0796 -0.2567 -0.0726 -0.2585 -0.0655 C -0.2603 -0.0583 -0.2618 -0.0511 -0.263 -0.0439 C -0.2642 -0.0366 -0.2651 -0.0293 -0.2658 -0.022 C -0.2664 -0.0147 -0.2667 -0.0073 -0.2667 0 Z', '#FF1F1F') +Class.zephiGearRed.CONTROLLERS = [["spin", { independent: true }]] +Class.zephiGearRed.BORDERLESS = true +Class.zephiGearGreen = makeDeco('M 0.0771 -0.2552 C 0.0743 -0.2561 0.0691 -0.2576 0.0657 -0.2585 L 0.0607 -0.2597 C 0.0571 -0.2605 0.0514 -0.2617 0.0479 -0.2623 L 0.0428 -0.2632 C 0.0392 -0.2638 0.0334 -0.2646 0.0299 -0.265 L 0.0247 -0.2655 C 0.0211 -0.2659 0.0153 -0.2662 0.0117 -0.2664 L 0.0066 -0.2666 C 0.003 -0.2667 -0.0029 -0.2667 -0.0065 -0.2666 L -0.0116 -0.2664 C -0.0153 -0.2662 -0.0211 -0.2659 -0.0247 -0.2655 L -0.0298 -0.265 C -0.0334 -0.2646 -0.0392 -0.2638 -0.0427 -0.2632 L -0.0478 -0.2623 C -0.0514 -0.2617 -0.0571 -0.2605 -0.0606 -0.2597 L -0.0656 -0.2585 C -0.0691 -0.2576 -0.0747 -0.256 -0.0782 -0.2549 C -0.081 -0.254 -0.0833 -0.2502 -0.0833 -0.2466 V 0.2466 C -0.0833 0.2502 -0.0805 0.2541 -0.0771 0.2552 C -0.0743 0.2561 -0.0691 0.2576 -0.0656 0.2585 L -0.0606 0.2597 C -0.0571 0.2605 -0.0514 0.2617 -0.0478 0.2623 L -0.0427 0.2632 C -0.0392 0.2638 -0.0334 0.2646 -0.0298 0.265 L -0.0247 0.2655 C -0.0211 0.2659 -0.0153 0.2663 -0.0116 0.2664 L -0.0065 0.2666 C -0.0029 0.2667 0.003 0.2667 0.0066 0.2666 L 0.0117 0.2664 C 0.0153 0.2663 0.0211 0.2659 0.0247 0.2655 L 0.0299 0.265 C 0.0334 0.2646 0.0392 0.2638 0.0428 0.2632 L 0.0479 0.2623 C 0.0514 0.2617 0.0571 0.2605 0.0607 0.2597 L 0.0657 0.2585 C 0.0691 0.2576 0.0748 0.256 0.0782 0.2549 C 0.0811 0.254 0.0834 0.2502 0.0834 0.2466 V -0.2466 C 0.0834 -0.2502 0.0806 -0.2541 0.0771 -0.2552 Z', '#1FDF1F') +Class.zephiGearGreen.CONTROLLERS = [["spin", { independent: true }]] +Class.zephiGearGreen.BORDERLESS = true +Class.zephiGearBlue = makeDeco('M -0.2667 0 C -0.2667 0.0074 -0.2664 0.0147 -0.2658 0.022 C -0.2651 0.0293 -0.2642 0.0366 -0.263 0.0439 C -0.2618 0.0511 -0.2603 0.0583 -0.2585 0.0655 C -0.2567 0.0726 -0.2546 0.0796 -0.2522 0.0866 C -0.2498 0.0935 -0.2472 0.1004 -0.2442 0.1071 C -0.2412 0.1139 -0.238 0.1205 -0.2345 0.1269 C -0.231 0.1334 -0.2273 0.1397 -0.2232 0.1459 C -0.2192 0.152 -0.2149 0.158 -0.2104 0.1638 C -0.2059 0.1696 -0.2012 0.1752 -0.1962 0.1806 C -0.1912 0.186 -0.186 0.1912 -0.1806 0.1962 C -0.1752 0.2012 -0.1696 0.2059 -0.1638 0.2104 C -0.158 0.215 -0.152 0.2192 -0.1458 0.2232 C -0.1397 0.2273 -0.1334 0.231 -0.1269 0.2345 C -0.1204 0.238 -0.1138 0.2413 -0.1071 0.2442 C -0.1032 0.2458 -0.1 0.2436 -0.1 0.2393 V -0.2393 C -0.1 -0.2436 -0.1032 -0.2458 -0.1071 -0.2442 C -0.1138 -0.2413 -0.1204 -0.238 -0.1269 -0.2345 C -0.1334 -0.231 -0.1397 -0.2273 -0.1458 -0.2232 C -0.152 -0.2192 -0.158 -0.215 -0.1638 -0.2104 C -0.1696 -0.2059 -0.1752 -0.2012 -0.1806 -0.1962 C -0.186 -0.1912 -0.1912 -0.186 -0.1962 -0.1806 C -0.2012 -0.1752 -0.2059 -0.1696 -0.2104 -0.1638 C -0.2149 -0.158 -0.2192 -0.152 -0.2232 -0.1458 C -0.2273 -0.1397 -0.231 -0.1334 -0.2345 -0.1269 C -0.238 -0.1205 -0.2412 -0.1138 -0.2442 -0.1071 C -0.2472 -0.1004 -0.2498 -0.0935 -0.2522 -0.0866 C -0.2546 -0.0796 -0.2567 -0.0726 -0.2585 -0.0655 C -0.2603 -0.0583 -0.2618 -0.0511 -0.263 -0.0439 C -0.2642 -0.0366 -0.2651 -0.0293 -0.2658 -0.022 C -0.2664 -0.0147 -0.2667 -0.0073 -0.2667 0 Z', '#1F7FDF') +Class.zephiGearBlue.CONTROLLERS = [["spin", { independent: true }]] +Class.zephiGearBlue.BORDERLESS = true +Class.zephiBoss = { + PARENT: "miniboss", + LABEL: "Shiny Mecha-Thaumaturge", + NAME: "Zephi", + DANGER: 10, + SHAPE: 4, + COLOR: "lightGreen", + UPGRADE_COLOR: "lightGreen", + SIZE: 50, + VALUE: 5e6, + SKILL: skillSet({ + rld: 1, + dam: 1, + pen: 1, + str: 1, + spd: 1, + atk: 1, + hlt: 1, + shi: 1, + rgn: 1, + mob: 1, + }), + BODY: { + FOV: 0.75, + SPEED: 0.05 * base.SPEED, + HEALTH: 15 * base.HEALTH, + DAMAGE: 5 * base.DAMAGE, + }, + UPGRADE_TOOLTIP: "Good luck.", + GUNS: weaponArray([ + { + POSITION: [2.5, 3, 1.2, 8, 5, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, g.summoner, g.pounder, { speed: 2.5 }, g.machineGun, { spray: 50, speed: 1.25, shudder: 1.25 }]), + TYPE: ["zephiEggchip", {COLOR: "black"}], + MAX_CHILDREN: 8, + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "drone", + WAIT_TO_CYCLE: true, + COLOR: "black", + } + }, { + POSITION: [2.5, 3, 1.2, 8, -5, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, g.summoner, g.pounder, { speed: 2.5 }, g.machineGun, { spray: 150, speed: 1.25, shudder: 1.25 }]), + TYPE: ["zephiEggchip", {COLOR: "black"}], + MAX_CHILDREN: 8, + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "drone", + WAIT_TO_CYCLE: true, + COLOR: "black", + } + }, { + POSITION: [3.5, 8.65, 1.2, 8, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, g.summoner, g.destroyer, g.destroyer, { speed: 2.5 }, { maxSpeed: 3 }]), + TYPE: ["zephiSunchip", {COLOR: "black"}], + MAX_CHILDREN: 4, + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "drone", + WAIT_TO_CYCLE: true + } + } + ], 4), + TURRETS: [{ + POSITION: [16 * Math.SQRT1_2, 0, 0, 0, 360, 2], + TYPE: "zephiGearOuter" + },{ + POSITION: [5.375 * Math.SQRT1_2, 0, 0, 0, 360, 2], + TYPE: "zephiGearCentre" + },{ + POSITION: [16 * Math.SQRT1_2, 0, 0, 0, 360, 2], + TYPE: "zephiGearRed" + },{ + POSITION: [16 * Math.SQRT1_2, 0, 0, 0, 360, 2], + TYPE: "zephiGearGreen" + },{ + POSITION: [16 * Math.SQRT1_2, 0, 0, 180, 360, 2], + TYPE: "zephiGearBlue" + },{ + POSITION: [20 * Math.SQRT1_2, 0, 0, 45, 0, 1], + TYPE: "overdriveDeco" + },{ + POSITION: [20 * Math.SQRT1_2 ** 2, 0, 0, 0, 0, 1], + TYPE: "zephiMiscDeco2" + },{ + POSITION: [20 * Math.SQRT1_2 ** 3, 0, 0, 45, 0, 1], + TYPE: "zephiMiscDeco" + }] +}; + +Class.dogeiscutBody = { + PARENT: "genericTank", + COLOR: "grey", + SHAPE: [[1,0],[-0.7,0.7],[-0.35,0],[-0.7,-0.7]] +} +Class.dogeiscutTurret = { + PARENT: "genericTank", + COLOR: "grey", + GUNS: [ { + POSITION: [ 50, 5, 2.5, 0, 0, 0, 0, ], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.assassin, g.minigun, {reload: 0.1}]), + TYPE: "bullet", + }, + }, { + POSITION: [ 18, 8, -2, 0, 0, 0, 0, ], + }, + ], + TURRETS: [ + { + POSITION: [16, 0, 0, 0, 360, 1], + TYPE: ["genericTank", { MIRROR_MASTER_ANGLE: true, COLOR: "#f6c6a2"}], + }, + { + POSITION: [12, 0, 0, 0, 360, 1], + TYPE: ["genericTank", { MIRROR_MASTER_ANGLE: true, COLOR: "pink"}], + }, + ] +} +function createDogeiscutMissileTurret(color) { + return { + PARENT: "genericTank", + COLOR: "grey", + GUNS: [ { + POSITION: [ 15, 8, 2.5, 0, 0, 180, 0, ], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([ + g.basic, + g.skimmer, + { reload: 0.5 }, + g.lowPower, + { recoil: 1.35 }, + { speed: 1.3, maxSpeed: 1.3 }, + { speed: 1.3, maxSpeed: 1.3 }, + {reload: 0.15, recoil: 1, range: 0.1}]), + TYPE: ["bullet", + { + PERSISTS_AFTER_DEATH: true, + COLOR: color + }, + ], + AUTOFIRE: true, + STAT_CALCULATOR: "thruster", + }, + }, + ], + } +} +function createDogeiscutMissile(color) { + return { + PARENT: "bullet", + LABEL: color + " Missile", + COLOR: color, + GUNS: [...Array(11).fill().map((_, i)=>({ + POSITION: [0, 8, 0, 0, 0, ((360) / 11)*i, 9999], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.shotgun, g.noSpread, { recoil: 0, range: 0.4, damage: 2.5, density: 30 }]), + TYPE: ["bullet", { PERSISTS_AFTER_DEATH: true, COLOR: color }], + SHOOT_ON_DEATH: true, + }, + }))], + TURRETS: [ + { + POSITION: [16, 0, 0, 0, 360, 1], + TYPE: ["dogeiscutMissileTurret_" + color], + }, + { + POSITION: [12, 0, 0, 0, 360, 1], + TYPE: ["genericTank", {COLOR: "grey"}], + } + ] + } +} +Class.dogeiscutMissileTurret_red = createDogeiscutMissileTurret('red') +Class.dogeiscutMissile_red = createDogeiscutMissile('red') +Class.dogeiscutMissileTurret_orange = createDogeiscutMissileTurret('orange') +Class.dogeiscutMissile_orange = createDogeiscutMissile('orange') +Class.dogeiscutMissileTurret_yellow = createDogeiscutMissileTurret('yellow') +Class.dogeiscutMissile_yellow = createDogeiscutMissile('yellow') +Class.dogeiscutMissileTurret_green = createDogeiscutMissileTurret('green') +Class.dogeiscutMissile_green = createDogeiscutMissile('green') +Class.dogeiscutMissileTurret_cyan = createDogeiscutMissileTurret('cyan') +Class.dogeiscutMissile_cyan = createDogeiscutMissile('cyan') +Class.dogeiscutMissileTurret_blue = createDogeiscutMissileTurret('blue') +Class.dogeiscutMissile_blue = createDogeiscutMissile('blue') +Class.dogeiscutMissileTurret_purple = createDogeiscutMissileTurret('purple') +Class.dogeiscutMissile_purple = createDogeiscutMissile('purple') +Class.dogeiscutBomb = { + PARENT: "trap", + LABEL: "Bomb", + SHAPE: 0, + GUNS: [...Array(32).fill().map((_, i)=>({ + POSITION: [0, 8, 0, 0, 0, ((360) / 32)*i, 9999], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.shotgun, g.noSpread, { recoil: 0, range: 0.4, damage: 2.5, size: 0.5}]), + TYPE: ["bullet", { PERSISTS_AFTER_DEATH: true }], + SHOOT_ON_DEATH: true, + }, + })),...Array(10).fill().map((_,i)=>({ + POSITION: [12, 3.5, 1, 0, 0, (360/10)*i, (i%3)/3], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([ + g.basic, + g.twin, + g.gunner, + g.cyclone, + {reload: 3} + ]), + TYPE: "bullet", + AUTOFIRE: true, + }, + })) + ], + TURRETS: [ + { + POSITION: [8, 0, 0, 0, 360, 1], + TYPE: ["genericTank", {COLOR: "grey"}], + } + ] + } +Class.dogeiscutBoss = { + PARENT: "miniboss", + LABEL: "DOG", + NAME: "DogeisCut", + DANGER: 10, + FACING_TYPE: "smoothToTarget", + SHAPE: [[1,0],[-0.7,0.7],[-0.35,0],[-0.7,-0.7]], + COLOR: "yellow", + UPGRADE_COLOR: "yellow", + SIZE: 50, + VALUE: 5e6, + BODY: { + FOV: 0.75, + SPEED: 0.25 * base.SPEED, + HEALTH: 14 * base.HEALTH, + DAMAGE: 4 * base.DAMAGE, + }, + GUNS: [ { + POSITION: [ 6, 8, 1.5, 3, 0, 180, 0, ], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.destroyer, g.annihilator, {size: 1, reload: 3, recoil: 5}]), + TYPE: ["dogeiscutBomb"], + STAT_CALCULATOR: "sustained", + } + }, { + POSITION: [ 4, 4, 1.5, 3, 0, 180, 0, ], + PROPERTIES: { + COLOR: "black" + } + }, + + { + POSITION: [ 1, 2, 1, 4, -8, 68, 0, ], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.sidewinder, {speed: 3, range: 0.8, reload: 4}]), + TYPE: ["dogeiscutMissile_red"], + STAT_CALCULATOR: "sustained", + COLOR: 'red' + } + }, { + POSITION: [ 1, 2, 1, 4, -5.333, 68, 1/7, ], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.sidewinder, {speed: 3, range: 0.8, reload: 4}]), + TYPE: ["dogeiscutMissile_orange"], + STAT_CALCULATOR: "sustained", + COLOR: 'orange' + } + }, { + POSITION: [ 1, 2, 1, 4, -2.666, 68, (1/7)*2, ], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.sidewinder, {speed: 3, range: 0.8, reload: 4}]), + TYPE: ["dogeiscutMissile_yellow"], + STAT_CALCULATOR: "sustained", + COLOR: 'yellow' + } + }, { + POSITION: [ 1, 2, 1, 4, 0, 68, (1/7)*3, ], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.sidewinder, {speed: 3, range: 0.8, reload: 4}]), + TYPE: ["dogeiscutMissile_green"], + STAT_CALCULATOR: "sustained", + COLOR: 'green' + } + }, { + POSITION: [ 1, 2, 1, 4, 2.666, 68, (1/7)*4, ], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.sidewinder, {speed: 3, range: 0.8, reload: 4}]), + TYPE: ["dogeiscutMissile_cyan"], + STAT_CALCULATOR: "sustained", + COLOR: 'cyan' + } + }, { + POSITION: [ 1, 2, 1, 4, 5.333, 68, (1/7)*5, ], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.sidewinder, {speed: 3, range: 0.8, reload: 4}]), + TYPE: ["dogeiscutMissile_blue"], + STAT_CALCULATOR: "sustained", + COLOR: 'blue' + } + }, { + POSITION: [ 1, 2, 1, 4, 8, 68, (1/7)*6, ], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.sidewinder, {speed: 3, range: 0.8, reload: 4}]), + TYPE: ["dogeiscutMissile_purple"], + STAT_CALCULATOR: "sustained", + COLOR: 'purple' + } + }, + + + { + POSITION: [ 1, 2, 1, 4, 8, -68, 0, ], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.sidewinder, {speed: 3, range: 0.8, reload: 4}]), + TYPE: ["dogeiscutMissile_red"], + STAT_CALCULATOR: "sustained", + COLOR: 'red' + } + }, { + POSITION: [ 1, 2, 1, 4, 5.333, -68, 1/7, ], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.sidewinder, {speed: 3, range: 0.8, reload: 4}]), + TYPE: ["dogeiscutMissile_orange"], + STAT_CALCULATOR: "sustained", + COLOR: 'orange' + } + }, { + POSITION: [ 1, 2, 1, 4, 2.666, -68, (1/7)*2, ], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.sidewinder, {speed: 3, range: 0.8, reload: 4}]), + TYPE: ["dogeiscutMissile_yellow"], + STAT_CALCULATOR: "sustained", + COLOR: 'yellow' + } + }, { + POSITION: [ 1, 2, 1, 4, 0, -68, (1/7)*3, ], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.sidewinder, {speed: 3, range: 0.8, reload: 4}]), + TYPE: ["dogeiscutMissile_green"], + STAT_CALCULATOR: "sustained", + COLOR: 'green' + } + }, { + POSITION: [ 1, 2, 1, 4, -2.666, -68, (1/7)*4, ], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.sidewinder, {speed: 3, range: 0.8, reload: 4}]), + TYPE: ["dogeiscutMissile_cyan"], + STAT_CALCULATOR: "sustained", + COLOR: 'cyan' + } + }, { + POSITION: [ 1, 2, 1, 4, -5.333, -68, (1/7)*5, ], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.sidewinder, {speed: 3, range: 0.8, reload: 4}]), + TYPE: ["dogeiscutMissile_blue"], + STAT_CALCULATOR: "sustained", + COLOR: 'blue' + } + }, { + POSITION: [ 1, 2, 1, 4, -8, -68, (1/7)*6, ], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.sidewinder, {speed: 3, range: 0.8, reload: 4}]), + TYPE: ["dogeiscutMissile_purple"], + STAT_CALCULATOR: "sustained", + COLOR: 'purple' + } + }, + ], + TURRETS: [ + { + POSITION: [16, 0, 0, 0, 360, 1], + TYPE: ["dogeiscutBody", { MIRROR_MASTER_ANGLE: true, COLOR: "#f6c6a2"}], + }, + { + POSITION: [12, 0, 0, 0, 360, 1], + TYPE: ["dogeiscutBody", { MIRROR_MASTER_ANGLE: true, COLOR: "pink"}], + }, + { + POSITION: [5, 0, 0, 0, 360, 1], + TYPE: ["dogeiscutTurret", { INDEPENDENT: true, CONTROLLERS: ["nearestDifferentMaster"], COLOR: "yellow" }], + }, + { + POSITION: [1, 10.5, 0, 0, 360, 0], + TYPE: ["genericTank", {COLOR: "black"}], + }, + ] +} +Class.trplnrBossAuraBulletAura = addAura(1, 0.8) +Class.trplnrBossAuraBullet = { + PARENT: 'genericTank', + LABEL: 'Nest', + SHAPE: -4, + PERSISTS_AFTER_DEATH: true, + BODY: { + HEALTH: 100, + }, + SIZE: 25, + COLOR: '#F49EFF', + GLOW: { + STRENGTH: 25, + COLOR: 'mirror', + ALPHA: 1 + }, + DRAW_HEALTH: true, + GUNS: weaponArray({ + POSITION: { ASPECT: -0.35, X: -5 }, + PROPERTIES: { + COLOR: 'white', + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, { size: 0.8 }, {reload: 1.6, damage: 1.5}]), + TYPE: 'autoswarm', + AUTOFIRE: true, + }, + }, 4), + TURRETS: [ + { + POSITION: {SIZE: 10, LAYER: 1}, + TYPE: "trplnrBossAuraBulletAura" + } + ] +} +const trplnrBossDecor = { + COLOR: '#F49EFF', + UPGRADE_COLOR: "lavender", + LABEL: 'Lavender', + NAME: 'Trioplane', + SHAPE: 3, + SIZE: 25, + VALUE: 5e7, + DANGER: 10, + GLOW: { + RADIUS: 15, + COLOR: 'mirror', + ALPHA: 1, + RECURSION: 5 + }, + PROPS: [{ + POSITION: { SIZE: 25 ** Math.SQRT1_2, ANGLE: 180, LAYER: 1 }, + TYPE: ['triangle', { COLOR: 'black', MIRROR_MASTER_ANGLE: true }] + }, { + POSITION: { SIZE: 25 ** Math.SQRT1_2, LAYER: 1 }, + TYPE: ['triangle', { COLOR: -1, MIRROR_MASTER_ANGLE: true }] + }, { + POSITION: { SIZE: 25 }, + TYPE: ['triangle', { COLOR: 'black', MIRROR_MASTER_ANGLE: true }] + }], +} +Class.trplnrBoss = { + PARENT: "miniboss", + ...trplnrBossDecor, + UPGRADE_TOOLTIP: "\"Heck, even The Guardians are afraid of him, \n" + + "They usually call him the The Light, Victory, Death and Ruler of the Pentagon Race a.k.a Lvndr. \n" + + "We don't know where his teleportation powers came from, \n" + + "He was secretive of it. \n" + + "Though some say there was an old script found at the Neutrality Point \n" + + "at the middle of the nest when it still existed, It had some \n" + + "sort of drawing of a tank going through walls, and this thing that said '6@D M0|)3 \n" + + "Nest Reseachers still haven't been able to decipher it though. \n" + + "One day, The Neutrality Point left and on that same day, \n" + + "A sentry's child went missing, \n" + + "Coincidence? I think not.\"", + BODY: { + HEALTH: 500, + }, + ON: [ + { + event: 'fire', + handler: ({ body, gun }) => { + if (gun.identifier != 'onHandler') return + const messages = [ + 'Attack my little swarms!', + 'Deploying, Attack swarms', + 'You really think you can defeat me? Heres a little challenge for you.', + 'This thing is really gonna annoy you HAHA!', + 'I don\'t know what to say uhhh, die i guess.' + ] + sockets.broadcast(messages[Math.floor(Math.random() * messages.length)]) + sockets.broadcast('Lavender will turn into `BULL3T HELL F0rM`, Run!') + for (let i = 0; i < 24; i++) { + i < 12 ? + setTimeout(() => { body.SIZE /= 1.1; body.alpha /= 1.2 }, i * 50) + : + setTimeout(() => { body.SIZE *= 1.1; body.alpha *= 1.2 }, i * 50) + } + setTimeout(() => { + let range = 500 + let whereToGoX = Math.random() > 0.5 ? Math.floor(Math.random() * -range) : Math.floor(Math.random() * range) + let whereToGoY = Math.random() > 0.5 ? Math.floor(Math.random() * -range) : Math.floor(Math.random() * range) + body.x += whereToGoX + body.y += whereToGoY + }, 12 * 50); + setTimeout(() => body.define('trplnrBossBulletHellForm'), 24 * 50) + } + } + ], + GUNS: [ + ...weaponArray({ + POSITION: { WIDTH: 10, X: -5, ASPECT: -0.7, ANGLE: 180 }, + PROPERTIES: { + COLOR: 'white', + SHOOT_SETTINGS: combineStats([g.basic, {reload: 100}]), + TYPE: "trplnrBossAuraBullet", + INDEPENDENT_CHILDREN: true, + } + }, 2), + { + POSITION: { WIDTH: 10, X: -5, ASPECT: -0.7, ANGLE: 60 }, + PROPERTIES: { + COLOR: 'white', + SHOOT_SETTINGS: combineStats([g.basic, {reload: 100}]), + TYPE: "trplnrBossAuraBullet", + INDEPENDENT_CHILDREN: true, + IDENTIFIER: 'onHandler', + ALPHA: 0, + } + }, + ...weaponArray({ + POSITION: { WIDTH: 5, ASPECT: -0.7, ANGLE: 60 }, + PROPERTIES: { + COLOR: 'black' + } + }, 3), + ...weaponArray([ + { + POSITION: { WIDTH: 5, HEIGHT: 5, X: -30, ASPECT: 0, ANGLE: 60 }, + PROPERTIES: { + COLOR: 'black' + } + }, { + POSITION: { WIDTH: 5, HEIGHT: 5, X: -25, ASPECT: 0, ANGLE: 60 }, + PROPERTIES: { + COLOR: 'white' + } + } + ], 3) + ] +} + +Class.trplnrBossBulletHellFormPentagonsAuraBullet = { + PARENT: 'bullet', + PERSISTS_AFTER_DEATH: true, + TURRETS: [{ + POSITION: {SIZE: 13, LAYER: 1}, + TYPE: "trplnrBossAuraBulletAura" + }] +} + +Class.trplnrBossBulletHellFormPentagons = { + PARENT: 'bullet', + LABEL: 'Pentagon', + SHAPE: -5, + PROPS: [{ + POSITION: { SIZE: 40 ** Math.SQRT1_2, ANGLE: 180, LAYER: 1 }, + TYPE: ['pentagon', {COLOR: 'black', MIRROR_MASTER_ANGLE: true}] + }], + GUNS: weaponArray({ + POSITION: { WIDTH: 10, HEIGHT: 10, ANGLE: 180, DELAY: 11.5 }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, {reload: 0.4}]), + TYPE: 'trplnrBossBulletHellFormPentagonsAuraBullet', + AUTOFIRE: true, + COLOR: 'white', + } + }, 5) +} +Class.trplnrBossBulletHellForm = { + PARENT: "miniboss", + ...trplnrBossDecor, + LABEL: 'Lavender - Bullet Hell Form', + BODY: { + HEALTH: 500, + }, + ON: [ + { + event: "fire", + handler: ({ body, masterStore, gun }) => { + if (gun.identifier != 'onHandler') return + masterStore.shotsFired ??= 0 + masterStore.shotsFired++ + + for (let i = 0; i < 24; i++) { + i < 12 ? + setTimeout(() => { body.SIZE /= 1.1; body.alpha /= 1.2 }, i * 50) + : + setTimeout(() => { body.SIZE *= 1.1; body.alpha *= 1.2 }, i * 50) + } + setTimeout(() => { + let range = 500 + let whereToGoX = Math.random() > 0.5 ? Math.floor(Math.random() * -range) : Math.floor(Math.random() * range) + let whereToGoY = Math.random() > 0.5 ? Math.floor(Math.random() * -range) : Math.floor(Math.random() * range) + body.x += whereToGoX + body.y += whereToGoY + }, 12 * 50) + + if (masterStore.shotsFired > 5) { + body.define('trplnrBossVulnerableForm') + const messages = [ + 'I\'m a little tired right now', + 'Ouch my leg!', + 'i sleep', + 'Bruh my keyboard isn\'t working', + 'Omg bruh I chose the wrong form' + ] + sockets.broadcast(messages[Math.floor(Math.random() * messages.length)]) + sockets.broadcast('Lavender is in its `VULN3RABLE F0RM`, Attack!') + } + } + } + ], + GUNS: [ + ...weaponArray([ + { + POSITION: { WIDTH: 15, HEIGHT: 5, ANGLE: 180, ASPECT: 0, X: -25 }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.destroyer, g.annihilator, { reload: 1 }]), + TYPE: 'trplnrBossBulletHellFormPentagonsAuraBullet', + COLOR: 'black' + } + }, { + POSITION: { WIDTH: 15, HEIGHT: 5, ANGLE: 180, ASPECT: 0, X: -20 }, + PROPERTIES: { + COLOR: 'white' + } + }, { + POSITION: { WIDTH: 10, HEIGHT: 5, ASPECT: 1.5, ANGLE: 180 }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.destroyer, g.annihilator, { reload: 3 }]), + TYPE: 'trplnrBossBulletHellFormPentagons', + COLOR: 'white' + } + }, { + POSITION: { WIDTH: 8, HEIGHT: 3, X: -1, ASPECT: 1.5, ANGLE: 180 }, + PROPERTIES: { + COLOR: 'pureWhite', + } + }, { + POSITION: { WIDTH: 5, HEIGHT: 10, X: 5, ASPECT: 0.2, ANGLE: 180 }, + PROPERTIES: { + COLOR: -1, + } + } + ], 3), + { + POSITION: { WIDTH: 0, HEIGHT: 0 }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.destroyer, g.annihilator, { reload: 2 }, g.fake]), + TYPE: 'bullet', + IDENTIFIER: 'onHandler', + ALPHA: 0 + } + } + ], +} +Class.trplnrBossVulnerableForm = { + PARENT: "miniboss", + ...trplnrBossDecor, + LABEL: 'Lavender - Vulnerable Form', + BODY: { + HEALTH: 500, + SPEED: 0.1 + }, + ON: [ + { + event: "tick", + handler: ({ body }) => { + body.store.ticks ??= 0 + body.store.ticks++ + const spawnCrashers = body.store.ticks % 3 == 0 + const spawnSentries = body.store.ticks % 60 == 0 + const sentries = ["sentrySwarm", "sentryGun", "sentryTrap"] + if (spawnCrashers) new Entity(body, body).define("crasher") + if (spawnSentries) new Entity(body, body).define(sentries[Math.floor(Math.random() * sentries.length)]) + } + }, + { + event: "fire", + handler: ({ body, gun }) => { + if (gun.identifier != 'onHandler') return + setTimeout(() => { + body.define('trplnrBoss') + sockets.broadcast('im awake') + }, 15000) + setTimeout(() => sockets.broadcast('Lavender will activate in 10 seconds and turn into S4nctuary F0rM'), 5000) + } + } + ], + GUNS: [{ + POSITION: {LENGTH: 0, WIDTH: 0}, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, {reload: 500}]), + TYPE: 'bullet', + AUTOFIRE: true, + IDENTIFIER: 'onHandler', + ALPHA: 0 + } + }] +} + +Class.frostAuraSmall = { + PARENT: "aura", + LAYER: 30, + FACING_TYPE: ["spin", {speed: -0.04}], + BORDERLESS: true, + SHAPE: "M 1 0 L 0.715 0.519 L 0.309 0.951 L -0.273 0.84 L -0.809 0.588 L -0.883 0 L -0.809 -0.588 L -0.273 -0.84 L 0.309 -0.951 L 0.715 -0.519 L 1 0", + TURRETS: [{ + POSITION: [20, 0, 0, 0, 0, 1], + TYPE: 'frostAuraSmallOutline' + }] +} +Class.frostAuraSmallOutline = { + PARENT: "aura", + MIRROR_MASTER_ANGLE: true, + DRAW_FILL: false, + SHAPE: "M 1 0 L 0.715 0.519 L 0.309 0.951 L -0.273 0.84 L -0.809 0.588 L -0.883 0 L -0.809 -0.588 L -0.273 -0.84 L 0.309 -0.951 L 0.715 -0.519 L 1 0" + + "L 0.309 0.951 L -0.809 0.588 L -0.809 -0.588 L 0.309 -0.951 L 1 0" + + "L 0 0 L 0.309 0.951 M 0 0 L -0.809 0.588 M 0 0 L -0.809 -0.588 M 0 0 L 0.309 -0.951", +} +Class.frostAuraLarge = { + PARENT: "aura", + LAYER: 30, + FACING_TYPE: ["spin", {speed: -0.04}], + BORDERLESS: true, + SHAPE: "M 1 0 L 0.988 0.156 L 0.951 0.309 L 0.891 0.454 L 0.809 0.588 L 0.707 0.707 L 0.588 0.809 L 0.454 0.891 L 0.309 0.951 L 0.156 0.988 L 0 1 L -0.156 0.988 L -0.309 0.951 L -0.454 0.891 L -0.588 0.809 L -0.707 0.707 L -0.809 0.588 L -0.891 0.454 L -0.951 0.309 L -0.988 0.156 L -1 0 L -0.988 -0.156 L -0.951 -0.309 L -0.891 -0.454 L -0.809 -0.588 L -0.707 -0.707 L -0.588 -0.809 L -0.454 -0.891 L -0.309 -0.951 L -0.156 -0.988 L 0 -1 L 0.156 -0.988 L 0.309 -0.951 L 0.454 -0.891 L 0.588 -0.809 L 0.707 -0.707 L 0.809 -0.588 L 0.891 -0.454 L 0.951 -0.309 L 0.988 -0.156 L 1 0", + TURRETS: [{ + POSITION: [20, 0, 0, 0, 0, 1], + TYPE: 'frostAuraLargeOutline' + }] +} +Class.frostAuraLargeOutline = { + PARENT: "aura", + MIRROR_MASTER_ANGLE: true, + DRAW_FILL: false, + SHAPE: "M 1 0 L 0.988 0.156 L 0.951 0.309 L 0.891 0.454 L 0.809 0.588 L 0.707 0.707 L 0.588 0.809 L 0.454 0.891 L 0.309 0.951 L 0.156 0.988 L 0 1 L -0.156 0.988 L -0.309 0.951 L -0.454 0.891 L -0.588 0.809 L -0.707 0.707 L -0.809 0.588 L -0.891 0.454 L -0.951 0.309 L -0.988 0.156 L -1 0 L -0.988 -0.156 L -0.951 -0.309 L -0.891 -0.454 L -0.809 -0.588 L -0.707 -0.707 L -0.588 -0.809 L -0.454 -0.891 L -0.309 -0.951 L -0.156 -0.988 L 0 -1 L 0.156 -0.988 L 0.309 -0.951 L 0.454 -0.891 L 0.588 -0.809 L 0.707 -0.707 L 0.809 -0.588 L 0.891 -0.454 L 0.951 -0.309 L 0.988 -0.156 L 1 0" + + "M 0.988 -0.156 L 0.988 0.156 L 0.891 0.454 L 0.707 0.707 L 0.454 0.891 L 0.156 0.988 L -0.156 0.988 L -0.454 0.891 L -0.707 0.707 L -0.891 0.454 L -0.988 0.156 L -0.988 -0.156 L -0.891 -0.454 L -0.707 -0.707 L -0.454 -0.891 L -0.156 -0.988 L 0.156 -0.988 L 0.454 -0.891 L 0.707 -0.707 L 0.891 -0.454 L 0.988 -0.156 L 0.949 0" + + "L 0.988 0.156 L 0.891 0.256 L 0.891 0.454 L 0.739 0.537 L 0.707 0.707 L 0.519 0.769 L 0.454 0.891 L 0.293 0.902 L 0.156 0.988 L 0.032 0.927 L -0.156 0.988 L -0.282 0.869 L -0.454 0.891 L -0.571 0.731 L -0.707 0.707 L -0.768 0.558 L -0.891 0.454 L -0.871 0.317 L -0.988 0.156 L -0.914 0 L -0.988 -0.156 L -0.871 -0.317 L -0.891 -0.454 L -0.768 -0.558 L -0.707 -0.707 L -0.571 -0.731 L -0.454 -0.891 L -0.282 -0.869 L -0.156 -0.988 L 0.032 -0.927 L 0.156 -0.988 L 0.293 -0.902 L 0.454 -0.891 L 0.519 -0.769 L 0.707 -0.707 L 0.739 -0.537 L 0.891 -0.454 L 0.891 -0.256 L 0.988 -0.156 L 0.949 0" + + "L 0.891 0.256 L 0.739 0.537 L 0.519 0.769 L 0.293 0.902 L 0.032 0.927 L -0.282 0.869 L -0.571 0.731 L -0.768 0.558 L -0.871 0.317 L -0.914 0 L -0.871 -0.317 L -0.768 -0.558 L -0.571 -0.731 L -0.282 -0.869 L 0.032 -0.927 L 0.293 -0.902 L 0.519 -0.769 L 0.739 -0.537 L 0.891 -0.256 L 0.949 0" + + "M 0.834 0 L 0.891 0.256 L 0.704 0.291 L 0.739 0.537 L 0.495 0.579 L 0.519 0.769 L 0.258 0.793 L 0.032 0.927 L -0.06 0.759 L -0.282 0.869 L -0.398 0.649 L -0.571 0.731 L -0.674 0.49 L -0.871 0.317 L -0.741 0.178 L -0.914 0 L -0.741 -0.178 L -0.871 -0.317 L -0.674 -0.49 L -0.571 -0.731 L -0.398 -0.649 L -0.282 -0.869 L -0.06 -0.759 L 0.032 -0.927 L 0.258 -0.793 L 0.519 -0.769 L 0.495 -0.579 L 0.739 -0.537 L 0.704 -0.291 L 0.891 -0.256 L 0.834 0" + + "L 0.704 0.291 L 0.495 0.579 L 0.258 0.793 L -0.06 0.759 L -0.398 0.649 L -0.674 0.49 L -0.741 0.178 L -0.741 -0.178 L -0.674 -0.49 L -0.398 -0.649 L -0.06 -0.759 L 0.258 -0.793 L 0.495 -0.579 L 0.704 -0.291 L 0.834 0" + + "M 0.592 0 L 0.704 0.291 L 0.413 0.3 L 0.495 0.579 L 0.183 0.563 L -0.06 0.759 L -0.158 0.485 L -0.398 0.649 L -0.479 0.348 L -0.741 0.178 L -0.51 0 L -0.741 -0.178 L -0.479 -0.348 L -0.398 -0.649 L -0.158 -0.485 L -0.06 -0.759 L 0.183 -0.563 L 0.495 -0.579 L 0.413 -0.3 L 0.704 -0.291 L 0.592 0" + + "L 0.413 0.3 L 0.183 0.563 L -0.158 0.485 L -0.479 0.348 L -0.51 0 L -0.479 -0.348 L -0.158 -0.485 L 0.183 -0.563 L 0.413 -0.3 L 0.592 0" + + "M 0.292 0 L 0.413 0.3 L 0.09 0.277 L -0.158 0.485 L -0.236 0.171 L -0.51 0 L -0.236 -0.171 L -0.158 -0.485 L 0.09 -0.277 L 0.413 -0.3 L 0.292 0 L 0.09 0.277" + + "L -0.236 0.171 L -0.236 -0.171 L 0.09 -0.277 L 0.292 0 M 0 0 L 0.949 0" + + "M 0 0 L 0.293 0.902 M 0 0 L -0.768 0.558 M 0 0 L -0.768 -0.558 M 0 0 L 0.293 -0.902", +} +Class.frostAuraSymbol = { + PARENT: "genericTank", + CONTROLLERS: [["spin", { speed: -0.04 }]], + INDEPENDENT: true, + BORDERLESS: true, + COLOR: 'teal', + SHAPE: "M 1 0 L 0.797 0.46 L 0.5 0.866 L 0 0.92 L -0.5 0.866 L -0.797 0.46 L -1 0 L -0.797 -0.46 L -0.5 -0.866 L 0 -0.92 L 0.5 -0.866 L 0.797 -0.46 L 1 0 Z", + TURRETS: [{ + POSITION: [20, 0, 0, 0, 0, 1], + TYPE: 'frostAuraSymbolOutline' + }] +} +Class.frostAuraSymbolOutline = { + PARENT: "genericTank", + MIRROR_MASTER_ANGLE: true, + DRAW_FILL: false, + SHAPE: "M 1 0 L 0.797 0.46 L 0.5 0.866 L 0 0.92 L -0.5 0.866 L -0.797 0.46 L -1 0 L -0.797 -0.46 L -0.5 -0.866 L 0 -0.92 L 0.5 -0.866 L 0.797 -0.46 L 1 0 Z" + + "M 0.52 0.3 L 0.52 -0.3 L 0.797 -0.46 M 0.52 -0.3 L 0 -0.6 L 0 -0.92 M 0 -0.6 L -0.52 -0.3 L -0.797 -0.46 M -0.52 -0.3 L -0.52 0.3 L -0.797 0.46 M -0.52 0.3 L 0 0.6 L 0 0.92 M 0 0.6 L 0.52 0.3 L 0.797 0.46" +} + +function addIcosphereAura(damageFactor = 1, sizeFactor = 1, opacity = 0.3, auraSize = "Medium") { + let auraType = "frostAura" + auraSize; + return { + PARENT: "genericTank", + INDEPENDENT: true, + LABEL: "", + COLOR: 17, + GUNS: [ + { + POSITION: [0, 20, 1, 0, 0, 0, 0,], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.aura, { size: sizeFactor, damage: damageFactor }]), + TYPE: [auraType, {ALPHA: opacity}], + MAX_CHILDREN: 1, + AUTOFIRE: true, + SYNCS_SKILLS: true, + }, + }, + ], + TURRETS: [ + { + POSITION: [20, 0, 0, 0, 360, 1], + TYPE: "frostAuraSymbol" + }, + ] + }; +} +Class.frostAuraBlockTop = { + SHAPE: "M -1.3 -0.15 L -1.3 0.15 L -0.3 0.3 L -0.15 1.3 L 0.15 1.3 L 0.3 0.3 L 1.3 0.15 L 1.3 -0.15 L 0.3 -0.3 L 0.15 -1.3 L -0.15 -1.3 L -0.3 -0.3 Z", + COLOR: { BASE: 17, BRIGHTNESS_SHIFT: 5 }, + MIRROR_MASTER_ANGLE: true, +} +Class.frostAuraBlockTurret = { + PARENT: "genericTank", + INDEPENDENT: true, + COLOR: 17, + CONTROLLERS: ["nearestDifferentMaster"], + LABEL: "", + BODY: { + FOV: 2, + }, + HAS_NO_RECOIL: true, + GUNS: [ + { + POSITION: [18, 15, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minionGun, g.turret, g.power, g.autoTurret, g.fake]), + TYPE: "bullet", + COLOR: {BASE: 17, BRIGHTNESS_SHIFT: -7.5} + }, + }, { + POSITION: [23, 11, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minionGun, g.turret, g.power, g.autoTurret, {density: 0.2}]), + TYPE: "bullet", + COLOR: {BASE: -1, BRIGHTNESS_SHIFT: -10, SATURATION_SHIFT: 0.6} + }, + }, { + POSITION: [15, 13, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minionGun, g.turret, g.power, g.autoTurret, g.fake]), + TYPE: "bullet", + COLOR: {BASE: 17, BRIGHTNESS_SHIFT: 7.5} + }, + }, + ], +} +Class.frostAuraBlockAura = addIcosphereAura(0.25, 1.6, 0.15, "Small"); +Class.frostAuraBlock = { + PARENT: 'unsetTrap', + TURRETS: [ + { + POSITION: [20, 0, 0, 45, 0, 1], + TYPE: 'frostAuraBlockTop' + }, { + POSITION: [11, 0, 0, 0, 360, 1], + TYPE: 'frostAuraBlockTurret' + }, { + POSITION: [10, 0, 0, 0, 360, 1], + TYPE: 'frostAuraBlockAura' + } + ] +} +Class.frostBossBigAura = addIcosphereAura(1.5, 1.45, 0.3, "Large"); + +Class.frostBossAutoTurret = { + PARENT: "autoTankGun", + INDEPENDENT: true, + COLOR: 17, + GUNS: [ + { + POSITION: [17, 14, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.autoTurret, {recoil: 0.1}, g.fake]), + TYPE: "bullet", + COLOR: {BASE: 17, BRIGHTNESS_SHIFT: -7.5} + }, + }, { + POSITION: [22, 10, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.autoTurret, {recoil: 0.1}]), + TYPE: "bullet", + COLOR: {BASE: -1, BRIGHTNESS_SHIFT: -10, SATURATION_SHIFT: 0.6} + }, + }, { + POSITION: [14, 12, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.autoTurret, {recoil: 0.1}, g.fake]), + TYPE: "bullet", + COLOR: {BASE: 17, BRIGHTNESS_SHIFT: 7.5} + }, + }, + ], + TURRETS: [ + { + POSITION: [13, 0, 0, 0, 0, 1], + TYPE: ["egg", {COLOR: -1, BORDERLESS: true}], + }, + ], +} + +Class.frostBossBaseDeco = { + SHAPE: "M -1.1 0 L -0.956 0.292 L -0.669 0.205 L -0.669 -0.205 L -0.956 -0.292 Z" + + "M -0.55 0.952 L -0.225 0.974 L -0.157 0.682 L -0.512 0.477 L -0.731 0.682 Z" + + "M -0.55 -0.952 L -0.225 -0.974 L -0.157 -0.682 L -0.512 -0.477 L -0.731 -0.682 Z" + + "M 0.55 0.952 L 0.225 0.974 L 0.157 0.682 L 0.512 0.477 L 0.731 0.682 Z" + + "M 0.55 -0.952 L 0.225 -0.974 L 0.157 -0.682 L 0.512 -0.477 L 0.731 -0.682 Z" + + "M 1.1 0 L 0.956 0.292 L 0.669 0.205 L 0.669 -0.205 L 0.956 -0.292 Z", + COLOR: { BASE: 17, BRIGHTNESS_SHIFT: 2.5 }, + MIRROR_MASTER_ANGLE: true, + GUNS: weaponArray([ + { + POSITION: [1.75, 3, -0.75, 7.5, 0, 0, 0], + PROPERTIES: { COLOR: { BASE: -1, BRIGHTNESS_SHIFT: 2.5, SATURATION_SHIFT: 0.9 }, DRAW_ABOVE: true }, + }, { + POSITION: [1, 9, 0, 8.5, 0, 30, 0], + PROPERTIES: { COLOR: { BASE: -1, BRIGHTNESS_SHIFT: 10, SATURATION_SHIFT: 1.15 } }, + }, + ], 6) +} +Class.frostBossBaseDeco2 = { + COLOR: {BASE: -1, BRIGHTNESS_SHIFT: 7.5}, + GUNS: weaponArray([ + { + POSITION: [5, 10, 0.001, 9.5, 0, 0, 0], + PROPERTIES: {COLOR: {BASE: 9, BRIGHTNESS_SHIFT: 10}}, + }, { + POSITION: [1.6, 9, 0, 8.4, 0, 0, 0], + PROPERTIES: {COLOR: {BASE: 9, BRIGHTNESS_SHIFT: 10}, DRAW_ABOVE: true}, + }, + ], 6), +} + +const trebuchetStats = [g.basic, g.sniper, g.predator, g.predator, g.predator, g.predator, {speed: 0.93, maxSpeed: 0.93, reload: 2, health: 1.7, damage: 1.4, size: 2}]; +const hielamanStats = [g.trap, g.setTrap, g.hexaTrapper, {reload: 2.85, health: 3.2, range: 1.2}]; +Class.frostBoss = { + PARENT: 'miniboss', + LABEL: 'Extrasolar', + NAME: 'Frostbyte', + CONTROLLERS: [["minion", {orbit: 260, leash: 190, repel: 270}]], + FACING_TYPE: 'toTarget', + SHAPE: 6, + COLOR: "aqua", + UPGRADE_COLOR: "aqua", + SIZE: 31, + DANGER: 12, + VALUE: 888888, + UPGRADE_TOOLTIP: "\"When the golden rays of sun shine through this world's\n" + + "darkened skies and looming clouds, the legend of the warrior\n" + + "and his eternal blade will finally come to fruition.\"", + BODY: { + SPEED: base.SPEED * 0.6, + HEALTH: base.HEALTH * 11, + SHIELD: base.SHIELD * 7, + REGEN: base.REGEN * 2.5, + FOV: base.FOV * 1.4, + RESIST: base.RESIST * 1.2, + DENSITY: base.DENSITY * 7.5, + }, + GUNS: [ + ...weaponArray({ + // Speed + POSITION: [8, 14.5, 0.001, 9.5, 0, 0, 0], + PROPERTIES: {COLOR: 9}, + }, 6), + ...weaponArray([ + { // Heavy Snipers + POSITION: [26.5, 9.5, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats(trebuchetStats), + TYPE: "bullet", + COLOR: { BASE: -1, BRIGHTNESS_SHIFT: -15, SATURATION_SHIFT: 0.6 }, + }, + }, { + POSITION: [24, 6.65, -1.3, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([...trebuchetStats, g.fake]), + TYPE: "bullet", + COLOR: { BASE: -1, BRIGHTNESS_SHIFT: -5, SATURATION_SHIFT: 0.6 }, + BORDERLESS: true + }, + }, { + POSITION: [4.25, 9.5, -0.5, 1.425, -8.5, 90, 0], + PROPERTIES: { COLOR: { BASE: 17, BRIGHTNESS_SHIFT: 2.5 } }, + }, { + POSITION: [4.25, 9.5, -0.5, 1.425, 8.5, -90, 0], + PROPERTIES: { COLOR: { BASE: 17, BRIGHTNESS_SHIFT: 2.5 } }, + }, { + POSITION: [4.25, 6.65, -0.35, 0.67, -8.5, 90, 0], + PROPERTIES: { COLOR: { BASE: 17, BRIGHTNESS_SHIFT: 7.5 }, BORDERLESS: true }, + }, { + POSITION: [4.25, 6.65, -0.35, 0.67, 8.5, -90, 0], + PROPERTIES: { COLOR: { BASE: 17, BRIGHTNESS_SHIFT: 7.5 }, BORDERLESS: true }, + }, { + POSITION: [19.5, 3.8, -1.4, 0, 0, 0, 0], + PROPERTIES: { COLOR: { BASE: 17, BRIGHTNESS_SHIFT: 10 } }, + }, { + POSITION: [4, 11.5, 1, 19.5, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([...trebuchetStats, g.fake]), + TYPE: "bullet", + COLOR: { BASE: -1, BRIGHTNESS_SHIFT: -5, SATURATION_SHIFT: 0.6 }, + }, + }, { + POSITION: [2, 12, 1, 20.5, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([...trebuchetStats, g.fake]), + TYPE: "bullet", + COLOR: { BASE: 17, BRIGHTNESS_SHIFT: 2.5 }, + }, + }, + { // Aura Blocks + POSITION: [15, 8.5, 1, 0, 0, 60, 0], + PROPERTIES: {COLOR: {BASE: -1, BRIGHTNESS_SHIFT: -15, SATURATION_SHIFT: 0.6}} + }, { + POSITION: [4, 7, -1.6, 9, 0, 60, 0], + PROPERTIES: {COLOR: {BASE: 17, BRIGHTNESS_SHIFT: 5}} + }, { + POSITION: [3, 6, -1.55, 9, 0, 60, 0], + PROPERTIES: {COLOR: {BASE: 17, BRIGHTNESS_SHIFT: 12.5}, BORDERLESS: true} + }, { + POSITION: [15, 5.4, -0.1, 0, 0, 60, 0], + PROPERTIES: {COLOR: {BASE: -1, BRIGHTNESS_SHIFT: -5, SATURATION_SHIFT: 0.75}} + }, { + POSITION: [3, 8.5, 1.6, 15, 0, 60, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats(hielamanStats), + TYPE: 'frostAuraBlock', + STAT_CALCULATOR: "trap", + COLOR: {BASE: -1, BRIGHTNESS_SHIFT: -15, SATURATION_SHIFT: 0.6} + }, + }, { + POSITION: [2, 6, 1.6, 16, 0, 60, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([...hielamanStats, g.fake]), + TYPE: 'bullet', + COLOR: {BASE: 17, BRIGHTNESS_SHIFT: 7.5} + }, + }, + ], 3), + ], + TURRETS: [ + ...weaponArray({ + POSITION: [2.95, 8.55, 0, 30, 180, 2], + TYPE: "frostBossAutoTurret", + }, 6), + { + POSITION: [8.55, 0, 0, 0, 360, 2], + TYPE: "frostBossBigAura", + }, + ], + PROPS: [ + { + POSITION: [12, 0, 0, 180, 1], + TYPE: ["hexagon", {COLOR: {BASE: -1, BRIGHTNESS_SHIFT: 7.5}}], + }, { + POSITION: [12, 0, 0, 0, 1], + TYPE: "frostBossBaseDeco2" + }, { + POSITION: [20, 0, 0, 0, 1], + TYPE: "frostBossBaseDeco", + } + ] +} + +const divide = 1000; +const arraySize = 10; +const colorArray = []; +const damageMultiplayer = 3.5; +const reloadMultiplayer = 2; +for (let i = 0; i < arraySize; i++) { + const rgb = Math.round(255 * i / (arraySize - 1)); + colorArray.push('#' + ((1 << 24) + (rgb << 16) + (rgb << 8) + rgb).toString(16).slice(1)); +} +class io_nearestDifferentMaster2 extends ioTypes.nearestDifferentMaster { + constructor(body, opts = {}) { + super(body); + this.lookAtDanger = opts.lookAtDanger ?? true; + this.firingAtMe = opts.firingAtMe ?? false; + this.timeout = opts.timeout || 90; + } + buildList(range) { + // Establish whom we judge in reference to + let mostDangerous = 0, + keepTarget = false; + // Filter through everybody... + let out = entities.filter(e => + // Only look at those within our view, and our parent's view, not dead, not invisible, not our kind, not a bullet/trap/block etc + this.validate(e, this.body, this.body.master.master, range * range, range * range * 4 / 3) + ).filter((e) => { + // Only look at those within range and arc (more expensive, so we only do it on the few) + if (this.body.firingArc == null || this.body.aiSettings.view360 || Math.abs(util.angleDifference(util.getDirection(this.body, e), this.body.firingArc[0])) < this.body.firingArc[1]) { + mostDangerous = Math.max(e.dangerValue, mostDangerous); + return true; + } + }).filter((e) => { + // Even more expensive + return !this.wouldHitWall(this.body, e); + }).filter((e) => { + // Only return the highest tier of danger + if (!this.lookAtDanger) return true; + if (this.body.aiSettings.farm || e.dangerValue === mostDangerous) { + if (this.targetLock && e.id === this.targetLock.id) keepTarget = true; + return true; + } + }); + // Reset target if it's not in there + if (!keepTarget) this.targetLock = undefined; + return out; + } + think(input) { + // Override target lock upon other commands + if (input.main || input.alt || this.body.master.autoOverride) { + this.targetLock = undefined; + return {}; + } + // Otherwise, consider how fast we can either move to ram it or shoot at a potiential target. + let tracking = this.body.topSpeed, + damageRef = (this.body.bond == null) ? this.body : this.body.bond, + range = this.body.fov; + // Use whether we have functional guns to decide + for (let i = 0; i < this.body.guns.length; i++) { + if (this.body.guns[i].canShoot && !this.body.aiSettings.SKYNET) { + let v = this.body.guns[i].getTracking(); + if (v.speed == 0 || v.range == 0) continue; + tracking = v.speed; + range = Math.min(range, (v.speed || 1.5) * (v.range < (this.body.size * 2) ? this.body.fov : v.range)); + break; + } + } + if (!Number.isFinite(tracking)) { + tracking = this.body.topSpeed + .01; + } + if (!Number.isFinite(range)) { + range = 640 * this.body.FOV; + } + // Check if my target's alive + if (this.targetLock && ( + !this.validate(this.targetLock, this.body, this.body.master.master, range * range, range * range * 4 / 3) || + this.wouldHitWall(this.body, this.targetLock) // Very expensive + )) { + this.targetLock = undefined; + this.tick = 100; + } + // Think damn hard + if (this.tick++ > 15 * Config.runSpeed) { + this.tick = 0; + this.validTargets = this.buildList(range); + // Ditch our old target if it's invalid + if (this.targetLock && this.validTargets.indexOf(this.targetLock) === -1) { + this.targetLock = undefined; + } + // Lock new target if we still don't have one. + if (this.targetLock == null && this.validTargets.length) { + this.targetLock = (this.validTargets.length === 1) ? this.validTargets[0] : nearest(this.validTargets, { + x: this.body.x, + y: this.body.y + }); + this.tick = -this.timeout; + } + } + // Lock onto whoever's shooting me. + if (this.firingAtMe && damageRef.collisionArray.length && damageRef.health.display() < this.oldHealth) { + this.oldHealth = damageRef.health.display(); + if (this.validTargets.indexOf(damageRef.collisionArray[0]) === -1) { + let a = (damageRef.collisionArray[0].master.id === -1) + ? damageRef.collisionArray[0].source + : damageRef.collisionArray[0].master; + if ( + this.body.firingArc == null || + this.body.aiSettings.view360 || + Math.abs(util.angleDifference(util.getDirection(this.body, a), this.body.firingArc[0])) < this.body.firingArc[1] + ) { + this.targetLock = a; + this.tick = -(this.timeout * 5); + } + } + } + // Consider how fast it's moving and shoot at it + if (this.targetLock != null) { + let radial = this.targetLock.velocity; + let diff = { + x: this.targetLock.x - this.body.x, + y: this.targetLock.y - this.body.y, + } + /// Refresh lead time + if (this.tick % 4 === 0) { + this.lead = 0 + // Find lead time (or don't) + if (!this.body.aiSettings.chase) { + let toi = timeOfImpact(diff, radial, tracking) + this.lead = toi + } + } + if (!Number.isFinite(this.lead)) { + this.lead = 0; + } + if (!this.accountForMovement) this.lead = 0; + // And return our aim + return { + target: { + x: diff.x + this.lead * radial.x, + y: diff.y + this.lead * radial.y, + }, + fire: true, + main: true + }; + } + return {}; + } +} +ioTypes.nearestDifferentMaster2 = io_nearestDifferentMaster2; +Class.toothlessBase = { + PARENT: "genericTank", + LABEL: "NightFury", + UPGRADE_TOOLTIP: "A cute...", + GLOW: { + RADIUS: 2, + COLOR: 42, + ALPHA: 0.6, + RECURSION: 6, + }, + BODY: { + SPEED: 0.8 * base.SPEED, + FOV: 1.5 * base.FOV, + HEALTH: 6 * base.HEALTH, + DAMAGE: 2 * base.DAMAGE, + }, + LEVEL_CAP: 45, + EXTRA_SKILL: 78, // 120 - 42 + SHAPE: 3, + VALUE: 30e+3, + SIZE: 24, + COLOR: "purple", + SKILL_CAP: Array(10).fill(smshskl + 3), + LEVEL_SKILL_POINT_FUNCTION: level => { + if (level < 2) return 0; + if (level <= 40) return 1; + if (level <= 45 && level & 1 == 1) return 1; + return 0; + }, +} +Class.toothlessBossTurret = { + PARENT: "genericTank", + LABEL: "", + BODY: { + FOV: 3, + }, + CONTROLLERS: [ + "onlyAcceptInArc", + [ "nearestDifferentMaster2", { lookAtDanger: false, firingAtMe: true, timeout: 10 } ], + ], + COLOR: "grey", + GUNS: [ + { + POSITION: [32, 8, 1, 0, 0, 0, 0.4], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.assassin, { + pen: 0.8, + health: 0.6, + damage: 0.6, + recoil: 0, + }]), + TYPE: "bullet", + }, + }, + ], + ON: [{ + event: "fire", + handler: ({ body }) => { + const master = body.master; + body._damage ??= []; + body._reload ??= []; + + if (!body._loaded) { + let _temp = 0; + master._maxPower ??= 0; + + body.guns.forEach((gun, i) => { + body._damage[i] = gun.shootSettings.damage; + body._reload[i] = gun.shootSettings.reload; + + _temp += (body._damage[i] * 3) / body._damage[i]; + _temp += body._reload[i] / (body._reload[i] / 3); + _temp /= 2; + }); + + _temp /= body.guns.length; + + master._maxPower += (_temp - 1) * divide * 2; + if (master._maxPower > _temp) master._maxPower /= 2; + + body._loaded = true; + } + + if (master._mode) { + master._power -= 1; + if (master._power < 1) { + master._mode = 0; + master.color.base = 14; + } + } + + if (!master._oldPower) return; + const power = master._oldPower / (divide * 2) + 1; + + body.guns.forEach((gun, i) => { + let _1 = body._damage[i] * (master._mode ? power : 1); + let _2 = body._reload[i] / (master._mode ? power : 1); + let max_damage = body._damage[i] * damageMultiplayer; + let min_reload = body._reload[i] / reloadMultiplayer; + + gun.shootSettings.damage = _1 > max_damage ? max_damage : _1; + gun.shootSettings.reload = _2 < min_reload ? min_reload : _2; + }); + }, + }], +}; +Class.toothlessBossDeco = { + PARENT: "genericTank", + LABEL: "", + SHAPE: 3, + SIZE: 10, + ON: [{ + event: "tick", + handler: ({ body }) => { + const master = body.master; + if (master._maxPower) + body.color.base = colorArray[ + Math.floor(master._power / (master._maxPower / arraySize)) > arraySize - 1 + ? arraySize - 1 + : Math.floor(master._power / (master._maxPower / arraySize) + ) + ]; + }, + }], +}; +Class.toothlessBoss = { + PARENT: "toothlessBase", + UPGRADE_COLOR: "magenta", + TURRETS: [{ + POSITION: { SIZE: 15, LAYER: 1 }, + TYPE: ["toothlessBossDeco", { MIRROR_MASTER_ANGLE: true }], + }, { + POSITION: { SIZE: 23 }, + TYPE: ["triangle", { COLOR: "black", MIRROR_MASTER_ANGLE: true }], + }], + GUNS: [{ + POSITION: { LENGTH: 0, WIDTH: 0 }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([ g.basic, { + range: 0.1, + speed: 0.1, + maxSpeed: 0.1, + recoil: 0, + }]), + TYPE: "bullet", + ALT_FIRE: true, + }, + }], + ON: [{ + event: "altFire", + handler: ({ body }) => { + if (!body._power || body._mode) return; + const power = Math.floor(body._power); + + if (power >= 1) { + body._oldPower = body._power; + body._mode = 1; + body.color.base = 5; + } + }, + }, { + event: "kill", + handler: ({ body, entity }) => { + body._power ??= 0; + body._mode ??= 0; + if (!body._mode) body._power += (entity.skill.score / divide) ** 0.8; + }, + }], +} +Class.toothlessBoss.TURRETS = Class.toothlessBoss.TURRETS.concat(weaponArray([{ + POSITION: [8, 6, -5.6, 180, 180, 0], + TYPE: "toothlessBossTurret", +}, { + POSITION: [8, 6, 5.6, 180, 180, 0], + TYPE: "toothlessBossTurret", +}], 3)); + +Class.MKAura = addAura(5, 0, 0.1, 42); +Class.MKDoneAura = addAura(2, 1, 0.3, 32); +Class.MKFactoryAura = addAura(2.6, 1, 0.3, "trans"); +Class.MKCarrierAura = addAura(2.1, 1, 0.3, 1); +Class.MKMinionAura = addAura(1.1, 1, 0.3, 32); +Class.MKDrone = { + PARENT: "drone", + LABEL: "MKShip Drone", + TURRETS: [ + { + POSITION: [13, 0, 0, 0, 360, 1], + TYPE: "MKDoneAura", + }, + ] +} +Class.MKMinion = { + PARENT: "minion", + LABEL: "MKShip Minion", + TURRETS: [ + { + POSITION: [13, 0, 0, 0, 360, 1], + TYPE: "MKMinionAura", + }, + ] +} +Class.MKTurretFactoryWithController = { + PARENT: "MKTurretFactory", + CONTROLLERS: ["nearestDifferentMaster"], + INDEPENDENT: true, + BODY: { + FOV: 2, + }, + TURRETS: [ + { + POSITION: [13, 0, 0, 0, 360, 1], + TYPE: "MKFactoryAura", + }, + ] +} +Class.MKTurretFactory = { + PARENT: "genericTank", + LABEL: "MKTurret factory", + SKILL: [12, 12, 12, 12, 12, 12, 12, 12, 12, 12], + COLOR: 16, + IGNORED_BY_AI: true, + DAMAGE_EFFECTS: false, + GUNS: [ + { + POSITION: [5, 11, 1, 10.5, 0, 0, 0], + }, + { + POSITION: [2, 14, 1, 15.5, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.factory]), + TYPE: "MKMinion", + MAX_CHILDREN: 6, + AUTOFIRE: true, + SYNCS_SKILLS: true, + }, + }, + { + POSITION: [12, 14, 1, 0, 0, 0, 0], + }, + ], +} +Class.MKTurretCarrier = { + PARENT: "carrier", + FACING_TYPE: "toTarget", + LABEL: "MKTurret carrier", + SKILL: [12, 12, 12, 12, 12, 12, 12, 12, 12, 12], + COLOR: 16, + IGNORED_BY_AI: true, + DAMAGE_EFFECTS: false, +} +Class.MKTurretCarrierWithController = { + PARENT: "MKTurretCarrier", + CONTROLLERS: ["nearestDifferentMaster"], + INDEPENDENT: true, + BODY: { + FOV: 2, + }, + TURRETS: [ + { + POSITION: [13, 0, 0, 0, 360, 1], + TYPE: "MKCarrierAura", + }, + ] +} +Class.MKTurretThruster = { + PARENT: "genericTank", + LABEL: "MKTurret Thruster", + FACING_TYPE: "toTarget", + IGNORED_BY_AI: true, + DAMAGE_EFFECTS: false, + COLOR: 16, + GUNS: [{ + POSITION: [14, 12, 1, 4, 0, 180, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.machineGun, g.thruster, { range: 0.375, reload: 0.75, recoil: 1.05 }]), + TYPE: "bullet" + } + }, { + POSITION: [12, 12, 1.4, 4, 0, 180, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.machineGun, g.thruster, { range: 0.375, reload: 0.75, recoil: 1.05 }]), + TYPE: "bullet" + }, + }] +} +Class.MKTurret = { + PARENT: "genericTank", + FACING_TYPE: "toTarget", + IGNORED_BY_AI: true, + DAMAGE_EFFECTS: false, + LABEL: "MKTurret", + COLOR: 16, + SHAPE: 5, + SKILL: [12, 12, 12, 12, 12, 12, 12, 12, 12, 12], + TURRETS: [ + { + POSITION: [13, 0, 0, 0, 360, 1], + TYPE: "MKTurretFactory", + }, + { + POSITION: [10, 16.1, 2.6, 140, 180, 0], + TYPE: "MKTurretFactoryWithController", + }, + { + POSITION: [10, 16.1, 2.6, 203, 180, 0], + TYPE: "MKTurretFactoryWithController", + }, + { + POSITION: [10, 16.1, -3.9, 310, 180, 0], + TYPE: "MKTurretFactoryWithController", + }, + { + POSITION: [10, 16.1, 2.6, 413, 180, 0], + TYPE: "MKTurretFactoryWithController", + }, + { + POSITION: [10, 10.2, 0, 0, 360, 0], + TYPE: "MKTurretCarrier", + }, + { + POSITION: [10, 10.2, 0, 105.5, 180, 0], + TYPE: "MKTurretCarrierWithController", + }, + { + POSITION: [10, 10.2, 0, 180, 180, 0], + TYPE: "MKTurretCarrierWithController", + }, + { + POSITION: [10, 10.2, 0, 255, 180, 0], + TYPE: "MKTurretCarrierWithController", + }, + { + POSITION: [8, -10, -2, -45, 90, 0], + TYPE: "MKTurretThruster" + }, + { + POSITION: [8, -10, 2, 45, 90, 0], + TYPE: "MKTurretThruster" + }, + ], +} +Class.AEMKShipBoss = { + PARENT: "genericTank", + LABEL: "MKShip", + NAME: "Æ🚫Sports", + SYNC_WITH_TANK: true, + CONTROLLERS: ["nearestDifferentMaster", "minion"], + UPGRADE_TOOLTIP: "Has 4 carrier's, 4 factories, and their own auras. NOW FACE MY DESTRUCTION!", + COLOR: 32, + UPGRADE_COLOR: 32, + GLOW: { + RADIUS: 1.5, + COLOR: 32, + ALPHA: 0.9, + RECURSION: 3, + }, + DANGER: 10, + LEVEL_CAP: 45, + LEVEL: 45, + SIZE: Class.genericTank.SIZE * (17 / 3), + SHAPE: 16, + VALUE: 5e5, + SKILL: [10, 10, 10, 10, 10, 10, 10, 10, 10, 10], + BODY: { + REGEN: 0.4, + FOV: 1, + SHIELD: 2, + ACCEL: 0.2, + SPEED: 0.6, + HEALTH: 5000, + PUSHABILITY: 0.15, + DENSITY: 0.2, + DAMAGE: 4, + }, + HITS_OWN_TYPE: "pushOnlyTeam", + TURRETS: [ + { + POSITION: [18, 0, 0, 0, 360, 1], + TYPE: "MKAura", + }, + { + POSITION: [11, 0, 0, 0, 360, 1], + TYPE: "MKTurret", + }, + ], + GUNS: (() => { + let e = [], + T = [1]; + for (let e = 1; e < 8.5; e += 0.5) { + let t = e / 16; + T.push(t); + } + for (let t = 0; t < 16; t++) { + let S = 22.5 * (t + 1), + E = { + MAX_CHILDREN: 2, + SHOOT_SETTINGS: combineStats([g.drone, g.overseer, g.mothership]), + TYPE: "MKDrone", + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "drone", + WAIT_TO_CYCLE: true, + }; + t % 2 == 0 && + (E.TYPE = [ + "MKDrone", + { + AI: { + skynet: true, + }, + INDEPENDENT: true, + LAYER: 10, + BODY: { + FOV: 2, + }, + }, + ]); + let O = { + POSITION: [4.3, 3.1, 1.2, 8, 0, S, T[t]], + PROPERTIES: E, + }; + e.push(O); + } + return e; + })(), +} +Class.helenaBossBaseAura = addAura(2, 2, 0) +const helenaBossBase = { + PARENT: "genericTank", + COLOR: "crasher", + UPGRADE_COLOR: "crasher", + LABEL: "AV-512-F", + NAME: "Helena", + SHAPE: 3.5, + SIZE: 28, + VALUE: 1e9, + DANGER: 100, + GLOW: { + RADIUS: 9, + COLOR: "mirror", + ALPHA: 1, + RECURSION: 3 + }, + BODY: { + HEALTH: 1180, + DAMAGE: 18, + REGEN: 3 * base.REGEN, + SHIELD: 3 * base.SHIELD, + SPEED: 0.35 * base.SPEED + }, + SKILL: [9, 9, 9, 9, 9, 9, 9, 9, 9, 9], + TURRETS: [ + { + POSITION: [10, 0, 0, 0, 360, 0], + TYPE: "helenaBossBaseAura" + } + ] +} +Class.helenaDpProp = makeDeco(3.5, "crasher") +Class.helenaBossDpProp2 = makeDeco(3.5, "black") +Class.helenaBossDpPropArmed = { + PARENT: "genericTank", + COLOR: "crasher", + SHAPE: 3, + GUNS: weaponArray( + { + POSITION: [15, 8, 1, 0, 0, 60, 0], + PROPERTIES: { + COLOR: "crasher", + } + }, 3 + ) +} +Class.helenaBossHDDProp = makeDeco(3.5, "darkGrey") +Class.helenaBossHDDProp2 = makeDeco(3.5, "crasher") +Class.helenaBossMinionProp = makeDeco(3.5, "black") +Class.helenaBossHDDMinion = { + PARENT: "minion", + LABEL: "AV-16-X", + SHAPE: 3.5, + DRAW_HEALTH: true, + PROPS: [ + { + POSITION: { SIZE: 30, LAYER: 0, ANGLE: 360 }, + TYPE: "helenaBossMinionProp" + }, + { + POSITION: { SIZE: 25, LAYER: 0, ANGLE: 360 }, + TYPE: ["helenaBossMinionProp", { COLOR: "white"}] + }, + { + POSITION: { SIZE: 11, LAYER: 1, ANGLE: 360 }, + TYPE: "helenaBossMinionProp" + } + ], + GUNS: [ + ...weaponArray([ + { + POSITION: [10.5, 7.5, 1.3, 7, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.swarm, g.pounder, { reload: 1.15 }]), + TYPE: "swarm", + STAT_CALCULATOR: "swarm", + COLOR: "white" + }, + } + ], 3 + ) + ] +} +Class.helenaBossAuraBulletAura = addAura(0.333, 1.5, 0.3, "crasher") +Class.helenaBossAuraBullet = { + PARENT: "bullet", + TURRETS: [ + { + POSITION: [10, 0, 0, 0, 360, 1], + TYPE: "helenaBossAuraBulletAura" + } + ] +} +Class.helenaBossChip = { + PARENT: "drone", + LABEL: "Helenchip", + PROPS: [ + { + POSITION: { SIZE: 10, LAYER: 1, ANGLE: 180 }, + TYPE: ["triangle", { COLOR: "crasher" }] + } + ] +} +Class.helenaBoss = { + ...helenaBossBase, + UPGRADE_TOOLTIP: "A crasher that descended upon the Universe, from the Crasher Heavens.\nAlso known as the \"Prime Crasher\".\nMore stories are to be told about her...", + CONTROLLERS: ["nearestDifferentMaster", "mapTargetToGoal", ["minion", { orbit: 240 }]], + PROPS: [ + { + POSITION: { SIZE: 25, LAYER: 0, ANGLE: 360 }, + TYPE: "helenaBossDpProp2" + }, + { + POSITION: { SIZE: 16, LAYER: 1, ANGLE: 360 }, + TYPE: "helenaBossHDDProp" + }, + { + POSITION: { SIZE: 12.5, LAYER: 1, ANGLE: 360 }, + TYPE: "helenaBossHDDProp2" + }, + { + POSITION: { SIZE: 7.75, LAYER: 1, ANGLE: 360 }, + TYPE: "helenaBossHDDProp" + }, + { + POSITION: { SIZE: 5.25, LAYER: 1, ANGLE: 360 }, + TYPE: ["helenaBossHDDProp", { COLOR: "white" }] + }, + { + POSITION: { SIZE: 3, LAYER: 1, ANGLE: 360 }, + TYPE: "helenaBossHDDProp2" + } + ], + GUNS: [ + ...weaponArray( + [{ + POSITION: [7.5, 11.75, 1.33, 5.5, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.factory, { reload: 3, health: 2 }]), + TYPE: ["helenaBossHDDMinion", { INDEPENDENT: true }], + COLOR: "black", + MAX_CHILDREN: 2 + }, + }, + { + POSITION: [8.5, 5, 1.25, 8.5, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.single, { reload: 1.1, size: 1.5 }]), + TYPE: "helenaBossAuraBullet", + COLOR: "white" + } + }, + { + POSITION: [8.5, 5, 1.25, 8.5, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, g.setTrap, g.twin, g.pounder, {reload: 1.15, health: 0.85, speed: 0.5, maxSpeed: 0.5, range: 0.25, size: 1.5}]), + TYPE: "unsetPillbox", + STAT_CALCULATOR: "block", + ALPHA: 0 + } + }, + { + POSITION: [8.5, 5, 1.25, 6.5, 5.5, 15, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, g.twin, g.pounder, {shudder: 0.6, health: 0.55, reload: 1.2, speed: 1, maxSpeed: 1, range: 0.33}]), + TYPE: "trap", + STAT_CALCULATOR: "trap", + COLOR: "white" + } + }, + { + POSITION: [8.5, 5, 1.25, 6.5, -5.5, -15, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, g.twin, g.pounder, {shudder: 0.6, health: 0.55, reload: 1.2, speed: 1, maxSpeed: 1, range: 0.33}]), + TYPE: "trap", + STAT_CALCULATOR: "trap", + COLOR: "white" + } + }, + { + POSITION: [8.5, 5, 1.25, 6.5, 5.5, 15, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, g.overseer, g.pounder, { size: 1.75, speed: 1.6, maxSpeed: 1.6 }]), + TYPE: "helenaBossChip", + STAT_CALCULATOR: "drone", + ALPHA: 0, + MAX_CHILDREN: 2 + } + }, + { + POSITION: [8.5, 5, 1.25, 6.5, -5.5, -15, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, g.overseer, g.pounder, { size: 1.75, speed: 1.6, maxSpeed: 1.6 }]), + TYPE: "helenaBossChip", + STAT_CALCULATOR: "drone", + ALPHA: 0, + MAX_CHILDREN: 2 + } + }, + ], 3 + ) + ], + ON: [ + { + event: "tick", + handler: ({ body }) => { + body.store.ticks ??= 0 + body.store.ticks++ + const spawnCrashers = body.store.ticks % 6 == 0 // a lot + const spawnSentries = body.store.ticks % 240 == 0 // ~8 seconds + const spawnLegions = body.store.ticks % 1300 == 0 // about every minute + const sentries = ["sentrySwarm", "sentryGun", "sentryTrap"] + const legions = ["eliteDestroyer", "eliteGunner", "eliteSprayer", "eliteBattleship", "eliteSpawner", "eliteTrapGuard", "eliteSpinner", "eliteSkimmer", "guardian", "defender", "sprayerLegion"] + if (spawnCrashers) new Entity(body, body).define("crasher") + if (spawnSentries) new Entity(body, body).define(sentries[Math.floor(Math.random() * sentries.length)]) + if (spawnLegions) new Entity(body, body).define(legions[Math.floor(Math.random() * legions.length)]) + } + }, + ] +} \ No newline at end of file diff --git a/server/modules/definitions/groups/dev.js b/server/modules/definitions/groups/dev.js index acae1892f..4bf7a12d5 100644 --- a/server/modules/definitions/groups/dev.js +++ b/server/modules/definitions/groups/dev.js @@ -1,8 +1,8 @@ -const { combineStats, menu, addAura, makeDeco, LayeredBoss, newWeapon, weaponArray, makeRadialAuto } = require('../facilitators.js'); -const { base, gunCalcNames, basePolygonDamage, basePolygonHealth, dfltskl, statnames } = require('../constants.js'); +const { combineStats, menu, addAura, makeAuto, makeDeco, LayeredBoss, newWeapon, weaponArray, makeRadialAuto, makeTurret } = require('../facilitators.js'); +const { base, basePolygonDamage, basePolygonHealth, dfltskl, statnames } = require('../constants.js'); const g = require('../gunvals.js'); -require('./tanks.js'); require('./food.js'); +require('./tanks.js'); // Menus Class.developer = { @@ -22,11 +22,13 @@ Class.developer = { ACCEPTS_SCORE: true, CAN_BE_ON_LEADERBOARD: true, CAN_GO_OUTSIDE_ROOM: false, + IS_IMMUNE_TO_TILES: false, DRAW_HEALTH: true, ARENA_CLOSER: true, INVISIBLE: [0, 0], ALPHA: [0, 1], HITS_OWN_TYPE: "hardOnlyTanks", + NECRO: false, SHAPE: [ [-1, -0.8], [-0.8, -1], @@ -52,21 +54,72 @@ Class.spectator = { PARENT: "genericTank", LABEL: "Spectator", ALPHA: 0, - IGNORED_BY_AI: true, CAN_BE_ON_LEADERBOARD: false, ACCEPTS_SCORE: false, DRAW_HEALTH: false, HITS_OWN_TYPE: "never", + IGNORED_BY_AI: true, ARENA_CLOSER: true, + IS_IMMUNE_TO_TILES: true, + TOOLTIP: "Left click to teleport, Right click above or below the screen to change FOV", SKILL_CAP: [0, 0, 0, 0, 0, 0, 0, 0, 0, 255], BODY: { + PUSHABILITY: 0, SPEED: 5, FOV: 2.5, DAMAGE: 0, HEALTH: 1e100, SHIELD: 1e100, REGEN: 1e100, - } + }, + GUNS: [{ + POSITION: [0,0,0,0,0,0,0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, {reload: 0.2}, g.fake]), + TYPE: "bullet", + ALPHA: 0 + } + }, { + POSITION: [0, 0, 0, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { reload: 0.25 }, g.fake]), + TYPE: "bullet", + ALPHA: 0, + ALT_FIRE: true, + } + }], + ON: [{ + event: "fire", + handler: ({ body }) => { + body.x = body.x + body.control.target.x + body.y = body.y + body.control.target.y + } + }, { + event: "altFire", + handler: ({ body }) => body.FOV = body.y + body.control.target.y < body.y ? body.FOV + 0.5 : Math.max(body.FOV - 0.5, 0.2) + }] +} + +Class.generatorBase = { + PARENT: "genericTank", + LABEL: "Generator", + ALPHA: 0, + IGNORED_BY_AI: true, + CAN_BE_ON_LEADERBOARD: false, + ACCEPTS_SCORE: false, + DRAW_HEALTH: false, + HITS_OWN_TYPE: "never", + ARENA_CLOSER: true, + IS_IMMUNE_TO_TILES: true, + SKILL_CAP: [31, 0, 0, 0, 0, 0, 0, 0, 0, 31], + BODY: { + SPEED: 5, + FOV: 2.5, + DAMAGE: 0, + HEALTH: 1e100, + SHIELD: 1e100, + REGEN: 1e100, + }, } Class.bosses = menu("Bosses") @@ -124,9 +177,8 @@ function compileMatrix(matrix, matrix2Entrance) { LABEL = str[0].toUpperCase() + str.slice(1).replace(/[A-Z]/g, m => ' ' + m) + " Generator", code = str + 'Generator'; Class[code] = matrix[y][x] = { - PARENT: "spectator", + PARENT: "generatorBase", LABEL, - SKILL_CAP: [31, 0, 0, 0, 0, 0, 0, 0, 0, 31], TURRETS: [{ POSITION: [5 + y * 2, 0, 0, 0, 0, 1], TYPE: str, @@ -171,16 +223,16 @@ function connectMatrix(matrix, matrix2Entrance) { } } let generatorMatrix = [ - [ "egg" , "gem" , "jewel" , "crasher" , "sentry" , "shinySentry" , "EggRelic" ], - [ "square" , "shinySquare" , "legendarySquare" , "shadowSquare" , "rainbowSquare" , "transSquare" , "SquareRelic" ], - [ "triangle" , "shinyTriangle" , "legendaryTriangle" , "shadowTriangle" , "rainbowTriangle" , "transTriangle" , "TriangleRelic" ], - [ "pentagon" , "shinyPentagon" , "legendaryPentagon" , "shadowPentagon" , "rainbowPentagon" , "transPentagon" , "PentagonRelic" ], - [ "betaPentagon" , "shinyBetaPentagon" , "legendaryBetaPentagon" , "shadowBetaPentagon" , "rainbowBetaPentagon" , "transBetaPentagon" , "BetaPentagonRelic" ], - [ "alphaPentagon" , "shinyAlphaPentagon" , "legendaryAlphaPentagon" , "shadowAlphaPentagon" , "rainbowAlphaPentagon" , "transAlphaPentagon" , "AlphaPentagonRelic" ], - [ "sphere" , "cube" , "tetrahedron" , "octahedron" , "dodecahedron" , "icosahedron" , "tesseract" ], + [ "egg" , "gem" , "jewel" , "crasher" , "sentry" , "shinySentry" , "EggRelic" , "sphere" ], + [ "square" , "shinySquare" , "legendarySquare" , "shadowSquare" , "rainbowSquare" , "transSquare" , "SquareRelic" , "cube" ], + [ "triangle" , "shinyTriangle" , "legendaryTriangle" , "shadowTriangle" , "rainbowTriangle" , "transTriangle" , "TriangleRelic" , "tetrahedron" ], + [ "pentagon" , "shinyPentagon" , "legendaryPentagon" , "shadowPentagon" , "rainbowPentagon" , "transPentagon" , "PentagonRelic" , "octahedron" ], + [ "betaPentagon" , "shinyBetaPentagon" , "legendaryBetaPentagon" , "shadowBetaPentagon" , "rainbowBetaPentagon" , "transBetaPentagon" , "BetaPentagonRelic" , "dodecahedron" ], + [ "alphaPentagon" , "shinyAlphaPentagon" , "legendaryAlphaPentagon" , "shadowAlphaPentagon" , "rainbowAlphaPentagon" , "transAlphaPentagon" , "AlphaPentagonRelic" , "icosahedron" ], + [ "hexagon" , "shinyHexagon" , "legendaryHexagon" , "shadowHexagon" , "rainbowHexagon" , "transHexagon" , "HexagonRelic" , "tesseract" ], ], gemRelicMatrix = []; -for (let tier of [ "", "Egg", "Square", "Triangle", "Pentagon", "BetaPentagon", "AlphaPentagon" ]) { +for (let tier of [ "", "Egg", "Square", "Triangle", "Pentagon", "BetaPentagon", "AlphaPentagon", "Hexagon" ]) { let row = []; for (let gem of [ "Power", "Space", "Reality", "Soul", "Time", "Mind" ]) { row.push(gem + (tier ? tier + 'Relic' : 'Gem')); @@ -203,9 +255,8 @@ for (let poly = 0; poly < 5; poly++) { let str = `laby_${poly}_${tier}_${shiny}_${rank}`, LABEL = ensureIsClass(str).LABEL + " Generator"; Class['generator_' + str] = { - PARENT: "spectator", + PARENT: "generatorBase", LABEL, - SKILL_CAP: [31, 0, 0, 0, 0, 0, 0, 0, 0, 31], TURRETS: [{ POSITION: [5 + tier * 2, 0, 0, 0, 0, 1], TYPE: str, @@ -284,6 +335,12 @@ Class.diamondShape = { SHAPE: 4.5 }; +Class.rotatedTrap = { + PARENT: "basic", + LABEL: "Rotated Inverted Body", + SHAPE: -3.5 +}; + Class.mummyHat = { SHAPE: 4.5, COLOR: -1 @@ -314,7 +371,7 @@ Class.mummifier = { TYPE: "mummy", AUTOFIRE: true, SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.necro + STAT_CALCULATOR: "necro" } },{ POSITION: [5.5, 13, 1.1, 8, 0, 270, 0], @@ -323,7 +380,7 @@ Class.mummifier = { TYPE: "mummy", AUTOFIRE: true, SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.necro + STAT_CALCULATOR: "necro" } }], TURRETS: [{ @@ -331,6 +388,39 @@ Class.mummifier = { TYPE: ["mummyHat"] }] }; + +Class.colorMan = { + PARENT: "genericTank", + LABEL: "Testing Animated Colors", + SHAPE: 4, + COLOR: "rainbow", + TURRETS: [{ + POSITION: [20, -20, -20, 0, 0, 1], + TYPE: { SHAPE: 4, COLOR: "animatedBlueRed" } + },{ + POSITION: [20, 0 , -20, 0, 0, 1], + TYPE: { SHAPE: 4, COLOR: "animatedBlueGrey" } + },{ + POSITION: [20, 20, -20, 0, 0, 1], + TYPE: { SHAPE: 4, COLOR: "animatedGreyBlue" } + },{ + POSITION: [20, -20, 0 , 0, 0, 1], + TYPE: { SHAPE: 4, COLOR: "animatedRedGrey" } + },{ + POSITION: [20, 20, 0 , 0, 0, 1], + TYPE: { SHAPE: 4, COLOR: "animatedGreyRed" } + },{ + POSITION: [20, 20, 20, 0, 0, 1], + TYPE: { SHAPE: 4, COLOR: "animatedLesbian" } + },{ + POSITION: [20, 0 , 20, 0, 0, 1], + TYPE: { SHAPE: 4, COLOR: "animatedTrans" } + },{ + POSITION: [20, 20, 20, 0, 0, 1], + TYPE: { SHAPE: 4, COLOR: "animatedBi" } + }] +}; + Class.miscTestHelper2 = { PARENT: "genericTank", LABEL: "Turret Reload 3", @@ -403,12 +493,6 @@ Class.mmaTest2 = { Class.mmaTest1 = { PARENT: "genericTank", COLOR: -1, - // Somehow, removing the gun below causes a crash when the tank is chosen ?????? - GUNS: [ - { - POSITION: [18, 8, 1, 0, 0, 0, 0], - } - ], TURRETS: [ { POSITION: [10, 0, 0, 0, 360, 1], @@ -454,17 +538,11 @@ Class.vulnturrettest = { TYPE: 'bullet' } }], - TURRETS: (() => { - let output = [] - for (let i = 0; i < 10; i++) { - output.push({ - POSITION: {SIZE: 20, X: 40, ANGLE: (360/10)*i}, - TYPE: "vulnturrettest_turret", - VULNERABLE: true - }) - } - return output - })(), + TURRETS: weaponArray({ + POSITION: {SIZE: 20, X: 40}, + TYPE: "vulnturrettest_turret", + VULNERABLE: true + }, 10) }; Class.turretLayerTesting = { @@ -510,7 +588,7 @@ Class.alphaGunTest = { Class.radialAutoTest = makeRadialAuto("gunner", { count: 5, isTurret: false, - extraStats: [{spray: 4, speed: 1.4, maxSpeed: 1.4, recoil: 0.2}], + extraStats: {spray: 4, speed: 1.4, maxSpeed: 1.4, recoil: 0.2}, turretIdentifier: "radialAutoTestTurret", size: 8, x: 10, @@ -520,11 +598,20 @@ Class.radialAutoTest = makeRadialAuto("gunner", { rotation: 0.04, danger: 10, }) +Class.makeAutoTestTurret = makeTurret("ranger", {canRepel: true, limitFov: true, extraStats: {reload: 0.5}}); +Class.makeAutoTest = { + PARENT: 'genericTank', + LABEL: "Make Auto Test", + TURRETS: weaponArray({ + POSITION: [8, 10, 0, 0, 180, 0], + TYPE: 'makeAutoTestTurret' + }, 3) +} Class.imageShapeTest = { PARENT: 'genericTank', LABEL: "Image Shape Test", - SHAPE: 'round.png', + SHAPE: 'favicon.png', GUNS: [ { POSITION: [18, 8, 1, 0, 0, 0, 0], @@ -536,7 +623,6 @@ Class.imageShapeTest = { ] } -// unfinished Class.strokeWidthTest = { PARENT: "basic", LABEL: "Stroke Width Test", @@ -613,27 +699,15 @@ Class.onTest = { }] } -Class.auraBasicGen = addAura(); -Class.auraBasic = { - PARENT: "genericTank", - LABEL: "Aura Basic", - TURRETS: [ - { - POSITION: [14, 0, 0, 0, 0, 1], - TYPE: "auraBasicGen" - } - ], - GUNS: [ - { - POSITION: [18, 8, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic]), - TYPE: "bullet", - }, - }, - ], -}; -Class.auraHealerGen = addAura(-1); +Class.turretStatScaleTest = { + PARENT: 'genericTank', + LABEL: 'Turret Stat Test', + TURRETS: Array(5).fill().map((_, i) => ({ + POSITION: [15, 0, -40 + 20 * i, 0, 360, 1], + TYPE: ['autoTankGun', {GUN_STAT_SCALE: {speed: 1 + i / 5, maxSpeed: 1 + i / 5, reload: 1 + i / 5, recoil: 0}}] + })) +} + Class.auraHealer = { PARENT: "genericTank", LABEL: "Aura Healer", @@ -761,7 +835,7 @@ Class.vanquisher = { PROPERTIES: { SHOOT_SETTINGS: combineStats([g.trap, g.setTrap]), TYPE: "setTrap", - STAT_CALCULATOR: gunCalcNames.block + STAT_CALCULATOR: "block" } //launcher @@ -769,7 +843,7 @@ Class.vanquisher = { POSITION: [10, 9, 1, 9, 0, 90, 0], },{ POSITION: [17, 13, 1, 0, 0, 90, 0], - PROPERTIES: { SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.artillery, g.artillery]), TYPE: "minimissile", STAT_CALCULATOR: gunCalcNames.sustained } + PROPERTIES: { SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.artillery, g.artillery]), TYPE: "minimissile", STAT_CALCULATOR: "sustained" } //shotgun },{ @@ -845,9 +919,52 @@ Class.armyOfOne = { } ], }; +Class.godbasic = { + PARENT: "genericTank", + LABEL: "God Basic", + SKILL_CAP: [31, 31, 31, 31, 31, 31, 31, 31, 31, 31], + SKILL: [ 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 ], + BODY: { + ACCELERATION: base.ACCEL * 1, + SPEED: base.SPEED * 1, + HEALTH: base.HEALTH * 1, + DAMAGE: base.DAMAGE * 1, + PENETRATION: base.PENETRATION * 1, + SHIELD: base.SHIELD * 1, + REGEN: base.REGEN * 1, + FOV: base.FOV * 1, + DENSITY: base.DENSITY * 1, + PUSHABILITY: 1, + HETERO: 3, + }, + GUNS: [ + { + POSITION: [18, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic]), + TYPE: "bullet", + COLOR: "grey", + LABEL: "", + STAT_CALCULATOR: 0, + WAIT_TO_CYCLE: false, + AUTOFIRE: false, + SYNCS_SKILLS: false, + MAX_CHILDREN: 0, + ALT_FIRE: false, + NEGATIVE_RECOIL: false, + }, + }, + ], +}; +Class.maximumOverdrive = { + PARENT: "overdrive", + LABEL: "Maximum Overdrive", + SKILL_CAP: Array(10).fill(255), + SKILL: Array(10).fill(255), +}; Class.weirdAutoBasic = { PARENT: "genericTank", - LABEL: "Weirdly defined Auto-Basic", + LABEL: "Weirdly Defined Auto-Basic", GUNS: [{ POSITION: { LENGTH: 20, @@ -897,7 +1014,6 @@ Class.bulletSpawnTest = { } ] } - Class.propTestProp = { PARENT: 'genericTank', SHAPE: 6, @@ -912,6 +1028,7 @@ Class.propTestProp = { } ] } + Class.propTest = { PARENT: 'genericTank', LABEL: 'Deco Prop Test', @@ -938,17 +1055,17 @@ Class.weaponArrayTest = { { POSITION: [20, 8, 1, 0, 0, 25, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic]), + SHOOT_SETTINGS: combineStats([g.basic, {reload: 2}]), TYPE: 'bullet' } }, { - POSITION: [17, 8, 1, 0, 0, 25, 0.5], + POSITION: [17, 8, 1, 0, 0, 25, 0.1], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic]), + SHOOT_SETTINGS: combineStats([g.basic, {reload: 2}]), TYPE: 'bullet' } } - ], 5), + ], 5, 0.4, false), TURRETS: weaponArray( { POSITION: [7, 10, 0, -11, 180, 0], @@ -957,10 +1074,22 @@ Class.weaponArrayTest = { , 5), } +Class.gunBenchmark = { + PARENT: 'genericTank', + LABEL: "Gun Benchmark", + GUNS: weaponArray({ + POSITION: [60, 0.2, 0, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, {size: 0, reload: 0.15, range: 0.05}]), + TYPE: ["bullet", {DRAW_SELF: false}] + } + }, 720) +} + Class.levels = menu("Levels") Class.levels.UPGRADES_TIER_0 = [] -for (let i = 0; i < 12; i++) { - let LEVEL = i * c.TIER_MULTIPLIER; +for (let i = 0; i < 16; i++) { + let LEVEL = i * Config.TIER_MULTIPLIER; Class["level" + LEVEL] = { PARENT: "levels", LEVEL, @@ -981,6 +1110,12 @@ for (let i = 1; i <= 8; i++) { }; Class.teams.UPGRADES_TIER_0.push("Team" + TEAM); } +Class['Team' + TEAM_DREADNOUGHTS] = { + PARENT: "teams", + TEAM: TEAM_DREADNOUGHTS, + COLOR: getTeamColor(TEAM_DREADNOUGHTS), + LABEL: "Dreads Team" +}; Class['Team' + TEAM_ROOM] = { PARENT: "teams", TEAM: TEAM_ROOM, @@ -993,10 +1128,17 @@ Class['Team' + TEAM_ENEMIES] = { COLOR: "yellow", LABEL: "Enemies Team" }; -Class.teams.UPGRADES_TIER_0.push('Team' + TEAM_ROOM, 'Team' + TEAM_ENEMIES); - -Class.testing = menu("Testing") +Class.teams.UPGRADES_TIER_0.push('Team' + TEAM_DREADNOUGHTS, 'Team' + TEAM_ROOM, 'Team' + TEAM_ENEMIES); +Class.testing = menu("Beta Tanks") +Class.features = menu("Features") +Class.overpowered = menu("Dev Funny", "rainbow") +Class.overpowered.UPGRADE_COLOR = "rainbow" +Class.goofytanks = menu("Goofy Shit", "rainbow") +Class.goofytanks.UPGRADE_COLOR = "rainbow" +Class.overpowered.UPGRADE_TOOLTIP = "The Funny v2" +Class.goofytanks.UPGRADE_TOOLTIP = "The Funny v3" + Class.addons = menu("Addon Entities") Class.addons.UPGRADES_TIER_0 = [] @@ -1029,7 +1171,7 @@ Class.snakeOld = { POSITION: [6, 12, 1.4, 8, 0, 180, 0], PROPERTIES: { AUTOFIRE: true, - STAT_CALCULATOR: gunCalcNames.thruster, + STAT_CALCULATOR: "thruster", SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.hunterSecondary, g.snake, g.snakeskin]), TYPE: ["bullet", { PERSISTS_AFTER_DEATH: true }], }, @@ -1039,7 +1181,7 @@ Class.snakeOld = { PROPERTIES: { AUTOFIRE: true, NEGATIVE_RECOIL: true, - STAT_CALCULATOR: gunCalcNames.thruster, + STAT_CALCULATOR: "thruster", SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.hunterSecondary, g.snake]), TYPE: ["bullet", { PERSISTS_AFTER_DEATH: true }], }, @@ -1048,7 +1190,7 @@ Class.snakeOld = { } Class.sidewinderOld = { PARENT: "genericTank", - LABEL: "Sidewinder (old)", + LABEL: "Sidewinder (Legacy)", DANGER: 7, BODY: { SPEED: 0.8 * base.SPEED, @@ -1063,13 +1205,62 @@ Class.sidewinderOld = { PROPERTIES: { SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.sidewinder]), TYPE: "snakeOld", - STAT_CALCULATOR: gunCalcNames.sustained, + STAT_CALCULATOR: "sustained", }, }, ], } +Class.tetraGunner = { + PARENT: "genericTank", + LABEL: "Tetra Gunner", + DANGER: 7, + GUNS: weaponArray([ + { + POSITION: [14, 3.5, 1, 0, 4, 0, 1 / 3], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.gunner, { speed: 1.2 }]), + TYPE: "bullet", + }, + }, + { + POSITION: [14, 3.5, 1, 0, -4, 0, 2 / 3], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.gunner, { speed: 1.2 }]), + TYPE: "bullet", + }, + }, + { + POSITION: [18, 3.5, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.gunner, { speed: 1.2 }]), + TYPE: "bullet", + }, + } + ], 4) +} + +// Whirlwind Class.whirlwindDeco = makeDeco(6) Class.whirlwindDeco.CONTROLLERS = [["spin", { independent: true, speed: 0.128 }]] +Class.tornadoDeco = makeDeco(4) +Class.tornadoDeco.CONTROLLERS = [["spin", { independent: true, speed: 0.128 }]] +Class.megaTornadoDeco = makeDeco([[0,-1],[0.5,0],[0,1],[-0.5,0]]) +Class.megaTornadoDeco.CONTROLLERS = [["spin", { independent: true }]] +Class.thunderboltDeco = makeDeco(4) +Class.thunderboltDeco.CONTROLLERS = [["spin", { independent: true, speed: 0.16 }]] +Class.hurricaneDeco = makeDeco(8) +Class.hurricaneDeco.CONTROLLERS = [["spin", { independent: true, speed: 0.128 }]] +Class.typhoonDeco = makeDeco(10) +Class.typhoonDeco.CONTROLLERS = [["spin", { independent: true, speed: 0.128 }]] +Class.tempestDeco1 = makeDeco(3) +Class.tempestDeco1.CONTROLLERS = [["spin", { independent: true, speed: 0.128 }]] +Class.tempestDeco2 = makeDeco(3) +Class.tempestDeco2.CONTROLLERS = [["spin", { independent: true, speed: -0.128 }]] +Class.blizzardDeco1 = makeDeco(5) +Class.blizzardDeco1.CONTROLLERS = [["spin", { independent: true, speed: 0.128 }]] +Class.blizzardDeco2 = makeDeco(5) +Class.blizzardDeco2.CONTROLLERS = [["spin", { independent: true, speed: -0.128 }]] + Class.whirlwind = { PARENT: "genericTank", LABEL: "Whirlwind", @@ -1085,7 +1276,7 @@ Class.whirlwind = { ], AI: { SPEED: 2, - }, + }, GUNS: (() => { let output = [] for (let i = 0; i < 6; i++) { @@ -1104,146 +1295,3187 @@ Class.whirlwind = { return output })() } -let testLayeredBoss = new LayeredBoss("testLayeredBoss", "Test Layered Boss", "terrestrial", 7, 3, "terrestrialTrapTurret", 5, 7, {SPEED: 10}); -testLayeredBoss.addLayer({gun: { - POSITION: [3.6, 7, -1.4, 8, 0, null, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.factory, { size: 0.5 }]), - TYPE: ["minion", {INDEPENDENT: true}], - AUTOFIRE: true, - SYNCS_SKILLS: true, - }, -}}, true, null, 16); -testLayeredBoss.addLayer({turret: { - POSITION: [10, 7.5, 0, null, 160, 0], - TYPE: "crowbarTurret", -}}, true); -// FLAIL!!! -Class.flailBallSpike = { - PARENT: "genericTank", - COLOR: "black", - SHAPE: 6, - INDEPENDENT: true, -}; -Class.flailBall = { +// Whirlwind upgrades +Class.tornado = { PARENT: "genericTank", - COLOR: "grey", - HITS_OWN_TYPE: 'hard', - INDEPENDENT: true, - TURRETS: [{ - POSITION: [21.5, 0, 0, 0, 360, 0], - TYPE: "flailBallSpike", - }], -}; -Class.flailBolt1 = { + LABEL: "Tornado", + DANGER: 6, + TURRETS: [ + { + POSITION: [10, 0, 0, 0, 360, 1], + TYPE: "tornadoDeco", + }, + ], + ANGLE: 90, + CONTROLLERS: ["whirlwind"], + HAS_NO_RECOIL: true, + STAT_NAMES: statnames.whirlwind, + AI: { + SPEED: 2, + }, + GUNS: (() => { + let output = [] + for (let i = 0; i < 4; i++) { + output.push({ + POSITION: {WIDTH: 12, LENGTH: 1, DELAY: i * 0.25}, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.satellite, g.pounder]), + TYPE: ["satellite", {ANGLE: i * 90}], + MAX_CHILDREN: 1, + AUTOFIRE: true, + SYNCS_SKILLS: false, + WAIT_TO_CYCLE: true + } + }) + } + return output + })() +} +Class.hurricane = { PARENT: "genericTank", - COLOR: "grey", - INDEPENDENT: true, - GUNS: [{ - POSITION: [40, 5, 1, 8, 0, 0, 0] - }], - TURRETS: [{ - POSITION: [48, 56, 0, 0, 360, 1], - TYPE: "flailBall" - }], -}; -Class.flailBolt2 = { + LABEL: "Hurricane", + DANGER: 6, + ANGLE: 45, + CONTROLLERS: ["whirlwind"], + HAS_NO_RECOIL: true, + STAT_NAMES: statnames.whirlwind, + TURRETS: [ + { + POSITION: [8, 0, 0, 0, 360, 1], + TYPE: "hurricaneDeco", + }, + ], + AI: { + SPEED: 2, + }, + GUNS: (() => { + let output = [] + for (let i = 0; i < 8; i++) { + output.push({ + POSITION: {WIDTH: 8, LENGTH: 1, DELAY: i * 0.25}, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.satellite]), + TYPE: ["satellite", {ANGLE: i * 45}], + MAX_CHILDREN: 1, + AUTOFIRE: true, + SYNCS_SKILLS: false, + WAIT_TO_CYCLE: true + } + }) + } + return output + })() +} + +// Tornado upgrades +Class.megaTornado = { PARENT: "genericTank", - COLOR: "grey", - INDEPENDENT: true, - GUNS: [{ - POSITION: [30, 5, 1, 8, 0, 0, 0] - }], - TURRETS: [{ - POSITION: [20, 36, 0, 0, 360, 1], - TYPE: "flailBolt1" - }], -}; -Class.flailBolt3 = { + LABEL: "Mega Tornado", + DANGER: 7, + TURRETS: [ + { + POSITION: [16, 0, 0, 0, 360, 1], + TYPE: "megaTornadoDeco", + }, + ], + ANGLE: 180, + CONTROLLERS: ["whirlwind"], + HAS_NO_RECOIL: true, + STAT_NAMES: statnames.whirlwind, + AI: { + SPEED: 2, + }, + GUNS: (() => { + let output = [] + for (let i = 0; i < 2; i++) { + output.push({ + POSITION: {WIDTH: 16, LENGTH: 1, DELAY: i * 0.25}, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.satellite, g.pounder, g.destroyer]), + TYPE: ["satellite", {ANGLE: i * 180}], + MAX_CHILDREN: 1, + AUTOFIRE: true, + SYNCS_SKILLS: false, + WAIT_TO_CYCLE: true + } + }) + } + return output + })() +} +Class.tempest = { + PARENT: "genericTank", + LABEL: "Tempest", + DANGER: 7, + TURRETS: [ + { + POSITION: [8, 0, 0, 0, 360, 1], + TYPE: "tempestDeco1", + }, + { + POSITION: [4, 0, 0, 180, 360, 1], + TYPE: "tempestDeco2", + }, + ], + ANGLE: 120, + CONTROLLERS: ["whirlwind"], + HAS_NO_RECOIL: true, + STAT_NAMES: statnames.whirlwind, + AI: { + SPEED: 2, + }, + GUNS: (() => { + let output = [] + for (let i = 0; i < 3; i++) { + output.push({ + POSITION: {WIDTH: 12, LENGTH: 1, DELAY: i * 0.25}, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.satellite, g.pounder]), + TYPE: ["satellite", {ANGLE: i * 120}], + MAX_CHILDREN: 1, + AUTOFIRE: true, + SYNCS_SKILLS: false, + WAIT_TO_CYCLE: true + } + }) + } + for (let i = 0; i < 3; i++) { + output.push({ + POSITION: {WIDTH: 12, LENGTH: 1, DELAY: i * 0.25}, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.satellite, g.pounder]), + TYPE: ["satellite", { ANGLE: i * 120, CONTROLLERS: [['orbit', {invert: true}]] }], + MAX_CHILDREN: 1, + AUTOFIRE: true, + SYNCS_SKILLS: false, + WAIT_TO_CYCLE: true + } + }) + } + return output + })() +} +Class.thunderbolt = { + PARENT: "genericTank", + LABEL: "Thunderbolt", + DANGER: 7, + TURRETS: [ + { + POSITION: [10, 0, 0, 0, 360, 1], + TYPE: "thunderboltDeco", + }, + ], + ANGLE: 90, + CONTROLLERS: ["whirlwind"], + HAS_NO_RECOIL: true, + STAT_NAMES: statnames.whirlwind, + AI: { + SPEED: 2.5, + }, + GUNS: (() => { + let output = [] + for (let i = 0; i < 4; i++) { + output.push({ + POSITION: {WIDTH: 12, LENGTH: 1, DELAY: i * 0.25}, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.satellite, g.pounder]), + TYPE: ["satellite", {ANGLE: i * 90}], + MAX_CHILDREN: 1, + AUTOFIRE: true, + SYNCS_SKILLS: false, + WAIT_TO_CYCLE: true + } + }) + } + return output + })() +} + +// Hurricane upgrades +Class.typhoon = { + PARENT: "genericTank", + LABEL: "Typhoon", + DANGER: 7, + ANGLE: 36, + CONTROLLERS: ["whirlwind"], + HAS_NO_RECOIL: true, + STAT_NAMES: statnames.whirlwind, + TURRETS: [ + { + POSITION: [8, 0, 0, 0, 360, 1], + TYPE: "typhoonDeco", + }, + ], + AI: { + SPEED: 2, + }, + GUNS: (() => { + let output = [] + for (let i = 0; i < 10; i++) { + output.push({ + POSITION: {WIDTH: 8, LENGTH: 1, DELAY: i * 0.25}, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.satellite]), + TYPE: ["satellite", {ANGLE: i * 36}], + MAX_CHILDREN: 1, + AUTOFIRE: true, + SYNCS_SKILLS: false, + WAIT_TO_CYCLE: true + } + }) + } + return output + })() +} +Class.blizzard = { + PARENT: "genericTank", + LABEL: "Blizzard", + DANGER: 7, + TURRETS: [ + { + POSITION: [8, 0, 0, 0, 360, 1], + TYPE: "blizzardDeco1", + }, + { + POSITION: [6, 0, 0, 180, 360, 1], + TYPE: "blizzardDeco2", + }, + ], + ANGLE: 72, + CONTROLLERS: ["whirlwind"], + HAS_NO_RECOIL: true, + STAT_NAMES: statnames.whirlwind, + AI: { + SPEED: 2, + }, + GUNS: (() => { + let output = [] + for (let i = 0; i < 5; i++) { + output.push({ + POSITION: {WIDTH: 8, LENGTH: 1, DELAY: i * 0.25}, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.satellite]), + TYPE: ["satellite", {ANGLE: i * 72}], + MAX_CHILDREN: 1, + AUTOFIRE: true, + SYNCS_SKILLS: false, + WAIT_TO_CYCLE: true + } + }) + } + for (let i = 0; i < 5; i++) { + output.push({ + POSITION: {WIDTH: 8, LENGTH: 1, DELAY: i * 0.25}, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.satellite]), + TYPE: ["satellite", { ANGLE: i * 72, CONTROLLERS: [['orbit', {invert: true}]] }], + MAX_CHILDREN: 1, + AUTOFIRE: true, + SYNCS_SKILLS: false, + WAIT_TO_CYCLE: true + } + }) + } + return output + })() +} + +// Whirlwind hybrids +Class.hexaWhirl = { + PARENT: "genericTank", + LABEL: "Hexa Whirl", + DANGER: 7, + ANGLE: 90, + CONTROLLERS: ["whirlwind"], + HAS_NO_RECOIL: true, + STAT_NAMES: statnames.whirlwind, + TURRETS: [ + { + POSITION: [8, 0, 0, 0, 360, 1], + TYPE: "tornadoDeco" + } + ], + AI: { + SPEED: 2, + }, + GUNS: (() => { + let output = [] + for (let i = 0; i < 4; i++) { + output.push({ + POSITION: {WIDTH: 8, LENGTH: 1, DELAY: i * 0.25}, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.satellite]), + TYPE: ["satellite", {ANGLE: i * 90}], + MAX_CHILDREN: 1, + AUTOFIRE: true, + SYNCS_SKILLS: false, + WAIT_TO_CYCLE: true + } + }) + } + return output + })() +} +Class.hexaWhirl.GUNS.push({ + POSITION: [18, 8, 1, 0, 0, 60, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.flankGuard]), + TYPE: "bullet" + } + }, + { + POSITION: [18, 8, 1, 0, 0, 180, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.flankGuard]), + TYPE: "bullet" + } + }, + { + POSITION: [18, 8, 1, 0, 0, 300, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.flankGuard]), + TYPE: "bullet" + } + }, + { + POSITION: [18, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.flankGuard]), + TYPE: "bullet" + } + }, + { + POSITION: [18, 8, 1, 0, 0, 120, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.flankGuard]), + TYPE: "bullet" + } + }, + { + POSITION: [18, 8, 1, 0, 0, 240, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.flankGuard]), + TYPE: "bullet" + } + }) +Class.munition = { + PARENT: "genericTank", + LABEL: "Munition", + DANGER: 7, + ANGLE: 90, + CONTROLLERS: ["whirlwind"], + HAS_NO_RECOIL: true, + STAT_NAMES: statnames.whirlwind, + TURRETS: [ + { + POSITION: [8, 0, 0, 0, 360, 1], + TYPE: "tornadoDeco" + } + ], + AI: { + SPEED: 2, + }, + GUNS: (() => { + let output = [] + for (let i = 0; i < 4; i++) { + output.push({ + POSITION: {WIDTH: 8, LENGTH: 1, DELAY: i * 0.25}, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.satellite]), + TYPE: ["satellite", {ANGLE: i * 90}], + MAX_CHILDREN: 1, + AUTOFIRE: true, + SYNCS_SKILLS: false, + WAIT_TO_CYCLE: true + } + }) + } + return output + })() +} +Class.munition.GUNS.push( + { + POSITION: [17, 3, 1, 0, -6, -7, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery]), + TYPE: "bullet", + LABEL: "Secondary", + }, + }, + { + POSITION: [17, 3, 1, 0, 6, 7, 0.75], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery]), + TYPE: "bullet", + LABEL: "Secondary", + }, + }, + { + POSITION: [19, 12, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.artillery]), + TYPE: "bullet", + LABEL: "Heavy", + }, + }, +) +Class.whirl3 = { + PARENT: "genericTank", + LABEL: "Whirl-3", + DANGER: 7, + ANGLE: 90, + CONTROLLERS: ["whirlwind"], + HAS_NO_RECOIL: true, + STAT_NAMES: statnames.whirlwind, + TURRETS: [ + { + POSITION: [8, 0, 0, 0, 360, 1], + TYPE: "tornadoDeco" + }, + { + POSITION: [11, 8, 0, 0, 190, 0], + TYPE: "autoTankGun", + }, + { + POSITION: [11, 8, 0, 120, 190, 0], + TYPE: "autoTankGun", + }, + { + POSITION: [11, 8, 0, 240, 190, 0], + TYPE: "autoTankGun", + } + ], + AI: { + SPEED: 2, + }, + GUNS: (() => { + let output = [] + for (let i = 0; i < 4; i++) { + output.push({ + POSITION: {WIDTH: 8, LENGTH: 1, DELAY: i * 0.25}, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.satellite]), + TYPE: ["satellite", {ANGLE: i * 90}], + MAX_CHILDREN: 1, + AUTOFIRE: true, + SYNCS_SKILLS: false, + WAIT_TO_CYCLE: true + } + }) + } + return output + })() +} +Class.whirlGuard = { + PARENT: "genericTank", + LABEL: "Whirl Guard", + DANGER: 7, + ANGLE: 90, + CONTROLLERS: ["whirlwind"], + HAS_NO_RECOIL: true, + STAT_NAMES: statnames.whirlwind, + TURRETS: [ + { + POSITION: [8, 0, 0, 0, 360, 1], + TYPE: "tornadoDeco" + } + ], + AI: { + SPEED: 2, + }, + GUNS: (() => { + let output = [] + for (let i = 0; i < 4; i++) { + output.push({ + POSITION: {WIDTH: 8, LENGTH: 1, DELAY: i * 0.25}, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.satellite]), + TYPE: ["satellite", {ANGLE: i * 90}], + MAX_CHILDREN: 1, + AUTOFIRE: true, + SYNCS_SKILLS: false, + WAIT_TO_CYCLE: true + } + }) + } + return output + })() +} +Class.whirlGuard.GUNS.push( + { + POSITION: [20, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.flankGuard]), + TYPE: "bullet" + } + }, + { + POSITION: [13, 8, 1, 0, 0, 180, 0] + }, + { + POSITION: [4, 8, 1.7, 13, 0, 180, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap]), + TYPE: "trap", + STAT_CALCULATOR: "trap" + } + } +) +// prophet temporarily disabled because it breaks the game for some reason +/*Class.prophet = { + PARENT: "genericTank", + LABEL: "Prophet", + DANGER: 7, + BODY: { + SPEED: base.SPEED * 0.9, + FOV: base.FOV * 1.1, + }, + SHAPE: 4, + NECRO: true, + ANGLE: 90, + CONTROLLERS: ["whirlwind"], + HAS_NO_RECOIL: true, + STAT_NAMES: statnames.whirlwind, + TURRETS: [ + { + POSITION: [8, 0, 0, 0, 360, 1], + TYPE: "tornadoDeco" + } + ], + AI: { + SPEED: 2, + }, + GUNS: (() => { + let output = [] + for (let i = 0; i < 4; i++) { + output.push({ + POSITION: {WIDTH: 8, LENGTH: 1, DELAY: i * 0.25}, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.satellite]), + TYPE: ["squareSatellite", {ANGLE: i * 90}], + MAX_CHILDREN: 1, + AUTOFIRE: true, + SYNCS_SKILLS: false, + WAIT_TO_CYCLE: true + } + }) + } + return output + })() +} +Class.prophet.GUNS.push({ + POSITION: [5.25, 12, 1.2, 8, 0, 90, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, g.sunchip, {reload: 0.8}]), + TYPE: "sunchip", + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "necro", + WAIT_TO_CYCLE: true, + DELAY_SPAWN: false, + MAX_CHILDREN: 7, + } + }, + { + POSITION: [5.25, 12, 1.2, 8, 0, 270, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, g.sunchip, {reload: 0.8}]), + TYPE: "sunchip", + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "necro", + WAIT_TO_CYCLE: true, + DELAY_SPAWN: false, + MAX_CHILDREN: 7, + } +})*/ +Class.vortex = { + PARENT: "genericTank", + LABEL: "Vortex", + DANGER: 7, + BODY: { + FOV: base.FOV * 1.1, + }, + ANGLE: 90, + CONTROLLERS: ["whirlwind"], + HAS_NO_RECOIL: true, + STAT_NAMES: statnames.whirlwind, + TURRETS: [ + { + POSITION: [8, 0, 0, 0, 360, 1], + TYPE: "tornadoDeco" + } + ], + AI: { + SPEED: 2, + }, + GUNS: (() => { + let output = [] + for (let i = 0; i < 4; i++) { + output.push({ + POSITION: {WIDTH: 8, LENGTH: 1, DELAY: i * 0.25}, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.satellite]), + TYPE: ["satellite", {ANGLE: i * 90}], + MAX_CHILDREN: 1, + AUTOFIRE: true, + SYNCS_SKILLS: false, + WAIT_TO_CYCLE: true + } + }) + } + return output + })() +} +Class.vortex.GUNS.push( + { + POSITION: [10, 9, 1, 9, 0, 0, 0], + }, + { + POSITION: [17, 13, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.launcher]), + TYPE: "minimissile", + STAT_CALCULATOR: "sustained", + }, + } +) + +// misc tanks, cont. +Class.masterBullet = { + PARENT: "missile", + FACING_TYPE: "veryfastspin", + MOTION_TYPE: "motor", + HAS_NO_RECOIL: false, + DIE_AT_RANGE: false, + GUNS: [ + { + POSITION: [18, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.triAngleFront]), + TYPE: "bullet", + LABEL: "Front", + AUTOFIRE: true, + }, + }, + { + POSITION: [13, 8, 1, 0, -1, 140, 0.6], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), + TYPE: "bullet", + LABEL: "Thruster", + AUTOFIRE: true, + }, + }, + { + POSITION: [13, 8, 1, 0, 1, 220, 0.6], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), + TYPE: "bullet", + LABEL: "Thruster", + AUTOFIRE: true, + }, + }, + { + POSITION: [16, 8, 1, 0, 0, 150, 0.1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), + TYPE: "bullet", + LABEL: "Thruster", + AUTOFIRE: true, + }, + }, + { + POSITION: [16, 8, 1, 0, 0, 210, 0.1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), + TYPE: "bullet", + LABEL: "Thruster", + AUTOFIRE: true, + }, + }, + ], +} +Class.master = { + PARENT: "genericTank", + LABEL: "Master", + BODY: { + HEALTH: base.HEALTH * 0.4, + SHIELD: base.SHIELD * 0.4, + DENSITY: base.DENSITY * 0.3, + }, + DANGER: 8, + GUNS: [ + { + POSITION: [18, 16, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic]), + TYPE: "masterBullet", + MAX_CHILDREN: 4, + DESTROY_OLDEST_CHILD: true, + }, + }, + { + POSITION: [13, 8, 1, 0, -1, 140, 0.6], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), + TYPE: "bullet", + LABEL: "thruster", + }, + }, + { + POSITION: [13, 8, 1, 0, 1, 220, 0.6], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), + TYPE: "bullet", + LABEL: "thruster", + }, + }, + { + POSITION: [16, 8, 1, 0, 0, 150, 0.1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), + TYPE: "bullet", + LABEL: "thruster", + }, + }, + { + POSITION: [16, 8, 1, 0, 0, 210, 0.1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), + TYPE: "bullet", + LABEL: "thruster", + }, + }, + ], +} +Class.jumpSmasher = { + PARENT: "genericSmasher", + LABEL: "Jump Smasher", + DANGER: 7, + GUNS: [ + { + POSITION: [2, 12, 1, 0, 0, 180, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { recoil: 12, reload: 13, damage: 0.2, range: 0.13 }]), + TYPE: ["bullet", { ALPHA: 0.5 }], + }, + }, + ], + TURRETS: [ + { + POSITION: [21.5, 0, 0, 0, 360, 0], + TYPE: "jumpsmashBody" + } + ] +} +Class.lamgSpinnerTurret = { + PARENT: "genericTank", + LABEL: "Spinner Turret", + COLOR: "grey", + GUNS: weaponArray({ + POSITION: [15, 3.5, 1, 0, 0, 0, 0] + }, 10) +} +Class.literallyAMachineGun = { + PARENT: "genericTank", + LABEL: "Literally a Machine Gun", + DANGER: 7, + BODY: { + FOV: base.FOV * 1.2 + }, + UPGRADE_TOOLTIP: "[DEV NOTE] This tank does not function as intended yet!", + TURRETS: [ + { + POSITION: [10, 14, 0, 0, 0, 1], + TYPE: "lamgSpinnerTurret" + } + ], + GUNS: [ + { + POSITION: [22, 8, 1, 0, 0, 0, 0] + } + ] +} + +// literally a tank +class io_turretWithMotion extends IO { + constructor(b, opts = {}) { + super(b) + } + think(input) { + return { + target: this.body.master.velocity, + main: true, + }; + } +} +ioTypes.turretWithMotion = io_turretWithMotion +Class.latTop = makeDeco(0) +Class.latDeco1 = { + PARENT: "genericTank", + LABEL: "Tank Deco", + FACING_TYPE: ["turnWithSpeed"], + COLOR: "#5C533F", + SHAPE: "M -1 -2 C -1 -2 -1 -3 0 -3 C 1 -3 1 -2 1 -2 V 2 C 1 2 1 3 0 3 C -1 3 -1 2 -1 2 V -2", + MIRROR_MASTER_ANGLE: true, +} +Class.latDeco2 = { + PARENT: "genericTank", + LABEL: "Tank Deco", + FACING_TYPE: ["turnWithSpeed"], + COLOR: "#5C533F", + SHAPE: "M -2 0 H 2 L 0 1 L -2 0", + MIRROR_MASTER_ANGLE: true, +} +Class.latDeco3 = { + PARENT: "genericTank", + LABEL: "Tank Deco", + FACING_TYPE: ["turnWithSpeed"], + COLOR: "#3F3B2D", + SHAPE: "M -10 -1 L 10 -1 L 10 1 L -10 1 L -10 -1", + MIRROR_MASTER_ANGLE: true, +} +Class.latRight = { + PARENT: "genericTank", + LABEL: "Tank Side", + FACING_TYPE: ["turnWithSpeed"], + COLOR: "#96794E", + SHAPE: "M -6 0 H 5 V 1 C 5 2 4 2 4 2 H -5 C -6 2 -6 1 -6 1 V 0", + MIRROR_MASTER_ANGLE: true, + TURRETS: [ + { + POSITION: [4.8, 31, 10, 0, 0, 1], + TYPE: "latDeco1", + }, + { + POSITION: [4.8, 24, 10, 0, 0, 1], + TYPE: "latDeco1", + }, + { + POSITION: [4.8, 17, 10, 0, 0, 1], + TYPE: "latDeco1", + }, + { + POSITION: [4.8, -42, 10, 0, 0, 1], + TYPE: "latDeco1", + }, + { + POSITION: [4.8, -35, 10, 0, 0, 1], + TYPE: "latDeco1", + }, + { + POSITION: [4.8, -28, 10, 0, 0, 1], + TYPE: "latDeco1", + }, + { + POSITION: [18, -5, 0, 0, 0, 1], + TYPE: "latDeco2", + }, + ] +} +Class.latLeft = { + PARENT: "genericTank", + LABEL: "Tank Side", + FACING_TYPE: ["turnWithSpeed"], + COLOR: "#96794E", + SHAPE: "M -5 0 H 6 V 1 C 6 2 5 2 5 2 H -4 C -5 2 -5 1 -5 1 V 0", + MIRROR_MASTER_ANGLE: true, + TURRETS: [ + { + POSITION: [4.8, -31, 10, 0, 0, 1], + TYPE: "latDeco1", + }, + { + POSITION: [4.8, -24, 10, 0, 0, 1], + TYPE: "latDeco1", + }, + { + POSITION: [4.8, -17, 10, 0, 0, 1], + TYPE: "latDeco1", + }, + { + POSITION: [4.8, 42, 10, 0, 0, 1], + TYPE: "latDeco1", + }, + { + POSITION: [4.8, 35, 10, 0, 0, 1], + TYPE: "latDeco1", + }, + { + POSITION: [4.8, 28, 10, 0, 0, 1], + TYPE: "latDeco1", + }, + { + POSITION: [18, 5, 0, 0, 0, 1], + TYPE: "latDeco2", + }, + ] +} +Class.latBase = { + PARENT: "genericTank", + LABEL: "Tank Base", + CONTROLLERS: ["turretWithMotion"], + COLOR: "#96794E", + SHAPE: [ + [1.1, 1], + [1.4, 0], + [1.1, -1], + [-1.1, -1], + [-0.8, 0], + [-1.1, 1] + ], + GUNS: [ + { + POSITION: [16, 5.5, 1, 1, 6.5, 0, 0] + }, + { + POSITION: [14.5, 5.5, 1, 1, 6.5, 0, 0] + }, + { + POSITION: [13, 5.5, 1, 1, 6.5, 0, 0] + }, + { + POSITION: [16, 5.5, 1, 1, -6.5, 0, 0] + }, + { + POSITION: [14.5, 5.5, 1, 1, -6.5, 0, 0] + }, + { + POSITION: [13, 5.5, 1, 1, -6.5, 0, 0] + }, + { + POSITION: [13, 5.5, 1, 1, 6.5, 180, 0] + }, + { + POSITION: [11.5, 5.5, 1, 1, 6.5, 180, 0] + }, + { + POSITION: [10, 5.5, 1, 1, 6.5, 180, 0] + }, + { + POSITION: [8.5, 5.5, 1, 1, 6.5, 180, 0] + }, + { + POSITION: [13, 5.5, 1, 1, -6.5, 180, 0] + }, + { + POSITION: [11.5, 5.5, 1, 1, -6.5, 180, 0] + }, + { + POSITION: [10, 5.5, 1, 1, -6.5, 180, 0] + }, + { + POSITION: [8.5, 5.5, 1, 1, -6.5, 180, 0] + }, + ], + TURRETS: [ + { + POSITION: [5.3, 0, -10, 0, 0, 1], + TYPE: "latLeft", + }, + { + POSITION: [5.3, 0, -10, 180, 0, 1], + TYPE: "latRight", + }, + { + POSITION: [2, 0, -1.4, 90, 0, 1], + TYPE: "latDeco3", + }, + ] +} +Class.literallyATank = { + PARENT: "genericTank", + DANGER: 6, + BODY: { + HEALTH: base.HEALTH * 1.2, + }, + LABEL: "Literally a Tank", + SHAPE: "M -1 -1 H 0 C 1 -1 1 0 1 0 C 1 0 1 1 0 1 H -1 V -1", + GUNS: [ + { + POSITION: [30, 8, 1, 0, 0, 0, 0] + }, + { + POSITION: [4, 8, -1.4, 8, 0, 0, 0] + }, + { + POSITION: [12, 8, 1.3, 30, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { reload: 3, damage: 1.2, shudder: 0.5 }]), + TYPE: "developerBullet" + } + }, + { + POSITION: [2, 11, 1, 34, 0, 0, 0] + } + ], + TURRETS: [ + { + POSITION: [15, 0, 0, 0, 360, 1], + TYPE: [ "latTop", { COLOR: "#5C533F" } ], + }, + { + POSITION: [10, 0, 0, 0, 360, 1], + TYPE: [ "latTop", { COLOR: "#736245" } ], + }, + { + POSITION: [35, 0, 0, 0, 360, 0], + TYPE: [ "latBase", { COLOR: "#96794E" } ], + }, + ] +} + + +let testLayeredBoss = new LayeredBoss("testLayeredBoss", "Test Layered Boss", "terrestrial", 7, 3, "terrestrialTrapTurret", 5, 7, {SPEED: 10}); +testLayeredBoss.addLayer({gun: { + POSITION: [3.6, 7, -1.4, 8, 0, null, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.factory, { size: 0.5 }]), + TYPE: ["minion", {INDEPENDENT: true}], + AUTOFIRE: true, + SYNCS_SKILLS: true, + }, +}}, true, null, 16); +testLayeredBoss.addLayer({turret: { + POSITION: [10, 7.5, 0, null, 160, 0], + TYPE: "crowbarTurret", +}}, true); + +// FLAIL!!! +Class.flailBallSpike = { + PARENT: "genericTank", + COLOR: "black", + SHAPE: 6, + INDEPENDENT: true, +} +Class.flailBall = { + PARENT: "genericTank", + COLOR: "grey", + HITS_OWN_TYPE: 'hard', + INDEPENDENT: true, + TURRETS: [{ + POSITION: [21.5, 0, 0, 0, 360, 0], + TYPE: "flailBallSpike", + }], + GUNS: [ + { + POSITION: {WIDTH: 8, LENGTH: 10}, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { + range: 0.1, + speed: 0, + maxSpeed: 0, + recoil: 0, + reload: 0.1, + damage: 2.6, + size: 2, + health: 1, + }]), + TYPE: ["bullet", { + ALPHA: 0, + ON: [{ + event: 'tick', + handler: ({body}) => { + body.DAMAGE -= 1; + body.SIZE -= 0.6; + if (body.SIZE < 1) body.kill(); + } + }], + }], + AUTOFIRE: true, + BORDERLESS: true, + DRAW_FILL: false, + } + } + ] +} +Class.flailBolt1 = { + PARENT: "genericTank", + COLOR: "grey", + INDEPENDENT: true, + GUNS: [{ + POSITION: [40, 5, 1, 8, 0, 0, 0] + }], + TURRETS: [{ + POSITION: [48, 56, 0, 0, 360, 1], + TYPE: "flailBall" + }], +} +Class.flailBolt2 = { + PARENT: "genericTank", + COLOR: "grey", + INDEPENDENT: true, + GUNS: [{ + POSITION: [30, 5, 1, 8, 0, 0, 0] + }], + TURRETS: [{ + POSITION: [20, 36, 0, 0, 360, 1], + TYPE: "flailBolt1" + }], +} +Class.flailBolt3 = { + PARENT: "genericTank", + COLOR: "grey", + GUNS: [{ + POSITION: [30, 5, 1, 8, 0, 0, 0] + }], + TURRETS: [{ + POSITION: [18, 36, 0, 0, 360, 1], + TYPE: "flailBolt2" + }], +} +Class.genericFlail = { + PARENT: "genericTank", + STAT_NAMES: statnames.flail, + SYNC_WITH_TANK: true, + SKILL_CAP: [dfltskl, dfltskl, dfltskl, dfltskl, 0, dfltskl, dfltskl, dfltskl, dfltskl, dfltskl], +} +Class.flail = { + PARENT: "genericFlail", + LABEL: "Flail", + TURRETS: [{ + POSITION: [6, 10, 0, 0, 190, 0], + TYPE: ["flailBolt3", { + INDEPENDENT: true + }] + }] +} +Class.doubleFlail = { + PARENT: "genericFlail", + LABEL: "Double Flail", + DANGER: 6, + TURRETS: [{ + POSITION: [6, 10, 0, 0, 190, 0], + TYPE: ["flailBolt3", { + INDEPENDENT: true + }] + }, { + POSITION: [6, 10, 0, 180, 190, 0], + TYPE: ["flailBolt3", { + INDEPENDENT: true + }] + }] +} +Class.tripleFlail = { + PARENT: "genericFlail", + LABEL: "Triple Flail", + DANGER: 7, + TURRETS: [{ + POSITION: [6, 10, 0, 0, 190, 0], + TYPE: ["flailBolt3", { + INDEPENDENT: true + }] + }, { + POSITION: [6, 10, 0, 120, 190, 0], + TYPE: ["flailBolt3", { + INDEPENDENT: true + }] + }, { + POSITION: [6, 10, 0, 240, 190, 0], + TYPE: ["flailBolt3", { + INDEPENDENT: true + }] + }] +} +Class.maceBallSpike = { + PARENT: "genericTank", + COLOR: 9, + SHAPE: 3, + INDEPENDENT: true, +} +Class.maceBall = { + PARENT: "genericTank", + COLOR: "grey", + HITS_OWN_TYPE: 'hard', + INDEPENDENT: true, + TURRETS: [{ + POSITION: [21.5, 0, 0, 0, 360, 0], + TYPE: ["maceBallSpike", { SHAPE: 3 }] + }, ], + GUNS: [ + { + POSITION: {WIDTH: 8, LENGTH: 10}, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { + range: 0.1, + speed: 0, + maxSpeed: 0, + recoil: 0, + reload: 0.1, + damage: 4, + size: 2, + health: 1, + }]), + TYPE: ["bullet", { + ALPHA: 0, + ON: [{ + event: 'tick', + handler: ({body}) => { + body.DAMAGE -= 1; + body.SIZE -= 0.6; + if (body.SIZE < 1) body.kill(); + } + }], + }], + AUTOFIRE: true, + BORDERLESS: true, + DRAW_FILL: false, + } + } + ] +} +Class.maceBolt1 = { + PARENT: "genericTank", + COLOR: "grey", + INDEPENDENT: true, + GUNS: [{ + POSITION: [48, 5, 1, 8, 0, 0, 0] + }], + TURRETS: [{ + POSITION: [76, 56, 0, 0, 190, 1], + TYPE: "maceBall", + }], +} +Class.maceBolt2 = { + PARENT: "genericTank", + COLOR: "grey", + INDEPENDENT: true, + GUNS: [{ + POSITION: [24, 5, 1, 8, 0, 0, 0] + }], + TURRETS: [{ + POSITION: [20, 28, 0, 0, 190, 1], + TYPE: "maceBolt1" + }, + ], +} +Class.maceBolt3 = { + PARENT: "genericTank", + COLOR: "grey", + GUNS: [{ + POSITION: [24, 5, 1, 8, 0, 0, 0] + }], + TURRETS: [{ + POSITION: [18, 28, 0, 0, 190, 1], + TYPE: "maceBolt2", + }], +} +Class.mace = { + PARENT: "genericFlail", + LABEL: "Mace", + DANGER: 6, + TURRETS: [{ + POSITION: [6, 10, 0, 0, 190, 0], + TYPE: ["maceBolt3", { + INDEPENDENT: true + }] + }] +} +Class.mamaBolt1 = { + PARENT: "genericTank", + COLOR: "grey", + INDEPENDENT: true, + GUNS: [{ + POSITION: [48, 5, 1, 8, 0, 0, 0] + }], + TURRETS: [{ + POSITION: [104, 56, 0, 0, 190, 1], + TYPE: "maceBall" + }, + ], +} +Class.mamaBolt2 = { + PARENT: "genericTank", + COLOR: "grey", + INDEPENDENT: true, + GUNS: [{ + POSITION: [18, 5, 1, 8, 0, 0, 0] + }], + TURRETS: [{ + POSITION: [20, 20, 0, 0, 190, 1], + TYPE: "mamaBolt1" + }, + ], +} +Class.mamaBolt3 = { + PARENT: "genericTank", + COLOR: "grey", + INDEPENDENT: true, + GUNS: [{ + POSITION: [18, 5, 1, 8, 0, 0, 0] + }], + TURRETS: [{ + POSITION: [18, 20, 0, 0, 190, 1], + TYPE: "mamaBolt2" + }, + ], +} +Class.bigMama = { + PARENT: "genericFlail", + LABEL: "BIG MAMA", + DANGER: 7, + TURRETS: [{ + POSITION: [6, 10, 0, 0, 190, 0], + TYPE: ["mamaBolt3", { + INDEPENDENT: true + }] + }] +} +Class.ihdtiBall = { + PARENT: "genericTank", + COLOR: "grey", + HITS_OWN_TYPE: 'hard', + INDEPENDENT: true, + TURRETS: [{ + POSITION: [21.5, 0, 0, 0, 360, 0], + TYPE: "maceBallSpike" + }, { + POSITION: [21.5, 0, 0, 180, 360, 0], + TYPE: "maceBallSpike" + }], + GUNS: [ + { + POSITION: {WIDTH: 8, LENGTH: 10}, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { + range: 0.1, + speed: 0, + maxSpeed: 0, + recoil: 0, + reload: 0.1, + damage: 6, + size: 2, + health: 1, + }]), + TYPE: ["bullet", { + ALPHA: 0, + ON: [{ + event: 'tick', + handler: ({body}) => { + body.DAMAGE -= 1; + body.SIZE -= 0.6; + if (body.SIZE < 1) body.kill(); + } + }], + }], + AUTOFIRE: true, + BORDERLESS: true, + DRAW_FILL: false, + } + } + ] +} +Class.ihdtiBolt1 = { + PARENT: "genericTank", + COLOR: "grey", + INDEPENDENT: true, + GUNS: [{ + POSITION: [48, 5, 1, 8, 0, 0, 0] + }], + TURRETS: [{ + POSITION: [76, 56, 0, 0, 190, 1], + TYPE: "ihdtiBall" + } + ] +} +Class.ihdtiBolt2 = { PARENT: "genericTank", COLOR: "grey", + INDEPENDENT: true, + GUNS: [{ + POSITION: [24, 5, 1, 8, 0, 0, 0] + }], + TURRETS: [{ + POSITION: [20, 28, 0, 0, 190, 1], + TYPE: "ihdtiBolt1" + } + ] +} +Class.ihdtiBolt3 = { + PARENT: "genericTank", + COLOR: "grey", + GUNS: [{ + POSITION: [24, 5, 1, 8, 0, 0, 0] + }], + TURRETS: [{ + POSITION: [18, 28, 0, 0, 190, 1], + TYPE: "ihdtiBolt2" + } + ] +} +Class.itHurtsDontTouchIt = { + PARENT: "genericFlail", + LABEL: "It hurts dont touch it", + DANGER: 7, + TURRETS: [{ + POSITION: [6, 10, 0, 0, 190, 0], + TYPE: ["ihdtiBolt3", { + INDEPENDENT: true + }] + }] +} +Class.flangle = { + PARENT: "genericFlail", + LABEL: "Flangle", + DANGER: 6, + STAT_NAMES: statnames.mixed, + GUNS: [ + { + POSITION: [16, 8, 1, 0, 0, 150, 0.1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), + TYPE: "bullet", + LABEL: "thruster", + }, + }, + { + POSITION: [16, 8, 1, 0, 0, 210, 0.1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), + TYPE: "bullet", + LABEL: "thruster", + }, + }, + ], + TURRETS: [{ + POSITION: [6, 10, 0, 0, 190, 0], + TYPE: ["flailBolt3", { + INDEPENDENT: true + }] + }], + SKILL_CAP: [dfltskl, dfltskl, dfltskl, dfltskl, dfltskl, dfltskl, dfltskl, dfltskl, dfltskl, dfltskl], +} +Class.flooster = { + PARENT: "genericFlail", + LABEL: "Flooster", + DANGER: 7, + STAT_NAMES: statnames.mixed, + GUNS: [ + { + POSITION: [13, 8, 1, 0, -1, 140, 0.6], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), + TYPE: "bullet", + LABEL: "thruster", + }, + }, + { + POSITION: [13, 8, 1, 0, 1, 220, 0.6], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), + TYPE: "bullet", + LABEL: "thruster", + }, + }, + { + POSITION: [16, 8, 1, 0, 0, 150, 0.1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), + TYPE: "bullet", + LABEL: "thruster", + }, + }, + { + POSITION: [16, 8, 1, 0, 0, 210, 0.1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), + TYPE: "bullet", + LABEL: "thruster", + }, + }, + ], + TURRETS: [{ + POSITION: [6, 10, 0, 0, 190, 0], + TYPE: ["flailBolt3", { + INDEPENDENT: true + }] + }], + SKILL_CAP: [dfltskl, dfltskl, dfltskl, dfltskl, dfltskl, dfltskl, dfltskl, dfltskl, dfltskl, dfltskl], +} +Class.flace = { + PARENT: "genericFlail", + LABEL: "Flace", + DANGER: 7, + STAT_NAMES: statnames.mixed, + GUNS: [ + { + POSITION: [16, 8, 1, 0, 0, 150, 0.1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), + TYPE: "bullet", + LABEL: "thruster", + }, + }, + { + POSITION: [16, 8, 1, 0, 0, 210, 0.1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), + TYPE: "bullet", + LABEL: "thruster", + }, + }, + ], + TURRETS: [{ + POSITION: [6, 10, 0, 0, 190, 0], + TYPE: ["maceBolt3", { + INDEPENDENT: true + }] + }], + SKILL_CAP: [dfltskl, dfltskl, dfltskl, dfltskl, dfltskl, dfltskl, dfltskl, dfltskl, dfltskl, dfltskl], +} + +Class.Trapper_guy = { + PARENT: "trapper", + LABEL: "Trapper_guy", + UPGRADE_COLOR: "blue", + SHAPE: "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/6fcc71bf-255f-4d26-b13e-e3f9f68fb77a.image.png?v=1705291478159", + GUNS: [ + { + POSITION: [15, 7, 1, 0, 0, 0, 0] + }, + { + POSITION: [3, 7, 1.7, 15, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap]), + TYPE: "trap", + STAT_CALCULATOR: "trap" + } + }, { + POSITION: [3, 7, 1.7, 15, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.nomove, g.halfrange, { damage: 5, pen: 5 }]), + TYPE: "shockwave", + STAT_CALCULATOR: "trap", + ALT_FIRE: true + } + } + ] +}; +Class.shockwave = { + PARENT: "bullet", + LABEL: "funy", + SHAPE: 'M 0 -1.1 A 1 1 0 0 0 0 1.1 A 1 1 0 0 0 0 -1.1 Z M 0 -1 A 0.001 0.001 0 0 1 0 1 A 0.001 0.001 0 0 1 0 -1', + MOTION_TYPE: "trappershockwave" +}; +Class.watergun = { + LABEL: 'Auto Turret', + SYNCS_SKILLS: true, + SHAPE: "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/e304fc26-480b-47b5-8270-949f7df44d92.image.png?v=1705294702951", + BODY: { + FOV: 1, + }, + COLOR: "blue", + CONTROLLERS: ['onlyAcceptInArc', 'nearestDifferentMaster'], + GUNS: [{ + POSITION: [10, 8, 1, 8, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.autoTurret, g.op, { damage: 5, pen: 5 }]), + TYPE: "bullet", + HAS_NO_RECOIL: true + } + } + ] +} +Class.watergundormant = { + LABEL: 'Auto Turret', + SYNCS_SKILLS: true, + SHAPE: "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/e304fc26-480b-47b5-8270-949f7df44d92.image.png?v=1705294702951", + BODY: { + FOV: 1 + }, + COLOR: 16, + GUNS: [{ + POSITION: [13.5, 10, 1, 8, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.fake]), + TYPE: "bullet" + } + } + ] +} +Class.waterpet = { + PARENT: "boomerang", + LABEL: "Base", + SHAPE: 0, + INDEPENDENT: true, + TURRETS: [{ + POSITION: [25, 0, 0, 180, 360, 1], + TYPE: "watergun", + }], +ON: [{ + event: "death", + handler: ({ body }) => { + if (!body.master.isDead) return + body.master.define(Class.watertank) + } + } + ] +}; +Class.watertank = { + PARENT: "triAngle", + LABEL: "Waduh", + DANGER: 6, + SYNC_TURRET_SKILLS: true, + GUNS: [ + { + POSITION: [18, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.triAngleFront, { recoil: 4 }]), + TYPE: "bullet", + LABEL: "Front", + }, + }, + { + POSITION: [16, 8, 1, 0, 0, 150, 0.1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), + TYPE: "bullet", + STAT_CALCULATOR: "thruster" + }, + }, + { + POSITION: [16, 8, 1, 0, 0, 210, 0.1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), + TYPE: "bullet", + STAT_CALCULATOR: "thruster" + }, + }, { + POSITION: [1, 10, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, g.setTrap, g.boomerang, g.bitlessspeed, { damage: 5, pen: 5, health: 5 }]), + TYPE: "waterpet", + ALT_FIRE: true, + } + }], + TURRETS: [{ + POSITION: [17, 9.85, 0, 180, 360, 1], + TYPE: "watergundormant", + }], + ON: [{ + event: "altFire", + handler: ({ body }) => { + body.define(Class.watertankFire) + } + } + ] +}; +Class.watertankFire = { + PARENT: "genericTank", + LABEL: "Waduh", + DANGER: 6, + GUNS: [{ + POSITION: [18, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.triAngleFront, { recoil: 4 }]), + TYPE: "bullet", + LABEL: "Front", + }, + }, + { + POSITION: [16, 8, 1, 0, 0, 150, 0.1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), + TYPE: "bullet", + STAT_CALCULATOR: "thruster" + }, + }, + { + POSITION: [16, 8, 1, 0, 0, 210, 0.1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), + TYPE: "bullet", + STAT_CALCULATOR: "thruster" + }, + }, + ] +}; +Class.piszerbeam = { + PARENT: "genericTank", + LABEL: "Pissliner", + COLOR: "yellow", + TEAM: TEAM_ROOM, + DANGER: 7, + BODY: { + ACCELERATION: base.ACCEL * 0.6, + SPEED: base.SPEED * 0.85, + FOV: base.FOV * 3, + }, + GUNS: [ + { + POSITION: [25, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.streamliner]), + TYPE: "bullet", + }, + }, + { + POSITION: [23, 8, 1, 0, 0, 0, 0.2], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.streamliner]), + TYPE: "bullet", + }, + }, + { + POSITION: [21, 8, 1, 0, 0, 0, 0.4], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.streamliner]), + TYPE: "bullet", + }, + }, + { + POSITION: [19, 8, 1, 0, 0, 0, 0.6], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.streamliner]), + TYPE: "bullet", + }, + }, + { + POSITION: [17, 8, 1, 0, 0, 0, 0.8], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.streamliner]), + TYPE: "bullet", + }, + }, { + POSITION: [25, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.streamliner, g.op, g.op]), + TYPE: "oplaser", + ALT_FIRE: true + }, + }, + { + POSITION: [23, 8, 1, 0, 0, 0, 0.2], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.streamliner, g.op, g.op]), + TYPE: "oplaser", + ALT_FIRE: true + + }, + }, + { + POSITION: [21, 8, 1, 0, 0, 0, 0.4], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.streamliner, g.op, g.op]), + TYPE: "oplaser", + ALT_FIRE: true + + }, + }, + { + POSITION: [19, 8, 1, 0, 0, 0, 0.6], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.streamliner, g.op, g.op]), + TYPE: "oplaser", + ALT_FIRE: true + + }, + }, + { + POSITION: [17, 8, 1, 0, 0, 0, 0.8], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.streamliner, g.op, g.op]), + TYPE: "oplaser", + ALT_FIRE: true + + }, + }, + ], +}; +Class.oplaser = { + PARENT: "bullet", + SHAPE: -1, + MOTION_TYPE: "fuckingnuclearbomb", + BODY: { + PENETRATION: 10, + SPEED: 30, + RANGE: 155, + DENSITY: 1.25, + HEALTH: 999, + DAMAGE: 999, + PUSHABILITY: 0.3, + }, + BUFF_VS_FOOD: true, +} +Class.deltabaseBullet = { + PARENT: "boomerang", + LABEL: "Base", + SHAPE: 'M 0 -1.1 A 1 1 0 0 0 0 1.1 A 1 1 0 0 0 0 -1.1 Z M 0 -1 A 0.001 0.001 0 0 1 0 1 A 0.001 0.001 0 0 1 0 -1', + CONTROLLERS: [["spin", { independent: true, speed: 0.1 }]], + INDEPENDENT: true, + COLOR: "rainbow", + BODY: { + COLOR: "rainbow" + }, + TURRETS: [{ + POSITION: [4.65, 9.85, 0, 90, 220, 1], + TYPE: ["deltagun", { COLOR: "rainbow" }] + }, { + POSITION: [4.65, 9.85, 0, 270, 220, 1], + TYPE: ["deltagun", { COLOR: "rainbow" }] + }], +ON: [{ + event: "death", + handler: ({ body }) => { + if (!body.master.isDead) return; + body.master.define(Class.baseThrowerDelta) + } + } + ] +}; +Class.deltagun = { + LABEL: 'Auto Turret', + SYNCS_SKILLS: true, + BODY: { + FOV: 1 + }, + COLOR: 16, + CONTROLLERS: ['onlyAcceptInArc', 'nearestDifferentMaster'], + GUNS: [{ + POSITION: [13.5, 10, 1, 8, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.autoTurret, g.halfreload, g.halfspeed, g.op, g.op, g.op]), + TYPE: "grenade", + HAS_NO_RECOIL: true + } + } + ] +} +Class.turretBaseDelta = { + LABEL: "Basethingygygyyasgsdgajskhg", + SHAPE: 'M 0 -1.1 A 1 1 0 0 0 0 1.1 A 1 1 0 0 0 0 -1.1 Z M 0 -1 A 0.001 0.001 0 0 1 0 1 A 0.001 0.001 0 0 1 0 -1', + COLOR: "rainbow",//iT WonT FUckING SpIN + SYNC_TURRET_SKILLS: true, + CONTROLLERS: [["spin", { independent: true }]], + INDEPENDENT: true, + TURRETS: [{ + POSITION: [4.65, 9.85, 0, 90, 220, 1], + TYPE: ["deltagun", { COLOR: "rainbow" }] + }, { + POSITION: [4.65, 9.85, 0, 270, 220, 1], + TYPE: ["deltagun", { COLOR: "rainbow" }] + }] +}; +Class.deltaDeco = { + SHAPE: "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/2024_01_15_05q_Kleki.png", +}; +Class.baseThrowerFireDelta = { + PARENT: "genericTank", + LABEL: "Delta Congregation", + DANGER: 6, + GUNS: [ + { + POSITION: [26, 7, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.lowPower, g.halfrecoil, g.machineGun, g.op, g.op, { recoil: 1.15 }]), + TYPE: "bullet", + }, + }, + { + POSITION: [23, 10, 1, 0, 0, 0, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.lowPower, g.halfrecoil, g.machineGun, g.op, g.op, { recoil: 1.15 }]), + TYPE: "bullet", + }, + }, + { + POSITION: [12, 10, 1.4, 8, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.halfrecoil, g.op, g.op]), + TYPE: "bullet", + }, + }, { + POSITION: [24, 1, 1, 0, 0, 0, 2 / 3], + PROPERTIES: { + COLOR: 'red', + SHOOT_SETTINGS: combineStats([g.basic, g.op, g.op, g.halfrecoil, g.op]), + TYPE: "laser", + HAS_NO_RECOIL: true, + }, + }], + TURRETS: [{ + POSITION: [34, 0, 0, 0, 360, 3], + TYPE: "deltaDeco" + } + ] +}; +Class.baseThrowerDelta = { + PARENT: "genericTank", + LABEL: "Delta", + DANGER: 6, + SYNC_TURRET_SKILLS: true, + GUNS: [ + { + POSITION: [26, 7, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.lowPower, g.machineGun, { recoil: 1.15 }]), + TYPE: "bullet", + }, + }, + { + POSITION: [23, 10, 1, 0, 0, 0, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.lowPower, g.machineGun, { recoil: 1.15 }]), + TYPE: "bullet", + }, + }, + { + POSITION: [12, 10, 1.4, 8, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun]), + TYPE: "bullet", + }, + }, { + POSITION: [1, 38, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, g.setTrap, g.boomerang, g.bitlessspeed, g.op, g.xxtrahealth]), + TYPE: ["deltabaseBullet"], + ALT_FIRE: true, + ALPHA: 0, + HAS_NO_RECOIL: true, + } + }], + TURRETS: [{ + POSITION: [34, 0, 0, 0, 360, 0], + TYPE: "turretBaseDelta" + }, { + POSITION: [34, 0, 0, 0, 360, 3], + TYPE: "deltaDeco" + }], + ON: [{ + event: "altFire", + handler: ({ body }) => { + body.define(Class.baseThrowerFireDelta) + } + } + ] +}; +Class.pounerbullet = { + PARENT: "bullet", + SHAPE: 'https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/74ccbc9f-e1fa-4144-8a05-bebbd593fba3.image.png?v=1705772359444' +}; +Class.pouner = { + PARENT: "genericTank", + LABEL: "PouNer", + SHAPE: 'https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Untitled979_20240120123618.png?v=1705772311845', + GUNS: [ + { + POSITION: [20.5, 12, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.op]), + TYPE: "pounerbullet" + } + } + ] +} + +Class.grappletest = { + PARENT: "genericTank", + LABEL: "GrappleTest", + DANGER: 4, + ON: [ + { + event: "define", + handler: ({ body }) => { + if (body.hasDefined) { + body.children = [] + body.hasDefined = false + } else { + body.hasDefined = true + } + } + }, + { + event: "tick", + handler: ({ body }) => { + if (body.children != null) { + for (let instance of body.children) { + let deltaX = instance.x - body.x, + deltaY = instance.y - body.y, + distance = util.getDistance(instance, body) + angle = Math.atan2(deltaY, deltaX), + combinedRadii = instance.realSize + body.realSize; + body.velocity.x += 5 * Math.cos(angle) + body.velocity.y += 5 * Math.sin(angle) + if (combinedRadii * 1.3 > distance) { + body.children = [] + break + } + + } + } + if (body.socket.player.command.ability) { + for (instance of entities) { + if (instance != body && instance.type == "wall" && util.getDistance(instance, { + x: body.control.target.x + body.x, + y: body.control.target.y + body.y + }) < instance.size * 1.3) { + if (body.children == 0) { + body.children.push(instance) + } + } + } + } + } + } + ] +} +Class.hook = { + PARENT: "bullet", + LABEL: "boolet", + ON: [ + { + event: "define", + handler: ({ body }) => { + if (body.master.hasDefined) { + body.master.children = [] + body.master.hasDefined = false + } else { + body.master.hasDefined = true + } + } + }, + { + event: "tick", + handler: ({ body }) => { + if (body.master.children != null) { + for (let instance of body.master.children) { + let deltaX = instance.x - body.master.x, + deltaY = instance.y - body.master.y, + distance = util.getDistance(instance, body) + angle = Math.atan2(deltaY, deltaX), + combinedRadii = instance.realSize + body.realSize; + body.master.velocity.x += 5 * Math.cos(angle) + body.master.velocity.y += 5 * Math.sin(angle) + if (combinedRadii * 1.3 > distance) { + body.master.children = [] + break + } + + } + } + if (body.master.control.fire) { + for (instance of entities) { + if (instance != body.master && instance.type == "wall" && util.getDistance(instance, { + x: body.master.control.target.x + body.master.x, + y: body.master.control.target.y + body.master.y + }) < instance.size * 1.3) { + if (body.master.children == 0) { + body.master.children.push(instance) + } + } + } + } + } + } + ] +}; +Class.hook2 = { + PARENT: "bullet", + TYPE: "hook", + LABEL: "boolet2", + BODY: { + SPEED: 3, + RANGE: 100, + }, + ON: [{ + event: "collide", + handler: ({ instance, other }) => { + if (other.type === "hookpoint") { + instance.master.sendMessage(`Grappling...`) + instance.x = other.x; + instance.y = other.y; + instance.velocity.x = 0; + instance.velocity.y = 0; + let deltaX = other.x - instance.master.x, + deltaY = other.y - instance.master.y, + distance = util.getDistance(other, instance.master) + angle = Math.atan2(deltaY, deltaX), + combinedRadii = other.realSize + instance.master.realSize; + instance.master.velocity.x += 5 * Math.cos(angle) + instance.master.velocity.y += 5 * Math.sin(angle) + if (util.getDistance(other, instance.master) < other.size && util.getDistance(other, instance.master) > -other.size) { instance.kill() } + } + } + }] +} +Class.grappletest2 = { + PARENT: "genericTank", + LABEL: "Grappling Hook 2", + DANGER: 7, + GUNS: [ + { + POSITION: [19, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.single, {damage: 0.01, health: 25, speed: 2}]), + TYPE: "hook2", + //MAX_CHILDREN: 1 + } + }, + { + POSITION: [5.5, 8, -1.8, 6.5, 0, 0, 0] + } + ] +}; + +Class.devtesttemplate = { + PARENT: "genericTank", + LABEL: "Single", + DANGER: 7, + GUNS: [ + { + POSITION: [19, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.single]), + TYPE: "bullet" + } + }, + { + POSITION: [5.5, 8, -1.8, 6.5, 0, 0, 0] + } + ] +}; +Class.alchem = { + PARENT: "genericTank", + LABEL: "Alchem", + DANGER: 7, + GUNS: [ + { + POSITION: [19, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { damage: 0, pen: 10, health: 100 }]), + TYPE: "stickyTrap" + } + }, + { + POSITION: [5.5, 8, -1.6, 6.5, 0, 0, 0] + }, { + POSITION: [13.95, 5.15, 1, 0, 0, 0, 0], + PROPERTIES: { + COLOR: "white" + } + } + ] +}; +Class.speedoflight = { + PARENT: "genericTank", + LABEL: "SpeedOfLight", + DANGER: 7, + GUNS: [ + { + POSITION: [24, 4, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.acceltospeedoflight, { range: 999 }]), + TYPE: ["bullet", { MOTION_TYPE: "acceleratetothespeedoflight" }] + } + } + ] +}; +Class.maxStatTank = { + PARENT: ['genericTank'], + DANGER: 11, + BODY: { + ACCELERATION: base.ACCEL*2, + SPEED: base.SPEED*2, + HEALTH: base.HEALTH*2, + DAMAGE: base.DAMAGE*2, + PENETRATION: base.PENETRATION*2, + SHIELD: base.SHIELD*2, + REGEN: base.REGEN*2, + FOV: base.FOV*2, + DENSITY: base.DENSITY*2, + PUSHABILITY: 2, + HETERO: 6, + }, + SKILL_CAP: Array(10).fill(255), + SKILL: Array(10).fill(255), +} +Class.qlamgSpinnerTurret = { + PARENT: "genericTank", + LABEL: "Spinner Turret", + GUNS: [ + { + POSITION: [15, 3.5, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.gunner, g.nailgun, g.literallyamachinegun]), + TYPE: "bullet" + } + }, { + POSITION: [15, 3.5, 1, 0, 0, 0, 0.1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.gunner, g.nailgun, g.literallyamachinegun]), + TYPE: "bullet" + } + }, { + POSITION: [15, 3.5, 1, 0, 0, 0, 0.2], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.gunner, g.nailgun, g.literallyamachinegun]), + TYPE: "bullet" + } + }, { + POSITION: [15, 3.5, 1, 0, 0, 0, 0.3], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.gunner, g.nailgun, g.literallyamachinegun]), + TYPE: "bullet" + } + }, { + POSITION: [15, 3.5, 1, 0, 0, 0, 0.4], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.gunner, g.nailgun, g.literallyamachinegun]), + TYPE: "bullet" + } + }, { + POSITION: [15, 3.5, 1, 0, 0, 0, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.gunner, g.nailgun, g.literallyamachinegun]), + TYPE: "bullet" + } + }, { + POSITION: [15, 3.5, 1, 0, 0, 0, 0.6], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.gunner, g.nailgun, g.literallyamachinegun]), + TYPE: "bullet" + } + }, { + POSITION: [15, 3.5, 1, 0, 0, 0, 0.7], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.gunner, g.nailgun, g.literallyamachinegun]), + TYPE: "bullet" + } + }, { + POSITION: [15, 3.5, 1, 0, 0, 0, 0.8], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.gunner, g.nailgun, g.literallyamachinegun]), + TYPE: "bullet" + } + }, { + POSITION: [15, 3.5, 1, 0, 0, 0, 0.9], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.gunner, g.nailgun, g.literallyamachinegun]), + TYPE: "bullet" + } + }, + ] +} +Class.quiteliterallyAMachineGun = { + PARENT: "genericTank", + LABEL: "Quite Literally a Motherfucking Machine Gun", + UPGRADE_COLOR: "red", + DANGER: 7, + BODY: { + FOV: base.FOV * 1.2 + }, + TURRETS: [ + { + POSITION: [10, 14, 0, 0, 0, 1], + TYPE: "qlamgSpinnerTurret" + }, { + POSITION: [5, 14, 0, 0, 0, 3], + TYPE: "lamgSpinnerTurret" + }, { + POSITION: [10, 14, 0, 0, 0, 2], + TYPE: "lamgSpinnerTurret" + } + ], + GUNS: [ + { + POSITION: [22, 8, 1, 0, 0, 0, 0] + }, { + POSITION: [2, 3.5, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.gunner, g.nailgun, g.literallyamachinegun, g.op]), + TYPE: "bullet" + } + } + ] +} +Class.goofysatellite = { + LABEL: "Satellite", + TYPE: "bullet", + ACCEPTS_SCORE: false, + CONTROLLERS: ["orbit"], + DANGER: 2, + SHAPE: 0, + LAYER: 13, + BODY: { + PENETRATION: 1.2, + PUSHABILITY: 0.6, + ACCELERATION: 0.75, + HEALTH: 0.3, + DAMAGE: 3.375, + SPEED: 10, + RANGE: 10, + DENSITY: 0.03, + RESIST: 1.5, + FOV: 0.5, + }, + COLOR: 'nero', + DRAW_HEALTH: true, + CLEAR_ON_MASTER_UPGRADE: true, + BUFF_VS_FOOD: true, + DIE_AT_RANGE: true, +} + +Class.goofywhirlwind = { + PARENT: "genericTank", + LABEL: "Goofy Whirlwind", + ANGLE: 60, + CONTROLLERS: ["whirlwind"], + HAS_NO_RECOIL: true, + STAT_NAMES: statnames.whirlwind, + TURRETS: [ + { + POSITION: [8, 0, 0, 0, 360, 1], + TYPE: "whirlwindDeco" + } + ], + AI: { + SPEED: 2, + }, + GUNS: (() => { + let output = [] + for (let i = 0; i < 5; i++) { + output.push({ + POSITION: {WIDTH: 8, LENGTH: 1, DELAY: i * 0.25}, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.satellite]), + TYPE: ["goofysatellite", {ANGLE: i * 72}], + MAX_CHILDREN: 4, + AUTOFIRE: true, + SYNCS_SKILLS: false, + } + }) + } + return output + })() +} + +Class.pisseroo = { + PARENT: ['basic'], + LABEL: 'Winsor', + UPGRADES_TIER_0: [], + RESET_UPGRADE_MENU: true, + ON: [ + { + event: "fire", + handler: ({ body, globalMasterStore: store, gun }) => { + if (gun.identifier != 'pisserooGun') return + store.pisseroo_i ??= 0; + store.pisseroo_i++; + store.pisseroo_i %= 4; + body.define(Class.winsor0.UPGRADES_TIER_0[store.pisseroo_i]); + setTimeout(() => body.define("pisseroo"), 3000); + } + } + ], GUNS: [{ - POSITION: [30, 5, 1, 8, 0, 0, 0] - }], + POSITION: {}, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic]), + TYPE: 'bullet', + IDENTIFIER: 'pisserooGun' + } + }] +} +Class.adsfoipuasdfiopu = { + PARENT: "genericTank", + LABEL: "Random tank i made in music class because i can", + UPGRADE_TOOLTIP: "send this * to the penis explosion chamber and have his penis exploded immediately", + GUNS: [{ + POSITION: [21, 10, 0, 0, 1, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.op]), + TYPE: "bullet" + } + } + ] +} +Class.adsfoipuasdfiopu.UPGRADE_COLOR = "animatednero", +Class.adsfoipuasdfiopu2 = { + PARENT: "genericTank", + LABEL: "Random tank i made on the bus because i can", + UPGRADE_TOOLTIP: "send this non-* to the asshole explosion chamber and have his ashole exploded immediately", + GUNS: [{ + POSITION: [21, 0, 0, 0, 1, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.op]), + TYPE: "bullet" + } + }, { + POSITION: [17, 0, 0, 0, 2, 180, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.op]), + TYPE: "bee", + MAX_CHILDREN: 30, + } + } + ] +} +Class.adsfoipuasdfiopu3 = { + PARENT: "genericTank", + LABEL: "Random tank i made in health class because i can", + UPGRADE_TOOLTIP: "send this nonon-* to the tit explosion chamber and have her tits exploded immediately", + GUNS: [{ + POSITION: [18, 8, 1, 0, 10, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic]), + TYPE: "denseasfbullet" + } + } + ] +} +Class.adsfoipuasdfiopu2.UPGRADE_COLOR = "animatednero", +//wait whats stuff +Class.placeableWall = { + PARENT: "rock", + LABEL: "Wall", + SIZE: 30, + SHAPE: 4, + CLEAR_ON_MASTER_UPGRADE: false, + TEAM: TEAM_ENEMIES, + VARIES_IN_SIZE: false, +}; +Class.placeableWallSmall = { + PARENT: "rock", + LABEL: "Wall", + SIZE: 15, + SHAPE: 4, + CLEAR_ON_MASTER_UPGRADE: false, + TEAM: TEAM_ENEMIES, + VARIES_IN_SIZE: false, +}; +Class.wallPlacerThing = { + PARENT: "genericTank", + SHAPE:0, + MIRROR_MASTER_ANGLE: true, + INTANGIBLE: true, + DRAW_SELF: false, + COLOR: 16, + CLEAR_ON_MASTER_UPGRADE: false, + BODY: { + ACCELERATION: 0.1, + SPEED: true, + HEALTH: 340282366920938463463374607431768211455, + RESIST: 1, + SHIELD: 340282366920938463463374607431768211455, + REGEN: 340282366920938463463374607431768211455, + DAMAGE: false, + PENETRATION: true, + RANGE: true, + FOV: true, + SHOCK_ABSORB: 340282366920938463463374607431768211455, + RECOIL_MULTIPLIER: false, + DENSITY: 340282366920938463463374607431768211455, + STEALTH: true, + PUSHABILITY: false, + HETERO: false, + }, + MOTION_TYPE: "aimassist", + GUNS: [ + { + POSITION: [0, 20, 1, 10, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([{reload:10, speed:0, maxSpeed:0, shudder:0.0001, spray:0.0001}]), + TYPE: "placeableWall", + COLOR: 16, + LABEL: "", + STAT_CALCULATOR: 0, + WAIT_TO_CYCLE: false, + AUTOFIRE: false, + SYNCS_SKILLS: false, + MAX_CHILDREN: 0, + ALT_FIRE: false, + NEGATIVE_RECOIL: false, + DRAW_FILL:false, + BORDERLESS:true, + }, + }, + ], + +}; +Class.wallPlacer = { + PARENT: "genericTank", + LABEL: "Messin' Around", + BODY: { + ACCELERATION: base.ACCEL * 1, + SPEED: base.SPEED * 1, + HEALTH: base.HEALTH * 1, + DAMAGE: base.DAMAGE * 1, + PENETRATION: base.PENETRATION * 1, + SHIELD: base.SHIELD * 1, + REGEN: base.REGEN * 1, + FOV: base.FOV * 1, + DENSITY: base.DENSITY * 1, + PUSHABILITY: 1, + HETERO: 3, + }, + GUNS: [ + { + POSITION: [16, 20, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic,{reload:1/8}]), + TYPE: "wallPlacerThing", + COLOR: 16, + LABEL: "", + STAT_CALCULATOR: 0, + WAIT_TO_CYCLE: false, + AUTOFIRE: false, + SYNCS_SKILLS: false, + MAX_CHILDREN: 1, + ALT_FIRE: false, + NEGATIVE_RECOIL: false, + }, + }, + ], +}; +Class.lavenderspawner = { + PARENT: "spectator", + LABEL: "Lavender Spawner", + SKILL_CAP: [31, 0, 0, 0, 0, 0, 0, 0, 0, 31], + GUNS: [{ + POSITION: [14, 12, 1, 4, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { recoil: 0 }]), + TYPE: "bullet" + } + }, { + POSITION: [12, 12, 1.4, 4, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { recoil: 0 }]), + INDEPENDENT_CHILDREN: true, + TYPE: "trplnrBoss", + ALT_FIRE: true + }, + }], + }; +Class.solariospawner = { + PARENT: "spectator", + LABEL: "Solario Spawner", + SKILL_CAP: [31, 0, 0, 0, 0, 0, 0, 0, 0, 31], + GUNS: [{ + POSITION: [14, 12, 1, 4, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { recoil: 0 }]), + TYPE: "bullet" + } + }, { + POSITION: [12, 12, 1.4, 4, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { recoil: 0 }]), + INDEPENDENT_CHILDREN: true, + TYPE: "solario", + ALT_FIRE: true + }, + }], + }; +Class.imagetest = { + PARENT: "genericTank", + UPGRADE_COLOR: "black", + LABEL: "PapyrusButBlackHoleOfDeath.exe", + SHAPE: 'https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Papyrus.webp?v=1701450294185', + DANGER: 7, + GUNS: [ + { + POSITION: [2, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.single]), + TYPE: "spaghetti" + } + } + ], + ON: [ + { + event: "damage", + handler: ({ body, damageInflictor, damageTool }) => { + damageTool[0].kill() + } + }, + { + event: "tick", + handler: ({ body }) => { + for (let instance of entities) { + let diffX = instance.x - body.x, + diffY = instance.y - body.y, + dist2 = diffX ** 2 + diffY ** 2, + number1 = 1, + number2 = 1, + number3 = 1/7, + number4 = 1, + number5 = 1, + distance = 250, + forceMulti = (((((body.size / 12)*250) ** 2)** number1) * number2) / dist2; + if (dist2 <= ((body.size / 12)*250) ** 2) { + if (instance.id != body.id /*&& !instance.ac && instance.alpha*/) { + instance.velocity.x += util.clamp(body.x - instance.x, -90, 90) * instance.damp * ((number5 - (number5/((forceMulti ** number3)* number4)))+ 0.001);//0.05 + instance.velocity.y += util.clamp(body.y - instance.y, -90, 90) * instance.damp * ((number5 - (number5/((forceMulti ** number3)* number4)))+ 0.001);//0.05 + } + } + if (dist2 < body.size ** 2 + instance.size ** 2) { + if (instance.id != body.id) { + instance.isProtected = false; + instance.invuln = false; + instance.damageReceived = Infinity, + instance.kill(), + instance.destroy(), + instance.removeFromGrid(), + instance.isGhost = true; + } + } + } + } + }, + ], +} +Class.papyrus = { + PARENT: "genericTank", + LABEL: "Papyrus", + UPGRADE_COLOR: 23, + SHAPE: 'https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Papyrus.webp?v=1701450294185', + DANGER: 7, + GUNS: [ + { + POSITION: [2, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.single]), + TYPE: "spaghetti" + } + } + ] +} +Class.oppenheimer = { + PARENT: "genericTank", + LABEL: "Oppen Heimer", + DANGER: 7, + ARENA_CLOSER: true, + GUNS: [ + { + POSITION: [19, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.single]), + TYPE: "nuke" + } + }, + { + POSITION: [5.5, 8, -1.8, 6.5, 0, 0, 0] + } + ] +} +Class.homingdevbullet = { + PARENT: "bullet", + TYPE: "swarm", + SHAPE: [[-1, -1], [1, -1], [2, 0], [1, 1], [-1, 1]], + ACCEPTS_SCORE: false, + MOTION_TYPE: "swarm", + CONTROLLERS: ["nearestDifferentMaster", "mapTargetToGoal"], + BUFF_VS_FOOD: true, + AI: { + FARMER: true + }, + INDEPENDENT: true +} +Class.homingdev = { + PARENT: "developer", + LABEL: "Homing Developer", + GUNS: [ + { + POSITION: [18, 10, -1.4, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.op]), + TYPE: "homingdevbullet" + } + } + ] +} +Class.winsor0 = { + PARENT: "genericTank", + LABEL: "Wi3nsor", + SHAPE: 'https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Papyrus.webp?v=1701450294185', + DANGER: 7, + GUNS: [ + { + POSITION: [2, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.single]), + TYPE: "bullet" + } + } + ] +} + +Class.winsor1 = { + PARENT: "genericTank", + LABEL: "Winsor has no Friends 🧐", + SIZE: 30, + SHAPE: 'https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/IMG_20231204_144411762_LAYER.jpg?v=1701714034323', + DANGER: 7, + GUNS: [ + { + POSITION: [2, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.single]), + TYPE: "bullet" + } + } + ] +} +Class.winsor2 = { + PARENT: "genericTank", + LABEL: "Winsor has no Brain 🧐🧐", + SIZE: 30, + SHAPE: 'https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/IMG_20231204_144409218_LAYER.jpg?v=1701714037274', + DANGER: 7, + GUNS: [ + { + POSITION: [2, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.single]), + TYPE: "bullet" + } + } + ] +} +Class.winsor3 = { + PARENT: "genericTank", + LABEL: "Winsor has no Muscle 🧐🧐🧐", + SIZE: 30, + SHAPE: 'https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/IMG_20231204_144406913_LAYER.jpg?v=1701714040278', + DANGER: 7, + GUNS: [ + { + POSITION: [2, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.single]), + TYPE: "bullet" + } + } + ] +} +Class.winsor4 = { + PARENT: "genericTank", + LABEL: "And Winsor certainly, has no Bitches 🧐🧐🧐🧐", + SIZE: 30, + SHAPE: 'https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/IMG_20231204_144358408_LAYER.jpg?v=1701714043765', + DANGER: 7, + GUNS: [ + { + POSITION: [2, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.single]), + TYPE: "bullet" + } + } + ] +} +Class.pickaxe = { + PARENT: "genericTank", + TYPE: "flail", + COLOR: "teal", + BODY: { + DENSITY: 2 * base.DENSITY, + HEALTH: 10000, + SHIELD: 10000, + DAMAGE: 4.5, + REGEN: 10000 + }, + HITS_OWN_TYPE: 'hard', + INDEPENDENT: true, + SHAPE: "M -0 -2 C 1.5 -1 1.5 1 0 2 C 1 1 1 -1 -0 -2", +} +Class.pickaxehandle = { + PARENT: "genericTank", + TYPE: "shield", + COLOR: "brown", + BODY: { + HEALTH: 10000, + SHIELD: 10000, + REGEN: 10000 + }, + HITS_OWN_TYPE: 'hard', + INDEPENDENT: true, + SHAPE: "M -0 -0.5 L 6 -0.5 L 6 0.5 L 0 0.5 L -0 -0.5", + TURRETS: [{ + POSITION: [40, 0, 40, 0, 360, 0], + TYPE: ["pickaxe"], + VULNERABLE: true + }] +} +Class.gettingoverit = { + PARENT: "genericTank", + LABEL: "getting over it", + TURRETS: [{ + POSITION: [13, 0, 0, 0, 360, 0], + TYPE: ["pickaxehandle"], + VULNERABLE: true + }] +} +Class.hyperlaser = { + PARENT: "laser", + //SHAPE: "M -1 8 L -1 -8 L 1 -8 L 1 8 L -1 8", + SHAPE: "M -1 -1 L 8 -1 L 8 1 L -1 1 L -1 -1", + IMMUNE_TO_TILES: true, + BORDERLESS: true, +} +Class.rayofdeath = { + PARENT: "genericTank", + LABEL: "rayofcertaindeath", + DANGER: 6, + BODY: { + FOV: 1.2, + }, + GUNS: [ + { + /*** LENGTH WIDTH ASPECT X Y ANGLE DELAY */ + POSITION: [21, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.doublereload, g.op, { speed: 7, maxSpeed: 7, damage: 9999, pen: 99999, health: 9999, size: 8, reload: 0.4, spray: 0.1}]), + TYPE: ["laser", { COLOR: 'rainbow'}], + }, + }, + { + POSITION: [19, 8, 1, 0, 0, 0, 1 / 3], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.doublereload, g.op, { speed: 7, maxSpeed: 7, damage: 9999, pen: 99999, health: 9999, size: 8, reload: 0.4, spray: 0.1}]), + TYPE: ["laser", { COLOR: 'rainbow'}], + }, + }, + { + POSITION: [17, 8, 1, 0, 0, 0, 2 / 3], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.doublereload, g.op, { speed: 7, maxSpeed: 7, damage: 9999, pen: 99999, health: 9999, size: 8, reload: 0.4, spray: 0.1}]), + TYPE: ["laser", { COLOR: 'rainbow'}], + }, + }, + { + POSITION: [20, 1, 1, 10, 0, 0, 2 / 3], + PROPERTIES: { + COLOR: 'rainbow', + SHOOT_SETTINGS: combineStats([g.fake]), + TYPE: "laser", + }, + }, + { + POSITION: [24, 1, 1, 0, 0, 0, 2 / 3], + PROPERTIES: { + COLOR: 'rainbow', + SHOOT_SETTINGS: combineStats([g.fake]), + TYPE: "laser", + }, + }, + { + POSITION: [17, 1, 1, 0, 5, 0, 2 / 3], + PROPERTIES: { + COLOR: 'rainbow', + SHOOT_SETTINGS: combineStats([g.fake]), + TYPE: "laser", + }, + }, + { + POSITION: [17, 1, 1, 0, -5, 0, 2 / 3], + PROPERTIES: { + COLOR: 'rainbow', + SHOOT_SETTINGS: combineStats([g.fake]), + TYPE: "laser", + }, + } + ], +} +Class.bigrayofdeath = { + PARENT: "genericTank", + LABEL: "biggerextremehypergonerlikehyperrayofcertaindeathholyshitwereallgonnadie.exe", + DANGER: 6, + IMMUNE_TO_TILES: true, + BODY: { + FOV: 1.5, + }, + ARENA_CLOSER: true, + GUNS: [ + { + /*** LENGTH WIDTH ASPECT X Y ANGLE DELAY */ + POSITION: [23, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.doublereload, g.op, { speed: 7, maxSpeed: 7, damage: 999999, pen: 999999, health: 999999, size: 4, reload: 0.4, spray: 0.05, recoil: 0.5}]), + TYPE: ["hyperlaser", { COLOR: 'rainbow'}], + }, + }, + { + POSITION: [21, 8, 1, 0, 0, 0, 1 / 6], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.doublereload, g.op, { speed: 7, maxSpeed: 7, damage: 999999, pen: 999999, health: 999999, size: 4, reload: 0.4, spray: 0.05, recoil: 0.5}]), + TYPE: ["hyperlaser", { COLOR: 'white'}], + COLOR: "flashBlueRed" + }, + }, + { + POSITION: [19, 8, 1, 0, 0, 0, 2 / 6], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.doublereload, g.op, { speed: 7, maxSpeed: 7, damage: 999999, pen: 999999, health: 999999, size: 4, reload: 0.4, spray: 0.05, recoil: 0.5}]), + TYPE: ["hyperlaser", { COLOR: 'rainbow'}], + }, + }, { + /*** LENGTH WIDTH ASPECT X Y ANGLE DELAY */ + POSITION: [17, 8, 1, 0, 0, 0, 3 / 6], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.doublereload, g.op, { speed: 7, maxSpeed: 7, damage: 999999, pen: 999999, health: 999999, size: 4, reload: 0.4, spray: 0.05, recoil: 0.5}]), + TYPE: ["hyperlaser", { COLOR: 'white'}], + COLOR: "epilepsy" + }, + }, + { + POSITION: [15, 8, 1, 0, 0, 0, 4 / 6], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.doublereload, g.op, { speed: 7, maxSpeed: 7, damage: 999999, pen: 999999, health: 999999, size: 4, reload: 0.4, spray: 0.05, recoil: 0.5}]), + TYPE: ["hyperlaser", { COLOR: 'rainbow'}], + }, + }, + { + POSITION: [13, 8, 1, 0, 0, 0, 5 / 6], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.doublereload, g.op, { speed: 7, maxSpeed: 7, damage: 999999, pen: 999999, health: 999999, size: 4, reload: 0.4, spray: 0.05, recoil: 0.5}]), + TYPE: ["hyperlaser", { COLOR: 'white'}], + COLOR: "nero" + }, + }, + { + POSITION: [20, 1, 1, 10, 0, 0, 1 / 3], + PROPERTIES: { + COLOR: 'rainbow', + SHOOT_SETTINGS: combineStats([g.fake]), + TYPE: "laser", + }, + }, + { + POSITION: [24, 1, 1, 0, 0, 0, 2 / 3], + PROPERTIES: { + COLOR: 'rainbow', + SHOOT_SETTINGS: combineStats([g.fake]), + TYPE: "laser", + }, + }, + { + POSITION: [17, 1, 1, 0, 5, 0, 2 / 3], + PROPERTIES: { + COLOR: 'rainbow', + SHOOT_SETTINGS: combineStats([g.fake]), + TYPE: "laser", + }, + }, + { + POSITION: [17, 1, 1, 0, -5, 0, 2 / 3], + PROPERTIES: { + COLOR: 'rainbow', + SHOOT_SETTINGS: combineStats([g.fake]), + TYPE: "laser", + }, + }, + { + POSITION: [11, 1, 1, 0, 6.5, 0, 2 / 3], + PROPERTIES: { + COLOR: 'flashRedGrey', + SHOOT_SETTINGS: combineStats([g.fake]), + TYPE: "laser", + }, + }, + { + POSITION: [11, 1, 1, 0, -6.5, 0, 2 / 3], + PROPERTIES: { + COLOR: 'flashRedGrey', + SHOOT_SETTINGS: combineStats([g.fake]), + TYPE: "laser", + }, + } + ], +} +Class.cheesedeco = { + SHAPE: "https://cdn.usdairy.com/optimize/getmedia/b5108b6f-59c3-4cc4-b1d5-4b9b0d1e0c54/swiss.jpg.jpg.aspx?format=webp" +} +Class.biggercheesedrone = { + PARENT: "drone", TURRETS: [{ - POSITION: [18, 36, 0, 0, 360, 1], - TYPE: "flailBolt2" + POSITION: [15, 0, 0, 0, 360, 2], + TYPE: "cheesedeco", }], -}; -Class.genericFlail = { - PARENT: "genericTank", - STAT_NAMES: statnames.flail, - TOOLTIP: "[DEV NOTE] The Flail is not finished yet. This tank is currently just a mockup.", - SKILL_CAP: [dfltskl, dfltskl, dfltskl, dfltskl, 0, dfltskl, dfltskl, dfltskl, dfltskl, dfltskl], } -Class.flail = { - PARENT: "genericFlail", - LABEL: "Flail", +Class.biggerCheese = { + PARENT: "genericTank", + LABEL: "Bigger Cheese", + STAT_NAMES: statnames.drone, + SKILL_CAP: Array(10).fill(255), + SKILL: Array(10).fill(255), + DANGER: 43, + ARENA_CLOSER: true, + BODY: { + SIZE: 2, + FOV: base.FOV * 3, + }, + GUNS: [ + { + POSITION: [27, 27, 6, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, g.bigCheese, { size: 7 }]), + TYPE: "biggercheesedrone", + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "drone", + MAX_CHILDREN: 1, + }, + }, + ], TURRETS: [{ - POSITION: [6, 10, 0, 0, 190, 0], - TYPE: ["flailBolt3", { - INDEPENDENT: true - }] - }] + POSITION: [15, 0, 0, 0, 360, 2], + TYPE: "cheesedeco", + }], } -Class.doubleFlail = { - PARENT: "genericFlail", - LABEL: "Double Flail", - DANGER: 6, +Class.kivaship = { + PARENT: "genericTank", + LABEL: "Kivaship", + STAT_NAMES: statnames.drone, + SKILL_CAP: Array(10).fill(10), + SKILL: Array(10).fill(10), + DANGER: 8, + ARENA_CLOSER: true, + GUNS: [ + { + POSITION: [6, 11, 1.3, 7, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone]), + TYPE: "baseThrower", + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "drone", + MAX_CHILDREN: 4, + }, + }, + ], TURRETS: [{ - POSITION: [6, 10, 0, 0, 190, 0], - TYPE: ["flailBolt3", { - INDEPENDENT: true - }] - }, { - POSITION: [6, 10, 0, 180, 190, 0], - TYPE: ["flailBolt3", { - INDEPENDENT: true - }] - }] + POSITION: [34, 0, 0, 0, 360, 0], + TYPE: "turretBaseKiva", + }], } -Class.tripleFlail = { - PARENT: "genericFlail", - LABEL: "Triple Flail", +Class.blaster = { + PARENT: "genericTank", + LABEL: "Blaster", DANGER: 7, - TURRETS: [{ - POSITION: [6, 10, 0, 0, 190, 0], - TYPE: ["flailBolt3", { - INDEPENDENT: true - }] - }, { - POSITION: [6, 10, 0, 120, 190, 0], - TYPE: ["flailBolt3", { - INDEPENDENT: true - }] - }, { - POSITION: [6, 10, 0, 240, 190, 0], - TYPE: ["flailBolt3", { - INDEPENDENT: true - }] - }] + GUNS: [{ + POSITION: [17, 13, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { damage: 0.8, health: 0.1, speed: 1.5, range: 0.25 } ]), + TYPE: "blasterbullet" + } + } + ], + TURRETS: [{ + POSITION: [8.2, 8, 5, 0, 0, 0], + TYPE: ["grenadeDeco", { MIRROR_MASTER_ANGLE: true }], + },{ + POSITION: [8.2, 8, -5, 0, 0, 0], + TYPE: ["grenadeDeco", { MIRROR_MASTER_ANGLE: true }], + } + ] +} +Class.trapperdesmos = { + PARENT: "genericTank", + LABEL: "Repeater", + GUNS: [ + { + POSITION: [30, 20, 0.8, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, { reload: 0.5 }]), + TYPE: ["snakeOld", {MOTION_TYPE: "desmos"}] + } + }, + { + POSITION: [4.625, 9.5, 3, 0.375, -8, 91.5, 0] + }, + { + POSITION: [4.625, 9.5, 3, 0.375, 8, -91.5, 0] + }, + { + POSITION: [5.75, 10, 2.125, 0, -5.75, 30, 0] + }, + { + POSITION: [5.75, 10, 2.125, 0, 5.75, -30, 0] + } + ] +} +Class.brokenanni = { + PARENT: "genericTank", + LABEL: "PPilator", + DANGER: 19041942194198412, + GUNS: [ + { + POSITION: [20.5, 19.5, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.destroyer, g.annihilator, { reload: 0.05, recoil: 0.1, speed: 2 }]), + TYPE: "bullet", + }, + }, + { + POSITION: [17, 19.5, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.destroyer, g.annihilator, { reload: 0.05, recoil: 0.1, speed: 2 }]), + TYPE: "bullet", + }, + }, + ], +} +Class.utilities = { + PARENT: "genericTank", + LABEL: "Utilities", + SHAPE: 'https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/Gear-icon-transparent-background.png?v=1705579178381' +}; +Class.stupidpony = { + PARENT: "developer", + LABEL: "Big long pink thing", + SHAPE: "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/IMG_1942.png?v=1723341388613" +} +Class.billcipher = { + PARENT: "developer", + LABEL: "Bill", + SHAPE: "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/52459e59-5ff9-4646-9949-a2a1461c7202.image.png?v=1724373801016" } +Class.AIT = menu("AIT") -Class.developer.UPGRADES_TIER_0 = ["tanks", "bosses", "spectator", "levels", "teams", "eggGenerator", "testing", "addons"] - Class.tanks.UPGRADES_TIER_0 = ["basic", "unavailable", "arenaCloser", "dominators", "sanctuaries", "mothership", "baseProtector", "antiTankMachineGun"] - Class.unavailable.UPGRADES_TIER_0 = ["flail", "healer", "volute", "whirlwind"] - Class.flail.UPGRADES_TIER_2 = ["doubleFlail"] - Class.doubleFlail.UPGRADES_TIER_3 = ["tripleFlail"] +Class.developer.UPGRADES_TIER_0 = ["basic", "tanks", "AIT", "utilities", "addons", ["developer", "basic"]] + Class.tanks.UPGRADES_TIER_0 = ["developer", "overpowered", "testing", "unavailable", "features"] + Class.AIT.UPGRADES_TIER_0 = ["developer", "bosses", "dominators", "sanctuaries", "mothership", "baseProtector", "antiTankMachineGun", "arenaCloser"] + Class.utilities.UPGRADES_TIER_0 = ["developer", "levels", "teams", "eggGenerator", "spectator", "wallPlacer", "lavenderspawner", "solariospawner"] + Class.unavailable.UPGRADES_TIER_0 = ["developer", "healer", "doubleFlail", "mace", "flangle", "winsor0", "volute", "tetraGunner", "sidewinder", "marksman", "basicCeption", "mirrorBackShield", "auto2", "bascrid", "autoBasic", "auraBasic"] + Class.sidewinder.UPGRADES_TIER_3 = ["coil", "oroboros", "cocci", "ranch", "python"] + Class.marksman.UPGRADES_TIER_3 = ["deadeye", "nimrod", "revolver", "fork"] Class.volute.UPGRADES_TIER_3 = ["sidewinderOld"] - Class.dominators.UPGRADES_TIER_0 = ["destroyerDominator", "gunnerDominator", "trapperDominator"] - Class.sanctuaries.UPGRADES_TIER_0 = ["sanctuaryTier1", "sanctuaryTier2", "sanctuaryTier3", "sanctuaryTier4", "sanctuaryTier5", "sanctuaryTier6"] - - Class.bosses.UPGRADES_TIER_0 = ["sentries", "elites", "mysticals", "nesters", "rogues", "rammers", "terrestrials", "celestials", "eternals", "devBosses"] - Class.sentries.UPGRADES_TIER_0 = ["sentrySwarm", "sentryGun", "sentryTrap", "shinySentrySwarm", "shinySentryGun", "shinySentryTrap", "sentinelMinigun", "sentinelLauncher", "sentinelCrossbow"] - Class.elites.UPGRADES_TIER_0 = ["eliteDestroyer", "eliteGunner", "eliteSprayer", "eliteBattleship", "eliteSpawner", "eliteTrapGuard", "eliteSpinner", "eliteSkimmer", "legionaryCrasher", "guardian", "defender", "sprayerLegion"] - Class.mysticals.UPGRADES_TIER_0 = ["sorcerer", "summoner", "enchantress", "exorcistor", "shaman"] - Class.nesters.UPGRADES_TIER_0 = ["nestKeeper", "nestWarden", "nestGuardian"] - Class.rogues.UPGRADES_TIER_0 = ["roguePalisade", "rogueArmada", "julius", "genghis", "napoleon"] - Class.rammers.UPGRADES_TIER_0 = ["bob", "nemesis"] - Class.terrestrials.UPGRADES_TIER_0 = ["ares", "gersemi", "ezekiel", "eris", "selene"] - Class.celestials.UPGRADES_TIER_0 = ["paladin", "freyja", "zaphkiel", "nyx", "theia", "atlas", "rhea", "julius", "genghis", "napoleon"] - Class.eternals.UPGRADES_TIER_0 = ["odin", "kronos"] - Class.devBosses.UPGRADES_TIER_0 = ["taureonBoss", "zephiBoss", "dogeiscutBoss", "trplnrBoss", "frostBoss", "toothlessBoss"] - - Class.testing.UPGRADES_TIER_0 = ["diamondShape", "miscTest", "mmaTest", "vulnturrettest", "onTest", "alphaGunTest", "strokeWidthTest", "testLayeredBoss", "tooltipTank", "turretLayerTesting", "bulletSpawnTest", "propTest", "weaponArrayTest", "radialAutoTest", "imageShapeTest", "auraBasic", "auraHealer", "weirdAutoBasic", "ghoster", "switcheroo", ["developer", "developer"], "armyOfOne", "vanquisher", "mummifier"] + //Class.flail.UPGRADES_TIER_2 = ["doubleFlail", "mace", "flangle"] + Class.doubleFlail.UPGRADES_TIER_3 = ["tripleFlail"] + Class.mace.UPGRADES_TIER_3 = ["bigMama", "itHurtsDontTouchIt", "flace"] + Class.flangle.UPGRADES_TIER_3 = ["flooster", "flace"] + Class.doubleFlail.UPGRADES_TIER_3 = ["tripleFlail"] + Class.whirlwind.UPGRADES_TIER_2 = ["tornado", "hurricane", "revolutionist"] + Class.whirlwind.UPGRADES_TIER_3 = ["hexaWhirl", "munition", "whirl3", "whirlGuard",/* "prophet",*/ "vortex"] + Class.tornado.UPGRADES_TIER_3 = ["megaTornado", "tempest", "thunderbolt"] + Class.hurricane.UPGRADES_TIER_3 = ["typhoon", "blizzard"] + Class.testing.UPGRADES_TIER_0 = ["tanks", "vanquisher", "mummifier", "tracker3", ["grappletest", "basic"], "grappletest2", "dasher", "ak47"] + Class.dominators.UPGRADES_TIER_0 = ["AIT", "destroyerDominator", "gunnerDominator", "trapperDominator"] + Class.sanctuaries.UPGRADES_TIER_0 = ["AIT", "sanctuaryTier1", "sanctuaryTier2", "sanctuaryTier3", "sanctuaryTier4", "sanctuaryTier5", "sanctuaryTier6"] + + Class.bosses.UPGRADES_TIER_0 = ["AIT", "sentries", "elites", "mysticals", "nesters", "rogues", "rammers", "terrestrials", "celestials", "eternals", "devBosses"] + Class.sentries.UPGRADES_TIER_0 = ["bosses", "sentrySwarm", "sentryGun", "sentryTrap", "shinySentrySwarm", "shinySentryGun", "shinySentryTrap", "sentinelMinigun", "sentinelLauncher", "sentinelCrossbow"] + Class.elites.UPGRADES_TIER_0 = ["bosses", "eliteDestroyer", "eliteGunner", "eliteSprayer", "eliteBattleship", "eliteSpawner", "eliteTrapGuard", "eliteSpinner", "eliteSkimmer", "legionaryCrasher", "guardian", "defender", "sprayerLegion"] + Class.mysticals.UPGRADES_TIER_0 = ["bosses", "sorcerer", "summoner", "enchantress", "exorcistor", "shaman"] + Class.nesters.UPGRADES_TIER_0 = ["bosses", "nestKeeper", "nestWarden", "nestGuardian"] + Class.rogues.UPGRADES_TIER_0 = ["bosses", "roguePalisade", "rogueArmada", "julius", "genghis", "napoleon"] + Class.rammers.UPGRADES_TIER_0 = ["bosses", "bob", "nemesis"] + Class.terrestrials.UPGRADES_TIER_0 = ["bosses", "ares", "gersemi", "ezekiel", "eris", "selene"] + Class.celestials.UPGRADES_TIER_0 = ["bosses", "paladin", "freyja", "zaphkiel", "nyx", "theia", "atlas", "rhea", "julius", "genghis", "napoleon"] + Class.eternals.UPGRADES_TIER_0 = ["bosses", "odin", "kronos"] + Class.devBosses.UPGRADES_TIER_0 = ["taureonBoss", "zephiBoss", "dogeiscutBoss", "trplnrBoss", "frostBoss", "toothlessBoss", "AEMKShipBoss", "helenaBoss"] + + Class.features.UPGRADES_TIER_0 = ["tanks", "diamondShape", "rotatedTrap", "colorMan", "miscTest", "mmaTest", "vulnturrettest", "onTest", "alphaGunTest", "strokeWidthTest", "testLayeredBoss", "tooltipTank", "turretLayerTesting", "bulletSpawnTest", "propTest", "weaponArrayTest", "radialAutoTest", "makeAutoTest", "imageShapeTest", "turretStatScaleTest", "auraBasic", "auraHealer", "weirdAutoBasic", "ghoster", "gunBenchmark", "switcheroo", ["developer", "developer"], "armyOfOne", "vanquisher", "mummifier"] + Class.overpowered.UPGRADES_TIER_0 = ["tanks", "goofytanks", "armyOfOne", "godbasic", "maximumOverdrive", "oppenheimer", "homingdev", ["maxStatTank", "basic"], "quiteliterallyAMachineGun", "speedoflight", "rayofdeath", "biggerCheese", "kivaship", "blaster", "trapperdesmos","brokenanni"] + Class.goofytanks.UPGRADES_TIER_0 = ["overpowered", "pisseroo", "papyrus", "Trapper_guy", "watertank", "piszerbeam", "baseThrowerDelta", "pouner", "adsfoipuasdfiopu", "goofywhirlwind", "gettingoverit", "alchem", "stupidpony", "billcipher"] + + //the "winsor" tank needs this to function, it worked before the "ON" thing was added + Class.winsor0.UPGRADES_TIER_0 = ["winsor1", "winsor2", "winsor3", "winsor4"] + Class.papyrus.UPGRADES_TIER_0 = ["imagetest"] + Class.adsfoipuasdfiopu.UPGRADES_TIER_0 = ["adsfoipuasdfiopu2", "adsfoipuasdfiopu3"] + Class.rayofdeath.UPGRADES_TIER_0 = ["bigrayofdeath"] \ No newline at end of file diff --git a/server/modules/definitions/groups/food.js b/server/modules/definitions/groups/food.js index 9e82ca96d..e86298d02 100644 --- a/server/modules/definitions/groups/food.js +++ b/server/modules/definitions/groups/food.js @@ -1,170 +1,5 @@ -const { basePolygonDamage, basePolygonHealth, base } = require('../constants.js'), - -// Code by Damocles (https://discord.com/channels/366661839620407297/508125275675164673/1090010998053818488) -// Albeit heavily modified because the math in the original didn't work LOL -makeRelic = (type, scale = 1, gem, SIZE) => { - type = ensureIsClass(type); - let relicCasing = { - PARENT: 'genericEntity', - LABEL: 'Relic Casing', - LEVEL_CAP: 45, - COLOR: type.COLOR, - MIRROR_MASTER_ANGLE: true, - SHAPE: [[-0.4,-1],[0.4,-0.25],[0.4,0.25],[-0.4,1]].map(r => r.map(s => s * scale)) - }, relicBody = { - PARENT: 'genericEntity', - LABEL: 'Relic Mantle', - LEVEL_CAP: 45, - COLOR: type.COLOR, - MIRROR_MASTER_ANGLE: true, - SHAPE: type.SHAPE - }; - Class[Math.random().toString(36)] = relicCasing; - Class[Math.random().toString(36)] = relicBody; - let width = 6 * scale, - y = 8.25 + ((scale % 1) * 5), - isEgg = type.SHAPE == 0, - casings = isEgg ? 8 : type.SHAPE, - fraction = 360 / casings, - GUNS = [], - TURRETS = [{ POSITION: [32.5, 0, 0, 0, 0, 0], TYPE: relicBody }], - PARENT = [type], - additionalAngle = type.SHAPE % 2 === 0 ? 0 : fraction / 2; - - if (SIZE) { - PARENT.push({ SIZE }); - } - - for (let i = 0; i < casings; i++) { - let angle = i * fraction, - gunAngle = angle + additionalAngle; - if (isEgg) { - GUNS.push({ - POSITION: [4, width, 2.5, 12, 0, gunAngle, 0] - }); - TURRETS.push({ - POSITION: [8, -15, 0, angle, 0, 1], - TYPE: relicCasing - }); - } else { - GUNS.push({ - POSITION: [4, width, 2.5, 12, y, gunAngle, 0] - }); - GUNS.push({ - POSITION: [4, width, 2.5, 12, -y, gunAngle, 0] - }); - TURRETS.push({ - POSITION: [8, -15, y, angle, 0, 1], - TYPE: relicCasing - }); - TURRETS.push({ - POSITION: [8, -15, -y, angle, 0, 1], - TYPE: relicCasing - }); - } - } - - if (gem) { - TURRETS.push({ - POSITION: [8, 0, 0, 0, 0, 1], - TYPE: [gem, { MIRROR_MASTER_ANGLE: true }] - }); - } - - return { - PARENT, - LABEL: type.LABEL + ' Relic', - COLOR: "white", // This is the color of the floor, this makes it look hollow. - BODY: { - ACCELERATION: 0.001 - }, - CONTROLLERS: [], - VALUE: type.VALUE * 100_000, - GUNS, - TURRETS - }; -}, - -makeCrasher = type => ({ - PARENT: type, - COLOR: 'pink', - TYPE: "crasher", - LABEL: 'Crasher ' + type.LABEL, - CONTROLLERS: ['nearestDifferentMaster', 'mapTargetToGoal'], - MOTION_TYPE: "motor", - FACING_TYPE: "smoothWithMotion", - HITS_OWN_TYPE: "hard", - HAS_NO_MASTER: true, - DRAW_HEALTH: true, - BODY: { - SPEED: 1 + 5 / Math.max(2, type.TURRETS.length + type.SHAPE), - ACCELERATION: 5, - DAMAGE: 5, - PUSHABILITY: 0.5, - DENSITY: 10, - RESIST: 2, - }, - AI: { - NO_LEAD: true, - } -}), - -makeRare = (type, level) => { - type = ensureIsClass(type); - return { - PARENT: "food", - LABEL: ["Shiny", "Legendary", "Shadow", "Rainbow", "Trans"][level] + " " + type.LABEL, - VALUE: [100, 500, 2000, 4000, 5000][level] * type.VALUE, - SHAPE: type.SHAPE, - SIZE: type.SIZE + level, - COLOR: ["lightGreen", "teal", "darkGrey", "rainbow", "trans"][level], - ALPHA: level == 2 ? 0.25 : 1, - BODY: { - DAMAGE: type.BODY.DAMAGE + level, - DENSITY: type.BODY.DENSITY + level, - HEALTH: [10, 20, 40, 80, 100][level] * type.BODY.HEALTH, - PENETRATION: type.BODY.PENETRATION + level, - ACCELERATION: type.BODY.ACCELERATION - }, - DRAW_HEALTH: true, - INTANGIBLE: false, - GIVE_KILL_MESSAGE: true, - } -}, - -lerp = (a, b, t) => a + (b - a) * t, - -makeLaby = (type, level) => { - type = ensureIsClass(type); - let usableSHAPE = Math.max(type.SHAPE, 3), - downscale = Math.cos(Math.PI / usableSHAPE), - strenghtMultiplier = 6 ** level; - return { - PARENT: "food", - LABEL: ["", "Beta ", "Alpha ", "Omega ", "Gamma ", "Delta "][level] + type.LABEL, - VALUE: type.VALUE * strenghtMultiplier, - SHAPE: type.SHAPE, - SIZE: level > 3 ? Math.max(40, type.SIZE * 2) * (1 + (level - 3) / 6) : type.SIZE * lerp(2 ** level, 1 + level / 3, Math.min(1, (type.SIZE - 5) / 17)), - COLOR: type.COLOR, - ALPHA: type.ALPHA, - BODY: { - DAMAGE: type.BODY.DAMAGE, - DENSITY: type.BODY.DENSITY, - HEALTH: type.BODY.HEALTH * strenghtMultiplier, - PENETRATION: type.BODY.PENETRATION, - PUSHABILITY: (type.BODY.PUSHABILITY / (level + 1)) || 0, - ACCELERATION: type.BODY.ACCELERATION - }, - VARIES_IN_SIZE: false, - DRAW_HEALTH: type.DRAW_HEALTH, - GIVE_KILL_MESSAGE: type.GIVE_KILL_MESSAGE || level > 2, - GUNS: type.GUNS, - TURRETS: [...(type.TURRETS ? type.TURRETS : []), ...Array(level).fill().map((_, i) => ({ - POSITION: [20 * downscale ** (i + 1), 0, 0, !(i & 1) ? 180 / usableSHAPE : 0, 0, 1], - TYPE: [type, { COLOR: -1, MIRROR_MASTER_ANGLE: true }] - }))] - }; -}; +const { basePolygonDamage, basePolygonHealth } = require('../constants.js'); +const { makeRelic, makeRare, makeCrasher, makeLaby } = require('../facilitators.js'); // EGGS Class.egg = { @@ -172,13 +7,14 @@ Class.egg = { LABEL: "Egg", VALUE: 10, SHAPE: 0, - SIZE: 5, + SIZE: 4.5, COLOR: "veryLightGrey", INTANGIBLE: true, BODY: { DAMAGE: 0, DENSITY: 2, HEALTH: 0.5 * basePolygonHealth, + PENETRATION: 1, PUSHABILITY: 0, ACCELERATION: 0.015 }, @@ -189,7 +25,7 @@ Class.gem = { LABEL: "Gem", VALUE: 2e3, SHAPE: 6, - SIZE: 5, + SIZE: 4.5, COLOR: "aqua", BODY: { DAMAGE: basePolygonDamage / 4, @@ -236,7 +72,7 @@ Class.square = { LABEL: "Square", VALUE: 30, SHAPE: 4, - SIZE: 10, + SIZE: 14, COLOR: "gold", BODY: { DAMAGE: basePolygonDamage, @@ -284,14 +120,14 @@ Class.pentagon = { LABEL: "Pentagon", VALUE: 400, SHAPE: 5, - SIZE: 20, + SIZE: 21, COLOR: "purple", BODY: { DAMAGE: 1.5 * basePolygonDamage, - DENSITY: 8, + DENSITY: 80, HEALTH: 10 * basePolygonHealth, - RESIST: 1.25, - PENETRATION: 1.1, + RESIST: 1, + PENETRATION: 0.7, ACCELERATION: 0.0035 }, DRAW_HEALTH: true, @@ -317,7 +153,6 @@ Class.betaPentagon = { RESIST: Math.pow(1.25, 2), PENETRATION: 1.1, SHIELD: 20 * basePolygonHealth, - REGEN: 0.2, ACCELERATION: 0.003 }, DRAW_HEALTH: true, @@ -344,7 +179,6 @@ Class.alphaPentagon = { RESIST: Math.pow(1.25, 3), PENETRATION: 1.1, SHIELD: 40 * basePolygonHealth, - REGEN: 0.6, ACCELERATION: 0.0025 }, DRAW_HEALTH: true, @@ -362,7 +196,7 @@ Class.hexagon = { LABEL: "Hexagon", VALUE: 500, SHAPE: 6, - SIZE: 22, + SIZE: 25, COLOR: "hexagon", BODY: { DAMAGE: 3 * basePolygonDamage, @@ -370,7 +204,8 @@ Class.hexagon = { HEALTH: 20 * basePolygonHealth, RESIST: 1.3, SHIELD: 50 * basePolygonHealth, - PENETRATION: 1.1, + //PENETRATION: 1.1, + PENETRATION: 0.5, ACCELERATION: 0.003 }, DRAW_HEALTH: true, @@ -390,7 +225,7 @@ Class.sphere = { SHAPE: 0, SIZE: 9, COLOR: { - BASE: "white", + BASE: "veryLightGrey", BRIGHTNESS_SHIFT: -15, }, BODY: { @@ -403,24 +238,24 @@ Class.sphere = { }, DRAW_HEALTH: true, GIVE_KILL_MESSAGE: true, - TURRETS: [{ - POSITION: [17, 0, 0, 0, 0, 1], - TYPE: ["egg", { COLOR: { BASE: "white", BRIGHTNESS_SHIFT: -14 }, BORDERLESS: true }] + PROPS: [{ + POSITION: [17, 0, 0, 0, 1], + TYPE: ["egg", { COLOR: { BRIGHTNESS_SHIFT: -14 }, BORDERLESS: true }] }, { - POSITION: [15, 1, -1, 0, 0, 1], - TYPE: ["egg", { COLOR: { BASE: "white", BRIGHTNESS_SHIFT: -9 }, BORDERLESS: true }] + POSITION: [15, 1, -1, 0, 1], + TYPE: ["egg", { COLOR: { BRIGHTNESS_SHIFT: -9 }, BORDERLESS: true }] }, { - POSITION: [13, 2, -2, 0, 0, 1], - TYPE: ["egg", { COLOR: { BASE: "white", BRIGHTNESS_SHIFT: -8 }, BORDERLESS: true }] + POSITION: [13, 2, -2, 0, 1], + TYPE: ["egg", { COLOR: { BRIGHTNESS_SHIFT: -8 }, BORDERLESS: true }] }, { - POSITION: [11, 3, -3, 0, 0, 1], - TYPE: ["egg", { COLOR: { BASE: "white", BRIGHTNESS_SHIFT: -3 }, BORDERLESS: true }] + POSITION: [11, 3, -3, 0, 1], + TYPE: ["egg", { COLOR: { BRIGHTNESS_SHIFT: -3 }, BORDERLESS: true }] }, { - POSITION: [8, 3.25, -3.25, 0, 0, 1], - TYPE: ["egg", { COLOR: { BASE: "white", BRIGHTNESS_SHIFT: 3 }, BORDERLESS: true }] + POSITION: [8, 3.25, -3.25, 0, 1], + TYPE: ["egg", { COLOR: { BRIGHTNESS_SHIFT: 3 }, BORDERLESS: true }] }, { - POSITION: [6, 3, -3, 0, 0, 1], - TYPE: ["egg", { COLOR: { BASE: "white", BRIGHTNESS_SHIFT: 9 }, BORDERLESS: true }] + POSITION: [6, 3, -3, 0, 1], + TYPE: ["egg", { COLOR: { BRIGHTNESS_SHIFT: 9 }, BORDERLESS: true }] }] }; Class.cube = { @@ -428,8 +263,8 @@ Class.cube = { LABEL: "The Cube", VALUE: 2e7, SIZE: 10, - COLOR: "white", - SHAPE: "M 0.0575 0.0437 V 0.9921 L 0.8869 0.5167 V -0.4306 L 0.0575 0.0437 Z M -0.0583 0.0437 V 0.9921 L -0.8869 0.5159 V -0.4306 L -0.0583 0.0437 Z M 0 -0.0556 L 0.829 -0.5266 L 0 -1 L -0.8254 -0.527 L 0 -0.0556", + COLOR: "egg", + SHAPE: "M -0.065 0.037 L -0.866 -0.425 L -0.866 0.5 L -0.065 0.962 Z M 0.065 0.037 L 0.065 0.962 L 0.866 0.5 L 0.866 -0.425 Z M 0 -0.075 L 0.801 -0.537 L 0 -1 L -0.801 -0.537 Z", BODY: { DAMAGE: 4.8, DENSITY: 20, @@ -447,8 +282,8 @@ Class.tetrahedron = { LABEL: "The Tetrahedron", VALUE: 3e7, SIZE: 12, - COLOR: "white", - SHAPE: "M 0.058 0.044 V 1 L 0.894 -0.434 L 0.058 0.044 Z M -0.0588 0.044 V 1 L -0.894 -0.434 L -0.0588 0.044 Z M 0 -0.056 L 0.8356 -0.5308 L -0.832 -0.5312 L 0 -0.056", + COLOR: "egg", + SHAPE: "M -0.065 0.037 L -0.934 -0.477 L -0.054 1.047 Z M 0.065 0.037 L 0.054 1.047 L 0.934 -0.477 Z M 0 -0.075 L 0.88 -0.57 L -0.88 -0.57 Z", BODY: { DAMAGE: 6, DENSITY: 23, @@ -465,8 +300,8 @@ Class.octahedron = { LABEL: "The Octahedron", VALUE: 4e7, SIZE: 13, - COLOR: "white", - SHAPE: "M 0.06 -0.06 L 0.95 -0.06 L 0.06 -0.95 L 0.06 -0.06 M -0.06 0.06 L -0.06 0.95 L -0.95 0.06 L -0.06 0.06 M -0.06 -0.06 L -0.95 -0.06 L -0.06 -0.95 L -0.06 -0.06 M 0.06 0.06 L 0.06 0.95 L 0.95 0.06 L 0.06 0.06", + COLOR: "egg", + SHAPE: "M -0.053 0.053 L -0.947 0.053 L -0.053 0.947 Z M 0.053 0.053 L 0.053 0.947 L 0.947 0.053 Z M 0.053 -0.053 L 0.947 -0.053 L 0.053 -0.947 Z M -0.053 -0.053 L -0.053 -0.947 L -0.947 -0.053 Z", BODY: { DAMAGE: 6.5, DENSITY: 26, @@ -483,8 +318,8 @@ Class.dodecahedron = { LABEL: "The Dodecahedron", VALUE: 5e7, SIZE: 18, - COLOR: "white", - SHAPE: "M -0.3273 -0.4318 H 0.3045 L 0.5068 0.1727 L -0.0091 0.5455 L -0.5227 0.1727 L -0.3273 -0.4318 Z M -0.6068 0.2682 L -0.0773 0.6545 V 0.9591 L -0.5955 0.7977 L -0.9136 0.3545 L -0.6068 0.2682 Z M 0.5909 0.2682 L 0.0523 0.6591 V 0.9636 L 0.5773 0.7955 L 0.8955 0.3545 L 0.5909 0.2682 Z M -0.65 0.1455 L -0.4477 -0.4818 L -0.6318 -0.7505 L -0.9545 -0.3182 V 0.2318 L -0.65 0.1455 Z M 0.4273 -0.4841 L 0.6318 0.1455 L 0.9341 0.2341 V -0.3136 L 0.6145 -0.7591 L 0.4273 -0.4841 Z M -0.0091 -1 L -0.5318 -0.8341 L -0.3455 -0.5609 H 0.3227 L 0.5159 -0.8314 L -0.0091 -1", + COLOR: "egg", + SHAPE: "M -0.341 -0.469 H 0.341 L 0.552 0.179 L 0 0.58 L -0.552 0.179 Z M -0.951 -0.309 L -0.95 0.238 L -0.674 0.149 L -0.458 -0.517 L -0.629 -0.751 Z M -0.588 0.809 L -0.067 0.977 L -0.067 0.687 L -0.633 0.276 L -0.909 0.366 Z M 0.588 0.809 L 0.908 0.366 L 0.633 0.276 L 0.067 0.687 L 0.067 0.977 Z M 0.951 -0.309 L 0.629 -0.751 L 0.458 -0.517 L 0.674 0.149 L 0.95 0.238 Z M 0 -1 L -0.52 -0.83 L -0.35 -0.595 H 0.35 L 0.52 -0.83 Z", BODY: { DAMAGE: 7, DENSITY: 28, @@ -501,8 +336,8 @@ Class.icosahedron = { LABEL: "The Icosahedron", VALUE: 1e8, SIZE: 20, - COLOR: "white", - SHAPE: "M 0 0.65 L -0.563 -0.325 L 0.563 -0.325 Z M -0.866 0.5 L -0.108 0.653 L -0.619 -0.233 Z M 0.679 -0.332 L 0.906 0.331 L 0.892 -0.455 Z M 0.627 -0.422 L 0.166 -0.95 L 0.84 -0.545 Z M 0.866 0.5 L 0.619 -0.233 L 0.108 0.653 Z M -0.627 -0.422 L -0.166 -0.95 L -0.84 -0.545 Z M -0.679 -0.332 L -0.906 0.331 L -0.892 -0.455 Z M 0 -1 L -0.511 -0.42 L 0.511 -0.42 Z M -0.052 0.754 L -0.74 0.619 L -0.052 1 Z M 0.052 0.754 L 0.74 0.619 L 0.052 1 Z", + COLOR: "egg", + SHAPE: "M -0.836 0.482 L -0.127 0.639 L -0.617 -0.209 Z M 0.699 -0.333 L 0.913 0.362 L 0.896 -0.447 Z M 0.638 -0.439 L 0.143 -0.972 L 0.836 -0.553 Z M 0.836 0.482 L 0.617 -0.209 L 0.127 0.639 Z M -0.638 -0.439 L -0.143 -0.972 L -0.836 -0.553 Z M -0.699 -0.333 L -0.913 0.362 L -0.896 -0.447 Z M 0 -0.965 L -0.49 -0.43 H 0.49 Z M -0.061 0.772 L -0.77 0.61 L -0.061 1 Z M 0.061 0.772 L 0.77 0.61 L 0.061 1 Z M 0 0.62 L -0.537 -0.31 L 0.537 -0.31 Z", BODY: { DAMAGE: 9, DENSITY: 30, @@ -528,7 +363,7 @@ for (let [gemColor, name] of [ let gem; if (gemColor) { gem = Class[name + "Gem"] = { - PARENT: ['gem'], + PARENT: 'gem', LABEL: name + ' Gem', SHAPE: 6, COLOR: gemColor @@ -541,6 +376,7 @@ for (let [gemColor, name] of [ Class[name + "PentagonRelic"] = makeRelic("pentagon", -0.6, gem); Class[name + "BetaPentagonRelic"] = makeRelic("betaPentagon", -0.6, gem); Class[name + "AlphaPentagonRelic"] = makeRelic("alphaPentagon", -0.6, gem); + Class[name + "HexagonRelic"] = makeRelic("hexagon", -0.4, gem, undefined, 6.25); } // 4D @@ -549,8 +385,8 @@ Class.tesseract = { LABEL: "The Tesseract", VALUE: 42e7, SIZE: 25, - COLOR: "white", - SHAPE: "M -0.43 0.35 L -0.71 0.63 L -0.71 -0.63 L -0.43 -0.35 L -0.43 0.35 M -0.35 0.43 L -0.63 0.71 L 0.63 0.71 L 0.35 0.43 L -0.35 0.43 M 0.35 -0.43 L 0.63 -0.71 L -0.63 -0.71 L -0.35 -0.43 L 0.35 -0.43 M 0.43 -0.35 L 0.71 -0.63 L 0.71 0.63 L 0.43 0.35 L 0.43 -0.35 M 0.32 0.32 L 0.32 -0.32 L -0.32 -0.32 L -0.32 0.32 L 0.32 0.32", + COLOR: "egg", + SHAPE: "M 0.47 -0.375 L 0.71 -0.615 L 0.71 0.615 L 0.47 0.375 Z M -0.375 -0.47 L -0.615 -0.71 L 0.615 -0.71 L 0.375 -0.47 Z M -0.47 0.375 L -0.71 0.615 L -0.71 -0.615 L -0.47 -0.375 Z M 0.375 0.47 L 0.615 0.71 L -0.615 0.71 L -0.375 0.47 Z M 0.35 0.35 L 0.35 -0.35 L -0.35 -0.35 L -0.35 0.35 Z", BODY: { DAMAGE: 10, DENSITY: 40, @@ -579,7 +415,7 @@ for (let tier = 0; tier < 6; tier++) { food = food[0].toLowerCase() + food.slice(1); Class[`laby${tier}${food}`] = // backwards compatability, DO NOT ADD A SEMICOLON HERE. javascript is funny about whitespace characters :)))))) - Class[`laby_${poly}_${tier}_${shiny}_0`] = makeLaby(Class[food], tier); + Class[`laby_${poly}_${tier}_${shiny}_0`] = makeLaby(Class[food], tier, (polyName == "Triangle" && tier > 0) ? 2/3 : 1); Class[`laby_${poly}_${tier}_${shiny}_1`] = makeCrasher(Class[`laby_${poly}_${tier}_${shiny}_0`]); } diff --git a/server/modules/definitions/groups/generics.js b/server/modules/definitions/groups/generics.js index a4f57a39f..6385fb609 100644 --- a/server/modules/definitions/groups/generics.js +++ b/server/modules/definitions/groups/generics.js @@ -1,4 +1,4 @@ -const { skillSet } = require('../facilitators.js'); +const { skillSet, addAura } = require('../facilitators.js'); const { base, statnames, dfltskl, smshskl } = require('../constants.js'); Class.genericEntity = { @@ -23,6 +23,7 @@ Class.genericEntity = { FACING_TYPE: "toTarget", DRAW_HEALTH: false, DRAW_SELF: true, + IS_IMMUNE_TO_TILES: false, DAMAGE_EFFECTS: true, RATEFFECTS: true, MOTION_EFFECTS: true, @@ -39,6 +40,7 @@ Class.genericEntity = { HEALTH_WITH_LEVEL: true, CAN_BE_ON_LEADERBOARD: true, HAS_NO_RECOIL: false, + SYNC_WITH_TANK: false, BUFF_VS_FOOD: false, OBSTACLE: false, CRAVES_ATTENTION: false, @@ -97,12 +99,15 @@ Class.genericTank = { BRIGHTNESS_SHIFT: 0, ALLOW_BRIGHTNESS_INVERT: true, }, + SHAPE: 0, MOTION_TYPE: "motor", FACING_TYPE: "toTarget", SIZE: 12, MAX_CHILDREN: 0, DAMAGE_EFFECTS: false, IGNORED_BY_AI: false, + SYNC_WITH_TANK: false, + IS_IMMUNE_TO_TILES: false, REROOT_UPGRADE_TREE: "basic", BODY: { ACCELERATION: base.ACCEL, @@ -127,6 +132,12 @@ Class.genericTank = { RESET_EVENTS: true, HITS_OWN_TYPE: "hardOnlyTanks" } +Class.genericLancer = { + PARENT: "genericTank", + DANGER: 5, + SKILL_CAP: [dfltskl, dfltskl, dfltskl, dfltskl, dfltskl, dfltskl, dfltskl, dfltskl, dfltskl, dfltskl], + STAT_NAMES: statnames.lancer, +} Class.genericSmasher = { PARENT: "genericTank", DANGER: 7, @@ -135,7 +146,12 @@ Class.genericSmasher = { STAT_NAMES: statnames.smasher, BODY: { FOV: 1.05 * base.FOV, - DENSITY: 2 * base.DENSITY + SPEED: 1.3 * base.SPEED, + DENSITY: 2 * base.DENSITY, + HEALTH: 2 * base.HEALTH, + PUSHABILITY: 0, + ACCELERATION: 1.3 * base.ACCEL, + DAMAGE: 1.5 * base.DAMAGE } } Class.genericBoss = { @@ -170,10 +186,12 @@ Class.food = { MOTION_TYPE: "drift", FACING_TYPE: "turnWithSpeed", VARIES_IN_SIZE: true, - LEVEL_CAP: 45, + IS_IMMUNE_TO_TILES: false, + LEVEL_CAP: 1, BODY: { STEALTH: 30, PUSHABILITY: 1, + REGEN: 0 }, DAMAGE_EFFECTS: false, RATEFFECTS: false, @@ -310,6 +328,10 @@ Class.satellite = { BUFF_VS_FOOD: true, MOTION_TYPE: 'motor' } +Class.squareSatellite = { + PARENT: "satellite", + SHAPE: 4 +} Class.auraBase = { TYPE: "aura", @@ -338,7 +360,7 @@ Class.aura = { LABEL: "Aura", COLOR: "teal", BODY: { - DAMAGE: 0.15, + DAMAGE: 0.4, }, }; Class.healAura = { @@ -347,9 +369,17 @@ Class.healAura = { HEALER: true, COLOR: "red", BODY: { - DAMAGE: 0.05, + DAMAGE: 0.4 / 3, }, }; +Class.auraBasicGen = addAura(1, 1.3); +Class.auraHealerGen = addAura(-1); +Class.auraDamageGen = addAura(2, 1.3, 0.3, "red"); +Class.auraRangeGen = addAura(2, 1.8, 0.3, "teal", "rangeAuraSymbol"); +Class.auraDamageRangeGen = addAura(2, 1.8, 0.3, "red", "rangeAuraSymbol"); +Class.auraMoreDamageGen = addAura(3, 1.3, 0.3, "orange"); +Class.auraMoreRangeGen = addAura(1, 2.3, 0.3, "aqua", "rangeAuraSymbol"); +Class.auraSmasherGen = addAura(11, 1.3); Class.auraSymbol = { PARENT: "genericTank", CONTROLLERS: [["spin", {speed: -0.04}]], @@ -357,3 +387,10 @@ Class.auraSymbol = { COLOR: "teal", SHAPE: [[-0.598,-0.7796],[-0.3817,-0.9053],[0.9688,-0.1275],[0.97,0.125],[-0.3732,0.9116],[-0.593,0.785]] }; +Class.rangeAuraSymbol = { + PARENT: "genericTank", + CONTROLLERS: [["spin", {speed: -0.04}]], + INDEPENDENT: true, + COLOR: "teal", + SHAPE: "M -0.7671 0.6521 L -0.7671 -0.6521 L -0.6521 -0.7671 L -0.6521 -0.7671 L 0.6521 -0.7671 L 0.7671 -0.6521 L 0.7671 0.6521 L 0.6521 0.7671 L -0.6521 0.7671 L -0.7671 0.6521" +}; \ No newline at end of file diff --git a/server/modules/definitions/groups/misc.js b/server/modules/definitions/groups/misc.js index d868c7879..b43a59aed 100644 --- a/server/modules/definitions/groups/misc.js +++ b/server/modules/definitions/groups/misc.js @@ -1,8 +1,8 @@ -const { combineStats, skillSet, makeAuto, makeDeco, makeMulti } = require('../facilitators.js'); -const { base, statnames, gunCalcNames, dfltskl, smshskl } = require('../constants.js'); +const { combineStats, skillSet, makeAuto, weaponArray } = require('../facilitators.js') +const { base, statnames, dfltskl, smshskl } = require('../constants.js') require('./generics.js') -require('./tanks.js'); -const g = require('../gunvals.js'); +require('./tanks.js') +const g = require('../gunvals.js') // OBSTACLES Class.rock = { @@ -43,14 +43,58 @@ Class.wall = { PARENT: "rock", LABEL: "Wall", SIZE: 25, - SHAPE: "M 1 1 L -1 1 L -1 -1 L 1 -1 Z", + SHAPE: 4, VARIES_IN_SIZE: false } +let biggerfov = new StatusEffect(1, {fov: 2}); +Class.fovwall = { + PARENT: "wall", + GLOW: { + RADIUS: 30, + COLOR: "yellow", + ALPHA: 1, + RECURSION: 5 + }, + COLOR: "yellow", + ON: [{ + event: "collide", + handler: ({ body, other }) => { + other.addStatusEffect(biggerfov) + }}] +} +Class.dfxwall = { + PARENT: "wall", + TURRETS: [{ + POSITION: [7, -5, -5, 0, 0, 3], + TYPE: "dfxskin" + },] +} +Class.hookpoint = { + TYPE: "hookpoint", + DAMAGE_CLASS: 1, + SIZE: 20, + ALPHA: 0.5, + SHAPE: "M 1 1 L -1 1 L -1 -1 L 1 -1 Z", + COLOR: "cyan", + VARIES_IN_SIZE: false, + BODY: { + PUSHABILITY: 0, + HEALTH: 10000, + SHIELD: 10000, + REGEN: 1000, + DAMAGE: 1, + RESIST: 0, + STEALTH: 1, + DENSITY: 100000, + }, + VALUE: 0, +} Class.moon = { PARENT: "rock", LABEL: "Moon", SIZE: 60, - SHAPE: 0 + SHAPE: 0, + VARIES_IN_SIZE: false } // DOMINATORS @@ -67,7 +111,10 @@ Class.dominator = { str: 1, spd: 1, }), - LEVEL: -1, + LEVEL: 45, + LEVEL_CAP: 45, + SIZE: 50, + SYNC_WITH_TANK: true, BODY: { RESIST: 100, SPEED: 1.32, @@ -93,6 +140,24 @@ Class.dominator = { ACCEPTS_SCORE: false, HITS_OWN_TYPE: "pushOnlyTeam" } +Class.territoryCapturePoint = { + PARENT: "dominator", + LABEL: "Capture Point", + BODY: { + HEALTH: 200, + DAMAGE: 5, + PENETRATION: 0.2, + }, +} +Class.trapTerritoryCapturePoint = { + PARENT: "trapperDominator", + LABEL: "Capture Point", + BODY: { + HEALTH: 350, + DAMAGE: 5, + PENETRATION: 0.2, + }, +} Class.destroyerDominator = { PARENT: "dominator", UPGRADE_LABEL: 'Destroyer', @@ -139,12 +204,11 @@ Class.gunnerDominator = { } ] } -Class.trapperDominator = makeMulti({ +Class.trapperDominator = { PARENT: "dominator", UPGRADE_LABEL: 'Trapper', FACING_TYPE: ["spin", {speed: 0.02}], - CONTROLLERS: ["alwaysFire"], - GUNS: [ + GUNS: weaponArray([ { POSITION: [4, 3.75, 1, 8, 0, 0, 0] }, @@ -153,11 +217,12 @@ Class.trapperDominator = makeMulti({ PROPERTIES: { SHOOT_SETTINGS: combineStats([g.trap, g.trapperDominator]), TYPE: "trap", - STAT_CALCULATOR: gunCalcNames.trap + STAT_CALCULATOR: "trap", + AUTOFIRE: true } } - ] -}, 8, "Dominator") + ], 8) +} // SANCTUARIES let sancTiers = [3, 6, 8, 9, 10, 12] @@ -165,22 +230,18 @@ let sancHealerTiers = [2, 3, 4] for (let tier of sancHealerTiers) { Class['sanctuaryHealerTier' + (sancHealerTiers.indexOf(tier) + 1)] = { PARENT: "sanctuaryHealer", - GUNS: (() => { - let output = [] - for (let i = 0; i < tier; i++) { - output.push({ - POSITION: { LENGTH: 8, WIDTH: 9, ASPECT: -0.5, X: 12.5, ANGLE: (360 / tier) * i }, - }, { - POSITION: { LENGTH: 8, WIDTH: 10, X: 10, ANGLE: (360 / tier) * i }, - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.healer]), - TYPE: "healerBullet", - AUTOFIRE: true, - } - }) + GUNS: weaponArray([ + { + POSITION: { LENGTH: 8, WIDTH: 9, ASPECT: -0.5, X: 12.5 }, + }, { + POSITION: { LENGTH: 8, WIDTH: 10, X: 10 }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { range: 0.5 }, g.healer]), + TYPE: "healerBullet", + AUTOFIRE: true, + } } - return output - })() + ], tier) } } @@ -190,7 +251,6 @@ Class.sanctuary = { LEVEL: 45, SIZE: 20, FACING_TYPE: ["spin", {speed: 0.02}], - CONTROLLERS: ["alwaysFire"], SKILL: skillSet({ rld: 1.25, dam: 1.25, @@ -213,23 +273,19 @@ for (let tier of sancTiers) { PARENT: "sanctuary", TURRETS: [], UPGRADE_LABEL: 'Tier ' + (sancIndex + 1), - GUNS: (() => { - let output = [] - for (let i = 0; i < tier; i++) { - output.push({ - POSITION: {LENGTH: 12, WIDTH: 4, ANGLE: (360/tier)*i} - }, { - POSITION: {LENGTH: 1.5, WIDTH: 4, ASPECT: 1.7, X: 12, ANGLE: (360/tier)*i}, - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, {shudder: 0.15, speed: 0.8, health: 3, reload: 1.5}]), - TYPE: "trap", - STAT_CALCULATOR: gunCalcNames.trap, - AUTOFIRE: true, - }, - }) + GUNS: weaponArray([ + { + POSITION: {LENGTH: 12, WIDTH: 4} + }, { + POSITION: {LENGTH: 1.5, WIDTH: 4, ASPECT: 1.7, X: 12}, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, {shudder: 0.15, speed: 0.8, health: 3, reload: 1.5}]), + TYPE: "trap", + STAT_CALCULATOR: "trap", + AUTOFIRE: true, + }, } - return output - })() + ], tier) } Class['sanctuaryTier' + (sancIndex + 1)].TURRETS.push({ POSITION: { SIZE: 22 }, @@ -268,37 +324,6 @@ Class.crasher = { HAS_NO_MASTER: true, DRAW_HEALTH: true, }; -Class.crasherSpawner = { - PARENT: "genericTank", - LABEL: "Spawned", - STAT_NAMES: statnames.drone, - CONTROLLERS: ["nearestDifferentMaster"], - COLOR: "pink", - INDEPENDENT: true, - AI: { - chase: true, - }, - MAX_CHILDREN: 4, - GUNS: [ - { - POSITION: [6, 12, 1.2, 8, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.weak, g.weak]), - TYPE: [ - "drone", - { - LABEL: "Crasher", - VARIES_IN_SIZE: true, - DRAW_HEALTH: true, - }, - ], - SYNCS_SKILLS: true, - AUTOFIRE: true, - STAT_CALCULATOR: gunCalcNames.drone, - }, - }, - ], -}; // SENTRIES Class.sentry = { @@ -350,9 +375,9 @@ Class.sentrySwarm = { { POSITION: [7, 14, 0.6, 7, 0, 180, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm, { recoil: 1.15 }]), + SHOOT_SETTINGS: combineStats([g.swarm, { recoil: 1.15, range: 0.9 }]), TYPE: "swarm", - STAT_CALCULATOR: gunCalcNames.swarm, + STAT_CALCULATOR: "swarm", }, }, ], @@ -389,13 +414,13 @@ Class.shinySentrySwarm = { PROPERTIES: { SHOOT_SETTINGS: combineStats([g.swarm, { recoil: 1.15 }, g.machineGun, { reload: 0.25 }]), TYPE: "swarm", - STAT_CALCULATOR: gunCalcNames.swarm, + STAT_CALCULATOR: "swarm", }, }, ], }; Class.shinySentryGun = makeAuto("shinySentry", "Sentry", { - type: Class.artilleryAutoTankgun, + type: "artilleryTurret", size: 12, }); Class.shinySentryGun.UPGRADE_LABEL = "Shiny Gun Sentry"; @@ -510,43 +535,43 @@ Class.sentinelMinigun = { { POSITION: [16, 7.5, 1, 0, 4.5, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.twin]), + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.twin, g.spam, g.spam]), TYPE: "bullet", }, }, { POSITION: [11.5, 7.5, -1.33, 1, 4.5, 0, 0.5], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.twin]), + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.twin, g.spam, g.spam]), TYPE: "bullet", }, }, { POSITION: [16, 7.5, 1, 0, -4.5, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.twin]), + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.twin, g.spam, g.spam]), TYPE: "bullet", }, }, { POSITION: [11.5, 7.5, -1.33, 1, -4.5, 0, 0.5], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.twin]), + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.twin, g.spam, g.spam]), TYPE: "bullet", }, }, { POSITION: [22.5, 9, 1, 0, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.twin]), + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.twin, g.spam, g.spam]), TYPE: "bullet", }, }, { POSITION: [20.4, 9, 1, 0, 0, 0, 1/3], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.twin]), + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.twin, g.spam, g.spam]), TYPE: "bullet", }, }, { POSITION: [18.3, 9, 1, 0, 0, 0, 2/3], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.twin]), + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.twin, g.spam, g.spam]), TYPE: "bullet", }, }, @@ -590,49 +615,19 @@ Class.baseProtector = { POSITION: [25, 0, 0, 0, 360, 0], TYPE: "dominationBody", }, - { + ...weaponArray({ POSITION: [12, 7, 0, 45, 100, 0], TYPE: "baseSwarmTurret", - }, - { - POSITION: [12, 7, 0, 135, 100, 0], - TYPE: "baseSwarmTurret", - }, - { - POSITION: [12, 7, 0, 225, 100, 0], - TYPE: "baseSwarmTurret", - }, - { - POSITION: [12, 7, 0, 315, 100, 0], - TYPE: "baseSwarmTurret", - }, + }, 4) ], - GUNS: [ + GUNS: weaponArray([ { POSITION: [4.5, 11.5, -1.3, 6, 0, 45, 0], }, - { - POSITION: [4.5, 11.5, -1.3, 6, 0, 135, 0], - }, - { - POSITION: [4.5, 11.5, -1.3, 6, 0, 225, 0], - }, - { - POSITION: [4.5, 11.5, -1.3, 6, 0, 315, 0], - }, { POSITION: [4.5, 8.5, -1.5, 7, 0, 45, 0], }, - { - POSITION: [4.5, 8.5, -1.5, 7, 0, 135, 0], - }, - { - POSITION: [4.5, 8.5, -1.5, 7, 0, 225, 0], - }, - { - POSITION: [4.5, 8.5, -1.5, 7, 0, 315, 0], - }, - ], + ], 4) }; Class.mothership = { @@ -656,46 +651,36 @@ Class.mothership = { DAMAGE: 1.5, }, HITS_OWN_TYPE: "pushOnlyTeam", - GUNS: (() => { - let e = [], - T = [1]; - for (let e = 1; e < 8.5; e += 0.5) { - let t = e / 16; - T.push(t); - } - for (let t = 0; t < 16; t++) { - let S = 22.5 * (t + 1), - E = { - MAX_CHILDREN: 2, - SHOOT_SETTINGS: combineStats([g.drone, g.overseer, g.mothership]), - TYPE: "drone", - AUTOFIRE: true, - SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.drone, - WAIT_TO_CYCLE: true, - }; - t % 2 == 0 && - (E.TYPE = [ - "drone", - { - AI: { - skynet: true, - }, + GUNS: + weaponArray([ + { + POSITION: [4.3, 3.1, 1.2, 8, 0, 22.5, 0], + PROPERTIES: { + MAX_CHILDREN: 2, + SHOOT_SETTINGS: combineStats([g.drone, g.overseer, g.mothership]), + TYPE: "drone", + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "drone", + WAIT_TO_CYCLE: true, + } + }, { + POSITION: [4.3, 3.1, 1.2, 8, 0, 45, 1/32], + PROPERTIES: { + MAX_CHILDREN: 2, + SHOOT_SETTINGS: combineStats([g.drone, g.overseer, g.mothership]), + TYPE: ["drone", { + AI: {skynet: true}, INDEPENDENT: true, - LAYER: 10, - BODY: { - FOV: 2, - }, - }, - ]); - let O = { - POSITION: [4.3, 3.1, 1.2, 8, 0, S, T[t]], - PROPERTIES: E, - }; - e.push(O); + BODY: {FOV: 2}, + }], + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "drone", + WAIT_TO_CYCLE: true, + } } - return e; - })(), + ], 8, 1/16) } Class.arenaCloser = { PARENT: "genericTank", @@ -718,6 +703,7 @@ Class.arenaCloser = { DRAW_HEALTH: false, HITS_OWN_TYPE: "never", ARENA_CLOSER: true, + IS_IMMUNE_TO_TILES: true, GUNS: [{ POSITION: [14, 10, 1, 0, 0, 0, 0], PROPERTIES: { @@ -733,6 +719,7 @@ Class.antiTankMachineGun = { UPGRADE_LABEL: "A.T.M.G.", CONTROLLERS: [['spin', {onlyWhenIdle: true}], 'nearestDifferentMaster'], LEVEL: 45, + SIZE: 12, BODY: { RESIST: 100, SPEED: 1.32, @@ -797,21 +784,10 @@ Class.tracker3 = { LABEL: "Tracker-3", FACING_TYPE: ["spin", {speed: 0.02}], SKILL_CAP: [0, 0, 0, 0, 0, smshskl, smshskl, smshskl, smshskl, smshskl], - TURRETS: [ - { - /* SIZE X Y ANGLE ARC */ - POSITION: [11, 8, 0, 0, 190, 0], - TYPE: ["tracker3gun", { INDEPENDENT: true }], - }, - { - POSITION: [11, 8, 0, 120, 190, 0], - TYPE: ["tracker3gun", { INDEPENDENT: true }], - }, - { - POSITION: [11, 8, 0, 240, 190, 0], - TYPE: ["tracker3gun", { INDEPENDENT: true }], - }, - ], + TURRETS: weaponArray({ + POSITION: [11, 8, 0, 0, 190, 0], + TYPE: ["tracker3gun", { INDEPENDENT: true }], + }, 3) }; // BOTS @@ -825,4 +801,4 @@ Class.tagMode = { PARENT: "bullet", LABEL: "Players", SHAPE: "" -}; +}; \ No newline at end of file diff --git a/server/modules/definitions/groups/projectiles.js b/server/modules/definitions/groups/projectiles.js index f4eddd911..45db2cade 100644 --- a/server/modules/definitions/groups/projectiles.js +++ b/server/modules/definitions/groups/projectiles.js @@ -1,5 +1,5 @@ -const { combineStats, makeAuto } = require('../facilitators.js'); -const { gunCalcNames, base } = require('../constants.js'); +const { combineStats, makeAuto, makeOver, weaponArray } = require('../facilitators.js'); +const { base } = require('../constants.js'); const g = require('../gunvals.js'); // Bullets @@ -10,7 +10,7 @@ Class.splitterBullet = { { POSITION: [8, 8, 1, 0, 0, 90, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic]), + SHOOT_SETTINGS: combineStats([g.basic, g.repeater]), TYPE: ["bullet", { PERSISTS_AFTER_DEATH: true }], SHOOT_ON_DEATH: true, } @@ -18,7 +18,7 @@ Class.splitterBullet = { { POSITION: [8, 8, 1, 0, 0, 270, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic]), + SHOOT_SETTINGS: combineStats([g.basic, g.repeater]), TYPE: ["bullet", { PERSISTS_AFTER_DEATH: true }], SHOOT_ON_DEATH: true, } @@ -32,7 +32,7 @@ Class.superSplitterBullet = { { POSITION: [8, 8, 1, 0, 0, 90, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic]), + SHOOT_SETTINGS: combineStats([g.basic, g.repeater]), TYPE: ["splitterBullet", { PERSISTS_AFTER_DEATH: true }], SHOOT_ON_DEATH: true, } @@ -40,14 +40,14 @@ Class.superSplitterBullet = { { POSITION: [8, 8, 1, 0, 0, 270, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic]), + SHOOT_SETTINGS: combineStats([g.basic, g.repeater]), TYPE: ["splitterBullet", { PERSISTS_AFTER_DEATH: true }], SHOOT_ON_DEATH: true, } }, ] } -Class.turretedBullet = makeAuto('bullet', "Auto-Bullet", {size: 14, color: "veryLightGrey", angle: 0}); +Class.turretedBullet = makeAuto('bullet', "Auto-Bullet", {type: "bulletAutoTurret", size: 14, color: "veryLightGrey", angle: 0}); Class.speedBullet = { PARENT: "bullet", MOTION_TYPE: "accel", @@ -70,6 +70,36 @@ Class.casing = { LABEL: "Shell", TYPE: "swarm", } +Class.forkSplitterBullet = { + PARENT: "bullet", + INDEPENDENT: true, + GUNS: [ + { + POSITION: [8, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, { damage: 0.65, size: 2.4 }]), + TYPE: ["bullet", { PERSISTS_AFTER_DEATH: true }], + SHOOT_ON_DEATH: true, + } + }, + { + POSITION: [8, 8, 1, 0, 0, 30, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, { damage: 0.65, size: 2.4 } ]), + TYPE: ["bullet", { PERSISTS_AFTER_DEATH: true }], + SHOOT_ON_DEATH: true, + } + }, + { + POSITION: [8, 8, 1, 0, 0, -30, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, { damage: 0.65, size: 2.4 }]), + TYPE: ["bullet", { PERSISTS_AFTER_DEATH: true }], + SHOOT_ON_DEATH: true, + } + }, + ] +} // Missiles Class.missile = { @@ -84,7 +114,7 @@ Class.missile = { AUTOFIRE: true, SHOOT_SETTINGS: combineStats([g.basic, g.lowPower, {speed: 1.3, maxSpeed: 1.3}]), TYPE: [ "bullet", { PERSISTS_AFTER_DEATH: true } ], - STAT_CALCULATOR: gunCalcNames.thruster, + STAT_CALCULATOR: "thruster", WAIT_TO_CYCLE: true, } }, @@ -94,7 +124,7 @@ Class.missile = { AUTOFIRE: true, SHOOT_SETTINGS: combineStats([g.basic, g.lowPower, {speed: 1.3, maxSpeed: 1.3}]), TYPE: [ "bullet", { PERSISTS_AFTER_DEATH: true } ], - STAT_CALCULATOR: gunCalcNames.thruster, + STAT_CALCULATOR: "thruster", WAIT_TO_CYCLE: true, } } @@ -109,7 +139,7 @@ Class.hypermissile = { AUTOFIRE: true, SHOOT_SETTINGS: combineStats([g.basic, {reload: 3}]), TYPE: [ "bullet", { PERSISTS_AFTER_DEATH: true } ], - STAT_CALCULATOR: gunCalcNames.thruster, + STAT_CALCULATOR: "thruster", }, }, { @@ -118,7 +148,7 @@ Class.hypermissile = { AUTOFIRE: true, SHOOT_SETTINGS: combineStats([g.basic, {reload: 3}]), TYPE: [ "bullet", { PERSISTS_AFTER_DEATH: true } ], - STAT_CALCULATOR: gunCalcNames.thruster, + STAT_CALCULATOR: "thruster", }, }, { @@ -149,7 +179,7 @@ Class.minimissile = { AUTOFIRE: true, SHOOT_SETTINGS: combineStats([g.basic, { recoil: 0.5 }, g.lowPower]), TYPE: ["bullet", { PERSISTS_AFTER_DEATH: true }], - STAT_CALCULATOR: gunCalcNames.thruster, + STAT_CALCULATOR: "thruster", }, }, ], @@ -157,69 +187,28 @@ Class.minimissile = { Class.spinmissile = { PARENT: "missile", CONTROLLERS: [["spin2", {speed: 0.1}]], - GUNS: [ - { - POSITION: [14, 8, 1, 0, 0, 0, 0], - PROPERTIES: { - AUTOFIRE: !0, - SHOOT_SETTINGS: combineStats([g.basic, g.lowPower, {size: 1.1}]), - TYPE: ["bullet", { PERSISTS_AFTER_DEATH: true }], - STAT_CALCULATOR: gunCalcNames.thruster, - WAIT_TO_CYCLE: true, - }, + GUNS: weaponArray({ + POSITION: [14, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + AUTOFIRE: !0, + SHOOT_SETTINGS: combineStats([g.basic, g.lowPower, {size: 1.1}]), + TYPE: ["bullet", { PERSISTS_AFTER_DEATH: true }], + STAT_CALCULATOR: "thruster", + WAIT_TO_CYCLE: true, }, - { - POSITION: [14, 8, 1, 0, 0, 180, 0], - PROPERTIES: { - AUTOFIRE: !0, - SHOOT_SETTINGS: combineStats([g.basic, g.lowPower, {size: 1.1}]), - TYPE: ["bullet", { PERSISTS_AFTER_DEATH: true }], - STAT_CALCULATOR: gunCalcNames.thruster, - WAIT_TO_CYCLE: true, - }, - }, - ], + }, 2), } Class.hyperspinmissile = { PARENT: "spinmissile", - GUNS: [ - { - POSITION: [14, 8, 1, 0, 0, 0, 0], - PROPERTIES: { - AUTOFIRE: !0, - SHOOT_SETTINGS: combineStats([g.basic, g.lowPower, {size: 1.1}]), - TYPE: ["bullet", { PERSISTS_AFTER_DEATH: true }], - STAT_CALCULATOR: gunCalcNames.thruster, - }, - }, - { - POSITION: [14, 8, 1, 0, 0, 180, 0], - PROPERTIES: { - AUTOFIRE: !0, - SHOOT_SETTINGS: combineStats([g.basic, g.lowPower, {size: 1.1}]), - TYPE: ["bullet", { PERSISTS_AFTER_DEATH: true }], - STAT_CALCULATOR: gunCalcNames.thruster, - }, + GUNS: weaponArray({ + POSITION: [14, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + AUTOFIRE: !0, + SHOOT_SETTINGS: combineStats([g.basic, g.lowPower, {size: 1.1}]), + TYPE: ["bullet", { PERSISTS_AFTER_DEATH: true }], + STAT_CALCULATOR: "thruster", }, - { - POSITION: [14, 8, 1, 0, 0, 90, 0], - PROPERTIES: { - AUTOFIRE: !0, - SHOOT_SETTINGS: combineStats([g.basic, g.lowPower, {size: 1.1}]), - TYPE: ["bullet", { PERSISTS_AFTER_DEATH: true }], - STAT_CALCULATOR: gunCalcNames.thruster, - }, - }, - { - POSITION: [14, 8, 1, 0, 0, 270, 0], - PROPERTIES: { - AUTOFIRE: !0, - SHOOT_SETTINGS: combineStats([g.basic, g.lowPower, {size: 1.1}]), - TYPE: ["bullet", { PERSISTS_AFTER_DEATH: true }], - STAT_CALCULATOR: gunCalcNames.thruster, - }, - }, - ], + }, 4), } Class.hive = { PARENT: "bullet", @@ -230,52 +219,19 @@ Class.hive = { }, FACING_TYPE: "turnWithSpeed", INDEPENDENT: true, - CONTROLLERS: ["alwaysFire", "nearestDifferentMaster", "targetSelf"], + CONTROLLERS: ["nearestDifferentMaster", "targetSelf"], AI: { NO_LEAD: true, }, - GUNS: [ - { - POSITION: [7, 9.5, 0.6, 7, 0, 108, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm, g.hive, g.bee]), - TYPE: ["bee", { PERSISTS_AFTER_DEATH: true }], - STAT_CALCULATOR: gunCalcNames.swarm, - }, - }, - { - POSITION: [7, 9.5, 0.6, 7, 0, 180, 0.2], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm, g.hive, g.bee]), - TYPE: ["bee", { PERSISTS_AFTER_DEATH: true }], - STAT_CALCULATOR: gunCalcNames.swarm, - }, - }, - { - POSITION: [7, 9.5, 0.6, 7, 0, 252, 0.4], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm, g.hive, g.bee]), - TYPE: ["bee", { PERSISTS_AFTER_DEATH: true }], - STAT_CALCULATOR: gunCalcNames.swarm, - }, - }, - { - POSITION: [7, 9.5, 0.6, 7, 0, 324, 0.6], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm, g.hive, g.bee]), - TYPE: ["bee", { PERSISTS_AFTER_DEATH: true }], - STAT_CALCULATOR: gunCalcNames.swarm, - }, - }, - { - POSITION: [7, 9.5, 0.6, 7, 0, 36, 0.8], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm, g.hive, g.bee]), - TYPE: ["bee", { PERSISTS_AFTER_DEATH: true }], - STAT_CALCULATOR: gunCalcNames.swarm, - }, + GUNS: weaponArray({ + POSITION: [7, 9.5, 0.6, 7, 0, 108, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.swarm, g.hive, g.bee]), + TYPE: ["bee", { PERSISTS_AFTER_DEATH: true }], + STAT_CALCULATOR: "swarm", + AUTOFIRE: true }, - ], + }, 5, 0.2) } Class.protoHive = { PARENT: "bullet", @@ -286,32 +242,17 @@ Class.protoHive = { }, FACING_TYPE: "turnWithSpeed", INDEPENDENT: true, - CONTROLLERS: ["alwaysFire", "nearestDifferentMaster", "targetSelf"], + CONTROLLERS: ["nearestDifferentMaster", "targetSelf"], AI: { NO_LEAD: true }, - GUNS: [ - { - POSITION: [7, 9.5, 0.6, 7, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm, g.hive, g.bee]), - TYPE: ["bee", { INDEPENDENT: true }], - STAT_CALCULATOR: gunCalcNames.swarm, - }, - }, { - POSITION: [7, 9.5, 0.6, 7, 0, 120, 0.2], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm, g.hive, g.bee]), - TYPE: ["bee", { INDEPENDENT: true }], - STAT_CALCULATOR: gunCalcNames.swarm, - }, - }, { - POSITION: [7, 9.5, 0.6, 7, 0, -120, 0.4], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm, g.hive, g.bee]), - TYPE: ["bee", { INDEPENDENT: true }], - STAT_CALCULATOR: gunCalcNames.swarm, - }, + GUNS: weaponArray({ + POSITION: [7, 9.5, 0.6, 7, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.swarm, g.hive, g.bee]), + TYPE: ["bee", { PERSISTS_AFTER_DEATH: true }], + STAT_CALCULATOR: "swarm", + AUTOFIRE: true }, - ], + }, 3, 1/3) } Class.snake = { PARENT: "bullet", @@ -325,7 +266,7 @@ Class.rocketeerMissile = { AUTOFIRE: true, SHOOT_SETTINGS: combineStats([g.basic, g.missileTrail, g.rocketeerMissileTrail]), TYPE: ["bullet", { PERSISTS_AFTER_DEATH: true }], - STAT_CALCULATOR: gunCalcNames.thruster, + STAT_CALCULATOR: "thruster", }, }, ], @@ -345,7 +286,7 @@ Class.sentinelMissile = { AUTOFIRE: true, SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.destroyer]), TYPE: ["bullet", { PERSISTS_AFTER_DEATH: true }], - STAT_CALCULATOR: gunCalcNames.thruster, + STAT_CALCULATOR: "thruster", }, }, { POSITION: [14, 6, 1, 0, -2, 130, 0], @@ -353,7 +294,7 @@ Class.sentinelMissile = { AUTOFIRE: true, SHOOT_SETTINGS: combineStats([g.basic, g.skimmer]), TYPE: ["bullet", { PERSISTS_AFTER_DEATH: true }], - STAT_CALCULATOR: gunCalcNames.thruster, + STAT_CALCULATOR: "thruster", }, }, { POSITION: [14, 6, 1, 0, 2, 230, 0], @@ -361,7 +302,7 @@ Class.sentinelMissile = { AUTOFIRE: true, SHOOT_SETTINGS: combineStats([g.basic, g.skimmer]), TYPE: ["bullet", { PERSISTS_AFTER_DEATH: true }], - STAT_CALCULATOR: gunCalcNames.thruster, + STAT_CALCULATOR: "thruster", }, }, ], @@ -370,59 +311,55 @@ Class.kronosMissile = { PARENT: "missile", GUNS: [ { - POSITION: [4, 8, 1.5, 14, 0, 90, 0.5], + POSITION: [4, 6, 1.6, 13, 0, 90, 0.5], PROPERTIES: { AUTOFIRE: true, - SHOOT_SETTINGS: combineStats([g.trap, { range: 0.5 }, {reload: 3}]), + SHOOT_SETTINGS: combineStats([g.trap, g.lowPower, {reload: 2, speed: 1.3, maxSpeed: 1.3, range: 0.5}]), TYPE: [ "trap", { PERSISTS_AFTER_DEATH: true } ], - STAT_CALCULATOR: gunCalcNames.trap, + STAT_CALCULATOR: "trap", }, }, { - POSITION: [4, 8, 1.5, 14, 0, -90, 0.5], + POSITION: [4, 6, 1.6, 13, 0, -90, 0.5], PROPERTIES: { AUTOFIRE: true, - SHOOT_SETTINGS: combineStats([g.trap, { range: 0.5 }, {reload: 3}]), + SHOOT_SETTINGS: combineStats([g.trap, g.lowPower, {reload: 2, speed: 1.3, maxSpeed: 1.3, range: 0.5}]), TYPE: [ "trap", { PERSISTS_AFTER_DEATH: true } ], - STAT_CALCULATOR: gunCalcNames.trap, + STAT_CALCULATOR: "trap", }, }, { POSITION: [14, 6, 1, 0, -2, 150, 0], PROPERTIES: { AUTOFIRE: true, - SHOOT_SETTINGS: combineStats([g.basic, {reload: 3}]), + SHOOT_SETTINGS: combineStats([g.basic, g.lowPower, {speed: 1.3, maxSpeed: 1.3}]), TYPE: [ "bullet", { PERSISTS_AFTER_DEATH: true } ], - STAT_CALCULATOR: gunCalcNames.thruster, + STAT_CALCULATOR: "thruster", }, }, { POSITION: [14, 6, 1, 0, 2, 210, 0], PROPERTIES: { AUTOFIRE: true, - SHOOT_SETTINGS: combineStats([g.basic, {reload: 3}]), + SHOOT_SETTINGS: combineStats([g.basic, g.lowPower, {speed: 1.3, maxSpeed: 1.3}]), TYPE: [ "bullet", { PERSISTS_AFTER_DEATH: true } ], - STAT_CALCULATOR: gunCalcNames.thruster, + STAT_CALCULATOR: "thruster", }, }, { - POSITION: [14, 8, 1, 0, 0, 90, 0], + POSITION: [13, 6, 1, 0, 0, 90, 0], }, { - POSITION: [14, 8, 1, 0, 0, -90, 0], + POSITION: [13, 6, 1, 0, 0, -90, 0], }, ], } Class.autoSmasherMissile = { PARENT: "missile", - LABEL: "Auto-Smasher", HITS_OWN_TYPE: "never", - BODY: { - FOV: 1.05 * base.FOV, - DENSITY: 2 * base.DENSITY, - }, + GUNS: [], TURRETS: [ { POSITION: [21.5, 0, 0, 0, 360, 0], TYPE: "smasherBody", }, { - POSITION: [11, 0, 0, 0, 360, 1], - TYPE: ["auto4gun", { INDEPENDENT: true }], + POSITION: [12, 0, 0, 0, 360, 1], + TYPE: "autoSmasherMissileTurret", }, ], } @@ -455,22 +392,6 @@ Class.surgeonPillbox = { // Drones Class.turretedDrone = makeAuto('drone', "Auto-Drone", {type: 'droneAutoTurret'}) -Class.gemDrone = { - PARENT: "drone", - COLOR: "aqua", - DRAW_HEALTH: true, - SHAPE: 6, - INDEPENDENT: true, - BODY: { - PUSHABILITY: 0.3, - HEALTH: 0.3*5, - DAMAGE: 3.375/5, - SPEED: 1, - DENSITY: 0.1, - RESIST: 3, - FOV: 100, - }, -} // Sunchips Class.sunchip = { @@ -546,12 +467,12 @@ Class.minion = { LABEL: "Minion", TYPE: "minion", DAMAGE_CLASS: 0, - HITS_OWN_TYPE: "hardWithBuffer", + HITS_OWN_TYPE: "hard", FACING_TYPE: "smoothToTarget", BODY: { FOV: 0.5, SPEED: 3, - ACCELERATION: 0.4, + ACCELERATION: 1, HEALTH: 5, SHIELD: 0, DAMAGE: 1.2, @@ -615,6 +536,39 @@ Class.tinyMinion = { DIE_AT_RANGE: true, BUFF_VS_FOOD: true, } +Class.sentrySwarmMinion = { + PARENT: 'drone', + LABEL: 'sentry', + COLOR: 'pink', + UPGRADE_COLOR: "pink", + DRAW_HEALTH: true, + HAS_NO_RECOIL: true, + GUNS: Class.sentrySwarm.GUNS +} +Class.sentryGunMinion = { + PARENT: 'drone', + LABEL: 'sentry', + COLOR: 'pink', + UPGRADE_COLOR: "pink", + DRAW_HEALTH: true, + HAS_NO_RECOIL: true, + TURRETS: [{ + POSITION: [12, 0, 0, 0, 360, 1], + TYPE: ['megaAutoTankGun', {GUN_STAT_SCALE: {health: 0.8}}] + }] +} +Class.sentryTrapMinion = { + PARENT: 'drone', + LABEL: 'sentry', + COLOR: 'pink', + UPGRADE_COLOR: "pink", + DRAW_HEALTH: true, + HAS_NO_RECOIL: true, + TURRETS: [{ + POSITION: [12, 0, 0, 0, 360, 1], + TYPE: 'trapTurret' + }] +} // Traps Class.setTrap = { @@ -659,7 +613,6 @@ Class.assemblerTrap = { }, TURRETS: [ { - /** SIZE X Y ANGLE ARC */ POSITION: [4, 0, 0, 0, 360, 1], TYPE: 'assemblerDot' } @@ -670,12 +623,22 @@ Class.shotTrapBox = { PARENT: 'unsetTrap', MOTION_TYPE: "glide", } +Class.ramrodTrap = { + PARENT: "setTrap", + INDEPENDENT: true, + FACING_TYPE: "withMaster", + CONTROLLERS: ["nearestDifferentMaster"], + GUNS: [ + { + POSITION: [30, 10, 1, 0, 0, 90, 0] + } + ] +} // Pillboxes Class.pillbox = { PARENT: "setTrap", LABEL: "Pillbox", - CONTROLLERS: ["nearestDifferentMaster"], INDEPENDENT: true, DIE_AT_RANGE: true, TURRETS: [ @@ -688,7 +651,6 @@ Class.pillbox = { Class.unsetPillbox = { PARENT: "unsetTrap", LABEL: "Pillbox", - CONTROLLERS: ["nearestDifferentMaster"], INDEPENDENT: true, DIE_AT_RANGE: true, TURRETS: [ @@ -743,3 +705,690 @@ Class.homingBullet = { }, CAN_GO_OUTSIDE_ROOM: true } + +//delta projectiles +Class.autobullet = makeAuto('bullet', "AutoBullet", {type: 'projectileAutoTurret'}) +Class.heavyautobullet = makeAuto('bullet', "HeavyAutoBullet", {type: 'pillboxTurret'}) +Class.shrapnel = { + PARENT: "bullet", + SHAPE: 5, + LABEL: "expold heheahah", + BODY: { + RANGE: 1, + FOV: 0.5, + }, + INDEPENDENT: true, + CONTROLLERS: ["alwaysFire"], + AI: { + NO_LEAD: true, + }, + GUNS: [ + { + POSITION: [7, 9.5, 1, 7, 0, 72, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.swarm, g.hive, g.bee, g.halfspeed, g.halfspeed, g.halfspeed, g.halfrange, g.halfrange]), + TYPE: ["trap", { PERSISTS_AFTER_DEATH: true }], + STAT_CALCULATOR: "swarm", + }, + }, + { + POSITION: [7, 9.5, 1, 7, 0, 72*2, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.swarm, g.hive, g.bee, g.halfspeed, g.halfspeed, g.halfrange, g.halfspeed, g.halfrange]), + TYPE: ["trap", { PERSISTS_AFTER_DEATH: true }], + STAT_CALCULATOR: "swarm", + }, + }, + { + POSITION: [7, 9.5, 1, 7, 0, 72*3, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.swarm, g.hive, g.bee, g.halfspeed, g.halfspeed, g.halfrange, g.halfspeed, g.halfrange]), + TYPE: ["trap", { PERSISTS_AFTER_DEATH: true }], + STAT_CALCULATOR: "swarm", + }, + }, + { + POSITION: [7, 9.5, 1, 7, 0, 72*4, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.swarm, g.hive, g.bee, g.halfspeed, g.halfspeed, g.halfrange, g.halfspeed, g.halfrange]), + TYPE: ["trap", { PERSISTS_AFTER_DEATH: true }], + STAT_CALCULATOR: "swarm", + }, + }, + { + POSITION: [7, 9.5, 1, 7, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.swarm, g.hive, g.bee, g.halfspeed, g.halfspeed, g.halfrange, g.halfspeed, g.halfrange]), + TYPE: ["trap", { PERSISTS_AFTER_DEATH: true }], + STAT_CALCULATOR: "swarm", + }, + }, + ], +} +Class.grenade = { + PARENT: "bullet", + INDEPENDENT: true, + BODY: { RANGE: 80 }, + GUNS: [{ + POSITION: [1, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.grenade_explosion]), + TYPE: ["shrapnel", { PERSISTS_AFTER_DEATH: true }], + SHOOT_ON_DEATH: true, + } + }, { + POSITION: [14, 6, 1, 0, 0, 180, 0], + PROPERTIES: { + AUTOFIRE: true, + SHOOT_SETTINGS: combineStats([g.basic, g.skimmer, { reload: 0.5 }, g.lowPower, { recoil: 1.35 }, { speed: 1.3, maxSpeed: 1.3 }]), + TYPE: ["bullet", { PERSISTS_AFTER_DEATH: true }], + STAT_CALCULATOR: "thruster", + } + } + ], + TURRETS: [{ + POSITION: [9, -8, 0, 0, 0, 1], + TYPE: ["grenadeDeco"] + } + ] +} +Class.blasterbullet = { + PARENT: "bullet", + INDEPENDENT: true, + GUNS: [{ + POSITION: [1, 8, 1, 0, 0, 180, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { range: 0.1, size: 10, damage: 1.5, maxSpeed: 0.01, speed: 0.01 }]), + TYPE: ["bullet", { PERSISTS_AFTER_DEATH: true, TYPE: "shield" }], + SHOOT_ON_DEATH: true, + } + } + ] +} +Class.firecrackerbomb = { + PARENT: "bullet", + INDEPENDENT: true, + BODY: { RANGE: 70 }, + GUNS: [{ + POSITION: [1, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.explosion]), + TYPE: ["growBullet", { PERSISTS_AFTER_DEATH: true }], + SHOOT_ON_DEATH: true, + } + }, { + POSITION: [14, 6, 1, 0, 0, 180, 0], + PROPERTIES: { + AUTOFIRE: true, + SHOOT_SETTINGS: combineStats([g.basic, { recoil: 0.5 }, g.lowPower]), + TYPE: ["bullet", { PERSISTS_AFTER_DEATH: true }], + STAT_CALCULATOR: "thruster", + }, + }, + ], + TURRETS: [{ + POSITION: [10, 0, 0, 0, 0, 1], + TYPE: "firecrackerDeco" + }] +} +Class.baseBullet = { + PARENT: "trap", + MOTION_TYPE: "motor", + HITS_OWN_TYPE: "never", + BODY: { + SPEED: 1.25, + RANGE: 120, + }, + LABEL: "Base", + SHAPE: 'M 0 -1 A 1 1 0 0 0 0 1 A 1 1 0 0 0 0 -1 Z M 0 -1 A 0.001 0.001 0 0 1 0 1 A 0.001 0.001 0 0 1 0 -1', + CONTROLLERS: [["spin", { independent: true, speed: 0.1 }], "kiva"], + INDEPENDENT: true, + FACING_TYPE: "toTarget", + COLOR: "#FC8208", + TURRETS: [{ + POSITION: [4.65, 9.85, 0, 90, 220, 1], + TYPE: ["revogun", { COLOR: "#FC8208", BODY: { FOV: 2 } }] + }, { + POSITION: [4.65, 9.85, 0, 270, 220, 1], + TYPE: ["revogun", { COLOR: "#FC8208", BODY: { FOV: 2 } }] + }], +ON: [{ + event: "death", + handler: ({ body }) => { + if (!body.master.isDead) return + body.master.define(Class.baseThrower) + } + } + ] +}; +Class.brellaShield = { + PARENT: "bullet", + TYPE: "brella", + LABEL: "Base", + SIZE: 7, + //SHAPE: 'M 1 3.5 L 2 2 L 2 0 L 1 -1.5 L 0 -1.8 L 0 -1 L 2 0.5 L 0 -1 L 0 0 L 2 0.85 L 0 0 L 0 1 L 2 1 L 0 1 L 0 1 L 0 2 L 2 1.15 L 0 2 L 0 3 L 2 1.5 L 0 3 L 0 3.8 L 1 3.5', + SHAPE: 'M -0 2.2587 L 0.9 0.905 L 0.9 -0.9 L -0 -2.2537 L -0.9 -2.5245 L -0.9 2.5295 L -0 2.2587', + INDEPENDENT: true, + BODY: { + PENETRATION: 0.01 + }, + COLOR: "grey", + GUNS: [ + { + POSITION: [14, 6, 1, 0, 0, 180, 0], + PROPERTIES: { + AUTOFIRE: true, + SHOOT_SETTINGS: combineStats([g.basic, { recoil: 0.35 }, g.lowPower]), + TYPE: ["bullet", { PERSISTS_AFTER_DEATH: true }], + STAT_CALCULATOR: "thruster", + }, + }, + ], +}; +Class.laser = { + PARENT: "bullet", + SHAPE: -1, + BODY: { + PENETRATION: 1.1, + SPEED: 5.8, + RANGE: 100, + DENSITY: 0.9, + HEALTH: 0.155, + DAMAGE: 5.6, + }, + BUFF_VS_FOOD: true, +} +Class.fastdrone = { + PARENT: "drone", + LABEL: 'Drone', + BODY: { + PENETRATION: 1.2, + PUSHABILITY: 0.6, + ACCELERATION: 0.05, + HEALTH: 0.5, + DAMAGE: 3.125, + SPEED: 6, + RANGE: 200, + DENSITY: 0.03, + RESIST: 1.5, + FOV: 0.8, + }, + GUNS: [ { /*** LENGTH WIDTH ASPECT X Y ANGLE DELAY */ + POSITION: [ 15, 5, 1, 0, 0, 180, 0, ], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.muchmorerecoil, g.muchmorerecoil, g.weak]), + TYPE: "bullet", + AUTOFIRE: true + }, }, + ], + HITS_OWN_TYPE: 'hard', + DRAW_HEALTH: false, + CLEAR_ON_MASTER_UPGRADE: true, + BUFF_VS_FOOD: true, +}; + +Class.revoorbitdrone = { + PARENT: "drone", + LABEL: 'Drone', + SYNC_TURRET_SKILLS: true, + TURRETS: [{ + POSITION: [34, 0, 0, 0, 360, 0], + TYPE: "droneturretBase", + }, + ], +}; +Class.hiveprobe = { + PARENT: "genericTank", + LABEL: "Probe", + TYPE: "drone", + HITS_OWN_TYPE: "hardWithBuffer", + DRAW_HEALTH: true, + BODY: { + FOV: 0.5, + SPEED: 3, + ACCELERATION: 0.4, + HEALTH: 2.5, + SHIELD: 0, + DAMAGE: 1.2, + RESIST: 1, + PENETRATION: 1, + DENSITY: 0.4 + }, + AI: { + BLIND: true + }, + CLEAR_ON_MASTER_UPGRADE: true, + GIVE_KILL_MESSAGE: false, + ACCEPTS_SCORE: false, + CONTROLLERS: [ + "nearestDifferentMaster", + "mapAltToFire", + "minion", + "canRepel", + "hangOutNearMaster" + ], + GUNS: [ + { + /*** LENGTH WIDTH ASPECT X Y ANGLE DELAY */ + POSITION: [18, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.lowPower]), + TYPE: "bullet" + } + } + ], + TURRETS: [ + { + /* SIZE X Y ANGLE ARC */ + POSITION: [27, 0, 0, 0, 360, 0], + TYPE: "mindindicator" + } + ] +}; +Class.clonerprobe = { + PARENT: "hiveprobe", + GUNS: [ + { + /*** LENGTH WIDTH ASPECT X Y ANGLE DELAY */ + POSITION: [18, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.lowPower]), + TYPE: "bullet" + } + } + ], + TURRETS: [ + { + /* SIZE X Y ANGLE ARC */ + POSITION: [24, 0, 0, 0, 360, 0], + TYPE: "mindindicator" + } + ] +} +Class.autoclonerprobe = makeAuto(Class.clonerprobe) +Class.spaghetti = { + PARENT: "bullet", + SHOOT_ON_DEATH: true, + SHAPE: "https://cdn.glitch.global/5fc7dcb6-aada-495b-828e-66901a470a29/afg-spaghetti-alla-assassina-1-19ef-superJumbo.jpg?v=1701450288242", + GUNS: [ + { + POSITION: [2, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.single]), + TYPE: "bullet" + } + } + ] +} +const timer = (run, duration) => { + let timer = setInterval(() => run(), 31.25); + setTimeout(() => { + clearInterval(timer); + }, duration * 1000); +}; + const damageOnTick = (body, instance, multiplier, duration, stopAtSetHealth, hitsOwnTeam) => { + if (!instance) return + if (!instance.damageOnTicking && !instance.godmode && !instance.invuln && (instance.type == "tank" || instance.type == "food" || instance.type == "miniboss" || instance.type == "crasher") && instance.team != body.team) { + instance.damageOnTicking = true; + setTimeout(() => { + instance.damageOnTicking = false; + }, 2 * duration * 1000); + timer(() => { + if (instance.damageOnTicking && instance.health.amount > stopAtSetHealth && instance.health.amount - (multiplier * 0.5) > stopAtSetHealth) { + instance.health.amount -= multiplier * 0.5; + } //else {if (instance.health.amount - (multiplier * 0.5) < stopAtSetHealth) {instance.health.amount === stopAtSetHealth}} + }, 2 * duration); + } +}; +const iceOnTick = (body, instance, multiplier, duration, hitsOwnTeam) => { + if (!instance) return + if (!instance.invuln && !instance.godmode && (instance.type == "tank" || instance.type == "food" || instance.type == "miniboss" || instance.type == "crasher") && instance.team != body.team) timer(() => { + instance.velocity.x /= 1.05 * multiplier; + instance.velocity.y /= 1.05 * multiplier; + }, 1.5 * duration); +}; +Class.poisonbullet = { + PARENT: "bullet", + GLOW: { + RADIUS: 2, + COLOR: "green", + ALPHA: 1, + RECURSION: 4, + }, + TURRETS: [{ + POSITION: [5.5, 0, 0, 0, 0, 1], + TYPE: ["effectBulletDeco", { color: "green" }] + }], + ON: [{ + event: "damage", + handler: ({ body, damageTool }) => { + damageOnTick(body, damageTool[0], 2, 1, 1, false); + } + }] +} +Class.icebullet = { + PARENT: "bullet", + GLOW: { + RADIUS: 2, + COLOR: "#28B1DE", + ALPHA: 1, + RECURSION: 4, + }, + TURRETS: [{ + POSITION: [5.5, 0, 0, 0, 0, 1], + TYPE: ["effectBulletDeco", { color: "#28B1DE" }] + }], + ON: [{ + event: "damage", + handler: ({ body, damageTool }) => { + iceOnTick(body, damageTool[0], 1, 1, true); + } + }] +} +Class.poisonicebullet = { + PARENT: "bullet", + GLOW: { + RADIUS: 2, + COLOR: "#28dead", + ALPHA: 1, + RECURSION: 4, + }, + TURRETS: [{ + POSITION: [5, 0, 0, 0, 0, 2], + TYPE: ["effectBulletDeco", { color: "#28B1DE" }] + }, { + POSITION: [7, 0, 0, 0, 0, 1], + TYPE: ["effectBulletDeco", { color: "green" }] + }], + ON: [{ + event: "damage", + handler: ({ body, damageTool }) => { + damageOnTick(body, damageTool[0], 2, 1, 1, false); + iceOnTick(body, damageTool[0], 1, 1, true); + } + }] +} +Class.empBullet = { + PARENT: "bullet", + ON: [{ + event: "damage", + handler: ({ body, damageTool }) => { + iceOnTick(body, damageTool[0], Infinity, 2.5, true); + } + }] +} +Class.icetrap = { + PARENT: "trap", + GLOW: { + RADIUS: 2, + COLOR: "#28B1DE", + ALPHA: 1, + RECURSION: 4, + }, + TURRETS: [{ + POSITION: [5.5, 0, 0, 0, 0, 1], + TYPE: ["effectBulletDeco", { color: "#28B1DE" }] + }], + ON: [{ + event: "damage", + handler: ({ body, damageTool }) => { + iceOnTick(body, damageTool[0], 1, 1, true); + } + }] +} +Class.setIceTrap = { + PARENT: "setTrap", + GLOW: { + RADIUS: 2, + COLOR: "#28B1DE", + ALPHA: 1, + RECURSION: 4, + }, + TURRETS: [{ + POSITION: [5.5, 0, 0, 0, 0, 1], + TYPE: ["effectBulletDeco", { color: "#28B1DE" }] + }], + ON: [{ + event: "damage", + handler: ({ body, damageTool }) => { + iceOnTick(body, damageTool[0], 1, 1, true); + } + }] +} +Class.ceptionistbullet = { + PARENT: "bullet", + GUNS: [{ + POSITION: [18, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.autoTurret, g.lesspower, g.lesspower, g.halfreload, g.halfreload, g.turret]), + TYPE: "bullet", + COLOR: "black", + AUTOFIRE: true + } + } + ] +} +Class.autoturretswarm = makeAuto('swarm', "AutoturretSwarm", {type: 'droneAutoTurret'}) +Class.hybridclonerprobe = makeOver('clonerprobe', "hybrid-cloner-probe", {count: 1, independent: true, cycle: false}) +Class.nuke = { + PARENT: "growBullet", + LABEL: "Nuke", + MOTION_TYPE: "fuckingnuclearbomb", + BODY: { + PENETRATION: 100, + SPEED: 7, + RANGE: 600, + DENSITY: 99999999999, + HEALTH: 99999, + DAMAGE: 999999, + PUSHABILITY: -99999999, + }, +}; +Class.denseasfbullet = { + PARENT: "bullet", + BODY: { + DENSITY: 999999999, + SPEED: 12 + } +} +Class.surgeempBullet = { + PARENT: "bullet", + HITS_OWN_TYPE: "never", + COLOR: "spaceGem", + ALPHA: 0.8, + BODY: { + }, + BORDERLESS: true, + GLOW: { + RADIUS: 1, + COLOR: "spaceGem", + ALPHA: 1, + RECURSION: 1, + } +}; +Class.flashfireBullet = { + PARENT: "bullet", + HITS_OWN_TYPE: "never", + COLOR: "#de2410", + ALPHA: 0.8, + BODY: { + }, + BORDERLESS: true, + GLOW: { + RADIUS: 1, + COLOR: "#de2410", + ALPHA: 1, + RECURSION: 1, + } +}; +Class.lineEMP = { + PARENT: "bullet", + LABEL: 'Line', + SHAPE: -1, + ARENA_CLOSER: true, + HAS_NO_RECOIL: true, + GUNS: [{ + POSITION: [18, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.lance]), + TYPE: "empBullet", + AUTOFIRE: true, + ALPHA: 0, + } + }], + GLOW: { + RADIUS: 3, + COLOR: "spaceGem", + ALPHA: 1, + RECURSION: 3, + } +} +Class.stickyTrap = { + PARENT: "setTrap", + TYPE: "popup", + HITS_OWN_TYPE: "hard", + LABEL: "Sticky Trap", + SHAPE: -8, + COLOR: "white", + GUNS: [{ + POSITION: [4, 4, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.magnet]), + TYPE: ["bullet", { SIZE: 5, ALPHA: 0.5 }], + AUTOFIRE: true + }, + }], + ON: [{ + event: "collide", + handler: ({ body, other }) => { + if ((other.team != body.team || other.master.id != body.master.id) && other.type != "wall" && other.isTurret != true) { + body.velocity.x = 0; + body.velocity.y = 0; + let amount = util.getDistance(body, other), + angle = Math.atan2(body.y - other.y, body.x - other.x); + other.velocity.x += amount * Math.cos(angle); + other.velocity.y += amount * Math.sin(angle); + } + } + }], +} +Class.katanaparticle = { + LABEL: "kpartic", + ACCEPTS_SCORE: false, + BODY: { + PENETRATION: 1, + SPEED: 3.75, + RANGE: 90, + DENSITY: 1.25, + HEALTH: 10, + DAMAGE: 6, + PUSHABILITY: 0.3, + }, + COLOR: 'mirror', + FACING_TYPE: "toTarget", + CAN_GO_OUTSIDE_ROOM: true, + HITS_OWN_TYPE: "never", + DIE_AT_RANGE: true, + GUNS: [ + { + POSITION: [20, 15, 0.001, 0, 0, 0, 0], + }, { + POSITION: [25, 15, 0.001, 0, 0, 0, 0] + } + ], +} +Class.shadowparticle = { + LABEL: "kpartic", + ACCEPTS_SCORE: false, + BODY: { + PENETRATION: 1, + SPEED: 3.75, + RANGE: 90, + DENSITY: 1.25, + HEALTH: 10, + DAMAGE: 6, + PUSHABILITY: 0.3, + }, + COLOR: 'mirror', + FACING_TYPE: "toTarget", + CAN_GO_OUTSIDE_ROOM: true, + HITS_OWN_TYPE: "never", + DIE_AT_RANGE: true, + GUNS: [ + { + POSITION: [18, 8, 1, 0, 0, 0, 0], + }, + { + POSITION: [16, 8, 1, 0, 0, 180, 0.1], + } + ], +} +Class.polygunMinion = { + PARENT: "minion", + LABEL: 'Protectorate', + SHAPE: 4, + AI: { + FARMER: true + }, + INDEPENDENT: true, + GUNS: [], + TURRETS: [{ + POSITION: [9, 8, 0, 0, 170, 0], + TYPE: "autoTurret3" + }, { + POSITION: [9, 8, 0, 90, 170, 0], + TYPE: "autoTurret3" + }, { + POSITION: [9, 8, 0, 180, 170, 0], + TYPE: "autoTurret3" + }, { + POSITION: [9, 8, 0, 270, 170, 0], + TYPE: "autoTurret3" + }] +}; + Class.undertowBlock = { + PARENT: 'setTrap', + ON: [ + { + event: "tick", + handler: ({ body }) => { + for (let instance of entities) { + let diffX = instance.x - body.x, + diffY = instance.y - body.y, + dist2 = diffX ** 2 + diffY ** 2; + if (dist2 <= ((body.size / 12)*250) ** 1.9) { + if ((instance.team != body.team || (instance.type == "undertowEffect" && instance.master.id == body.master.id)) && instance.type != "wall" && instance.isTurret != true) { + if (instance.type == "undertowEffect") { + forceMulti = 1 + } + else if (instance.type == "food") { + forceMulti = (6 / instance.size) + } + else { + forceMulti = (2 / instance.size) + } + instance.velocity.x += util.clamp(body.x - instance.x, -90, 90) * instance.damp * forceMulti;//0.05 + instance.velocity.y += util.clamp(body.y - instance.y, -90, 90) * instance.damp * forceMulti;//0.05 + if (instance.type != "undertowEffect" && instance.type != "bullet" && instance.type != "swarm" && instance.type != "drone" && instance.type != "trap" && instance.type != "dominator") { + let o = new Entity({x: instance.x, y: instance.y}) + o.define('undertowEffect') + o.team = body.team; + o.color = instance.color; + o.alpha = 0.3; + o.master = body.master; + } + } + } + if (dist2 < body.size ** 3 + instance.size ** 3) { + if (instance.master.id == body.master.id) { + if (instance.type == "undertowEffect") + { + instance.kill(); + } + } + } + } + } + } + ], + } \ No newline at end of file diff --git a/server/modules/definitions/groups/tanks.js b/server/modules/definitions/groups/tanks.js index 79c65b7d4..cc63b7b8d 100644 --- a/server/modules/definitions/groups/tanks.js +++ b/server/modules/definitions/groups/tanks.js @@ -1,3663 +1,8814 @@ -const { combineStats, makeAuto, makeOver, makeDeco, makeGuard, makeBird, makeMulti, makeRadialAuto, weaponArray } = require('../facilitators.js'); -const { base, statnames, gunCalcNames, dfltskl, smshskl } = require('../constants.js'); -require('./generics.js'); -const g = require('../gunvals.js'); - -// Basic & starting upgrades -Class.basic = { - PARENT: "genericTank", - LABEL: "Basic", - DANGER: 4, - /*BODY: { - ACCELERATION: base.ACCEL * 1, - SPEED: base.SPEED * 1, - HEALTH: base.HEALTH * 1, - DAMAGE: base.DAMAGE * 1, - PENETRATION: base.PENETRATION * 1, - SHIELD: base.SHIELD * 1, - REGEN: base.REGEN * 1, - FOV: base.FOV * 1, - DENSITY: base.DENSITY * 1, - PUSHABILITY: 1, - HETERO: 3 - },*/ - GUNS: [ - { - POSITION: [18, 8, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic]), - TYPE: "bullet", - /*COLOR: "grey", - LABEL: "", - STAT_CALCULATOR: 0, - WAIT_TO_CYCLE: false, - AUTOFIRE: false, - SYNCS_SKILLS: false, - MAX_CHILDREN: 0, - ALT_FIRE: false, - NEGATIVE_RECOIL: false*/ - } - } - ] -} -Class.twin = { - PARENT: "genericTank", - LABEL: "Twin", - GUNS: [ - { - POSITION: [20, 8, 1, 0, 5.5, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin]), - TYPE: "bullet" - } - }, - { - POSITION: [20, 8, 1, 0, -5.5, 0, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin]), - TYPE: "bullet" - } - } - ] -} -Class.sniper = { - PARENT: "genericTank", - LABEL: "Sniper", - BODY: { - FOV: 1.2 * base.FOV - }, - GUNS: [ - { - POSITION: [24, 8.5, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper]), - TYPE: "bullet" - } - } - ] -} -Class.machineGun = { - PARENT: "genericTank", - LABEL: "Machine Gun", - GUNS: [ - { - POSITION: [12, 10, 1.4, 8, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.machineGun]), - TYPE: "bullet" - } - } - ] -} -Class.flankGuard = { - PARENT: "genericTank", - LABEL: "Flank Guard", - BODY: { - SPEED: 1.1 * base.SPEED - }, - GUNS: weaponArray({ - POSITION: [18, 8, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard]), - TYPE: "bullet" - } - }, 3) -} -Class.director = { - PARENT: "genericTank", - LABEL: "Director", - STAT_NAMES: statnames.drone, - BODY: { - FOV: base.FOV * 1.1 - }, - GUNS: [ - { - POSITION: [6, 11, 1.3, 7, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone]), - TYPE: "drone", - AUTOFIRE: true, - SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.drone, - MAX_CHILDREN: 6, - WAIT_TO_CYCLE: true - } - } - ] -} -Class.pounder = { - PARENT: "genericTank", - LABEL: "Pounder", - GUNS: [ - { - POSITION: [20.5, 12, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder]), - TYPE: "bullet" - } - } - ] -} -Class.trapper = { - PARENT: "genericTank", - LABEL: "Trapper", - STAT_NAMES: statnames.trap, - GUNS: [ - { - POSITION: [15, 7, 1, 0, 0, 0, 0] - }, - { - POSITION: [3, 7, 1.7, 15, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap]), - TYPE: "trap", - STAT_CALCULATOR: gunCalcNames.trap - } - } - ] -} -Class.desmos = { - PARENT: "genericTank", - LABEL: "Desmos", - STAT_NAMES: statnames.desmos, - GUNS: [ - { - POSITION: [20, 10, 0.8, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.desmos]), - TYPE: ["bullet", {MOTION_TYPE: "desmos"}] - } - }, - { - POSITION: [3.75, 10, 2.125, 1.25, -6.25, 90, 0] - }, - { - POSITION: [3.75, 10, 2.125, 1.25, 6.25, -90, 0] - } - ] -} -Class.smasher = { - PARENT: "genericSmasher", - LABEL: "Smasher", - DANGER: 6, - TURRETS: [ - { - POSITION: [21.5, 0, 0, 0, 360, 0], - TYPE: "smasherBody" - } - ] -} -Class.healer = { - PARENT: "genericTank", - LABEL: "Healer", - STAT_NAMES: statnames.heal, - TURRETS: [ - { - POSITION: [13, 0, 0, 0, 360, 1], - TYPE: "healerSymbol" - } - ], - GUNS: [ - { - POSITION: [8, 9, -0.5, 12.5, 0, 0, 0] - }, - { - POSITION: [18, 10, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.healer]), - TYPE: "healerBullet" - } - } - ] -} - -// Twin upgrades -Class.doubleTwin = { - PARENT: "genericTank", - LABEL: "Double Twin", - DANGER: 6, - GUNS: weaponArray([ - { - POSITION: [20, 8, 1, 0, 5.5, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.doubleTwin]), - TYPE: "bullet" - } - }, - { - POSITION: [20, 8, 1, 0, -5.5, 0, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.doubleTwin]), - TYPE: "bullet" - } - } - ], 2) -} -Class.tripleShot = { - PARENT: "genericTank", - LABEL: "Triple Shot", - DANGER: 6, - BODY: { - SPEED: base.SPEED * 0.9 - }, - GUNS: [ - { - POSITION: [19, 8, 1, 0, -2, -17.5, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.tripleShot]), - TYPE: "bullet" - } - }, - { - POSITION: [19, 8, 1, 0, 2, 17.5, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.tripleShot]), - TYPE: "bullet" - } - }, - { - POSITION: [22, 8, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.tripleShot]), - TYPE: "bullet" - } - } - ] -} - -// Double Twin upgrades -Class.tripleTwin = { - PARENT: "genericTank", - LABEL: "Triple Twin", - DANGER: 7, - GUNS: weaponArray([ - { - POSITION: [20, 8, 1, 0, 5.5, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.spam, g.doubleTwin]), - TYPE: "bullet" - } - }, - { - POSITION: [20, 8, 1, 0, -5.5, 0, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.spam, g.doubleTwin]), - TYPE: "bullet" - } - } - ], 3) -} -Class.hewnDouble = { - PARENT: "genericTank", - LABEL: "Hewn Double", - DANGER: 7, - GUNS: [ - { - POSITION: [19, 8, 1, 0, 5.5, 205, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.twin, g.doubleTwin, g.hewnDouble, { recoil: 1.15 }]), - TYPE: "bullet" - } - }, - { - POSITION: [19, 8, 1, 0, -5.5, -205, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.twin, g.doubleTwin, g.hewnDouble, { recoil: 1.15 }]), - TYPE: "bullet" - } - }, - { - POSITION: [20, 8, 1, 0, 5.5, 180, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.doubleTwin, g.hewnDouble, { recoil: 1.15 }]), - TYPE: "bullet" - } - }, - { - POSITION: [20, 8, 1, 0, -5.5, 180, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.doubleTwin, g.hewnDouble, { recoil: 1.15 }]), - TYPE: "bullet" - } - }, - { - POSITION: [20, 8, 1, 0, 5.5, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.doubleTwin, g.hewnDouble]), - TYPE: "bullet" - } - }, - { - POSITION: [20, 8, 1, 0, -5.5, 0, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.doubleTwin, g.hewnDouble]), - TYPE: "bullet" - } - } - ] -} - -// Triple Shot upgrades -Class.pentaShot = { - PARENT: "genericTank", - LABEL: "Penta Shot", - DANGER: 7, - BODY: { - SPEED: 0.85 * base.SPEED - }, - GUNS: [ - { - POSITION: [16, 8, 1, 0, -3, -30, 0.667], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.tripleShot]), - TYPE: "bullet" - } - }, - { - POSITION: [16, 8, 1, 0, 3, 30, 0.667], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.tripleShot]), - TYPE: "bullet" - } - }, - { - POSITION: [19, 8, 1, 0, -2, -15, 0.333], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.tripleShot]), - TYPE: "bullet" - } - }, - { - POSITION: [19, 8, 1, 0, 2, 15, 0.333], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.tripleShot]), - TYPE: "bullet" - } - }, - { - POSITION: [22, 8, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.tripleShot]), - TYPE: "bullet" - } - } - ] -} -Class.spreadshot = { - PARENT: "genericTank", - LABEL: "Spreadshot", - DANGER: 7, - GUNS: [ - { - POSITION: [13, 4, 1, 0, -0.5, -75, 5 / 6], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery, g.twin, g.spreadshot]), - TYPE: "bullet", - LABEL: "Spread" - } - }, - { - POSITION: [13, 4, 1, 0, 0.5, 75, 5 / 6], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery, g.twin, g.spreadshot]), - TYPE: "bullet", - LABEL: "Spread" - } - }, - { - POSITION: [14.5, 4, 1, 0, -0.5, -60, 4 / 6], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery, g.twin, g.spreadshot]), - TYPE: "bullet", - LABEL: "Spread" - } - }, - { - POSITION: [14.5, 4, 1, 0, 0.5, 60, 4 / 6], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery, g.twin, g.spreadshot]), - TYPE: "bullet", - LABEL: "Spread" - } - }, - { - POSITION: [16, 4, 1, 0, -0.5, -45, 3 / 6], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery, g.twin, g.spreadshot]), - TYPE: "bullet", - LABEL: "Spread" - } - }, - { - POSITION: [16, 4, 1, 0, 0.5, 45, 3 / 6], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery, g.twin, g.spreadshot]), - TYPE: "bullet", - LABEL: "Spread" - } - }, - { - POSITION: [17.5, 4, 1, 0, -0.5, -30, 2 / 6], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery, g.twin, g.spreadshot]), - TYPE: "bullet", - LABEL: "Spread" - } - }, - { - POSITION: [17.5, 4, 1, 0, 0.5, 30, 2 / 6], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery, g.twin, g.spreadshot]), - TYPE: "bullet", - LABEL: "Spread" - } - }, - { - POSITION: [19, 4, 1, 0, -1, -15, 1 / 6], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery, g.twin, g.spreadshot]), - TYPE: "bullet", - LABEL: "Spread" - } - }, - { - POSITION: [19, 4, 1, 0, 1, 15, 1 / 6], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery, g.twin, g.spreadshot]), - TYPE: "bullet", - LABEL: "Spread" - } - }, - { - POSITION: [12, 8, 1, 8, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.spreadshotMain, g.spreadshot]), - TYPE: "bullet" - } - } - ] -} -Class.bentDouble = { - PARENT: "genericTank", - LABEL: "Bent Double", - DANGER: 7, - GUNS: weaponArray([ - { - POSITION: [19, 8, 1, 0, -2, -17.5, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.tripleShot, g.doubleTwin]), - TYPE: "bullet" - } - }, - { - POSITION: [19, 8, 1, 0, 2, 17.5, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.tripleShot, g.doubleTwin]), - TYPE: "bullet" - } - }, - { - POSITION: [22, 8, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.tripleShot, g.doubleTwin]), - TYPE: "bullet" - } - } - ], 2) -} -Class.triplet = { - PARENT: "genericTank", - DANGER: 7, - LABEL: "Triplet", - BODY: { - FOV: 1.05 * base.FOV - }, - GUNS: [ - { - POSITION: [18, 10, 1, 0, 5, 0, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.triplet]), - TYPE: "bullet" - } - }, - { - POSITION: [18, 10, 1, 0, -5, 0, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.triplet]), - TYPE: "bullet" - } - }, - { - POSITION: [21, 10, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.triplet]), - TYPE: "bullet" - } - } - ] -} - -// Sniper upgrades -Class.assassin = { - PARENT: "genericTank", - DANGER: 6, - LABEL: "Assassin", - BODY: { - SPEED: 0.85 * base.SPEED, - FOV: 1.4 * base.FOV - }, - GUNS: [ - { - POSITION: [27, 8, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.assassin]), - TYPE: "bullet" - } - }, - { - POSITION: [5, 8, -1.4, 8, 0, 0, 0] - } - ] -} -Class.hunter = { - PARENT: "genericTank", - LABEL: "Hunter", - DANGER: 6, - BODY: { - SPEED: base.SPEED * 0.9, - FOV: base.FOV * 1.25 - }, - CONTROLLERS: ["zoom"], - TOOLTIP: "Hold right click to zoom.", - GUNS: [ - { - POSITION: [24, 8, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.hunterSecondary]), - TYPE: "bullet" - } - }, - { - POSITION: [21, 12, 1, 0, 0, 0, 0.25], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter]), - TYPE: "bullet" - } - } - ] -} -Class.rifle = { - PARENT: "genericTank", - LABEL: "Rifle", - DANGER: 6, - BODY: { - FOV: base.FOV * 1.225 - }, - GUNS: [ - { - POSITION: [20, 12, 1, 0, 0, 0, 0] - }, - { - POSITION: [24, 7, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.rifle]), - TYPE: "bullet" - } - } - ] -} - -// Assassin upgrades -Class.ranger = { - PARENT: "genericTank", - LABEL: "Ranger", - DANGER: 7, - BODY: { - SPEED: 0.8 * base.SPEED, - FOV: 1.5 * base.FOV, - }, - GUNS: [ - { - POSITION: [32, 8, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.assassin]), - TYPE: "bullet", - }, - }, - { - POSITION: [5, 8, -1.4, 8, 0, 0, 0], - }, - ], -} -Class.stalker = { - PARENT: "genericTank", - DANGER: 7, - LABEL: "Stalker", - BODY: { - SPEED: 0.85 * base.SPEED, - FOV: 1.35 * base.FOV - }, - INVISIBLE: [0.08, 0.03], - TOOLTIP: "Stay still to turn invisible.", - GUNS: [ - { - POSITION: [27, 8, -1.8, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.assassin]), - TYPE: "bullet" - } - } - ] -} -Class.single = { - PARENT: "genericTank", - LABEL: "Single", - DANGER: 7, - GUNS: [ - { - POSITION: [19, 8, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.single]), - TYPE: "bullet" - } - }, - { - POSITION: [5.5, 8, -1.8, 6.5, 0, 0, 0] - } - ] -} - -// Hunter upgrades -Class.predator = { - PARENT: "genericTank", - LABEL: "Predator", - DANGER: 7, - BODY: { - SPEED: base.SPEED * 0.9, - FOV: base.FOV * 1.25 - }, - CONTROLLERS: ["zoom"], - TOOLTIP: "Hold right click to zoom.", - GUNS: [ - { - POSITION: [24, 8, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.hunterSecondary, g.hunterSecondary, g.predator]), - TYPE: "bullet" - } - }, - { - POSITION: [21, 12, 1, 0, 0, 0, 0.15], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.hunterSecondary, g.predator]), - TYPE: "bullet" - } - }, - { - POSITION: [18, 16, 1, 0, 0, 0, 0.3], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.predator]), - TYPE: "bullet" - } - } - ] -} -Class.xHunter = { - PARENT: "genericTank", - LABEL: "X-Hunter", - DANGER: 7, - BODY: { - SPEED: base.SPEED * 0.9, - FOV: base.FOV * 1.25 - }, - CONTROLLERS: [["zoom", { distance: 550 }]], - TOOLTIP: "Hold right click to zoom.", - GUNS: [ - { - POSITION: [24, 8, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.hunterSecondary]), - TYPE: "bullet" - } - }, - { - POSITION: [21, 12, 1, 0, 0, 0, 0.25], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter]), - TYPE: "bullet" - } - }, - { - POSITION: [5, 12, -1.2, 7, 0, 0, 0] - } - ] -} -Class.dual = { - PARENT: "genericTank", - LABEL: "Dual", - DANGER: 7, - BODY: { - FOV: 1.1 * base.FOV - }, - CONTROLLERS: ["zoom"], - TOOLTIP: "Hold right click to zoom.", - GUNS: [ - { - POSITION: [18, 7, 1, 0, 5.5, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.dual, g.lowPower]), - TYPE: "bullet", - LABEL: "Small" - } - }, - { - POSITION: [18, 7, 1, 0, -5.5, 0, .5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.dual, g.lowPower]), - TYPE: "bullet", - LABEL: "Small" - } - }, - { - POSITION: [16, 8.5, 1, 0, 5.5, 0, 0.25], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.dual]), - TYPE: "bullet" - } - }, - { - POSITION: [16, 8.5, 1, 0, -5.5, 0, .75], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.dual]), - TYPE: "bullet" - } - } - ] -} - -// Rifle upgrades -Class.musket = { - PARENT: "genericTank", - LABEL: "Musket", - DANGER: 7, - BODY: { - FOV: base.FOV * 1.225 - }, - GUNS: [ - { - POSITION: [16, 19, 1, 0, 0, 0, 0], - }, - { - POSITION: [18, 7, 1, 0, 4, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.rifle, g.twin]), - TYPE: "bullet" - } - }, - { - POSITION: [18, 7, 1, 0, -4, 0, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.rifle, g.twin]), - TYPE: "bullet" - } - } - ] -} -Class.crossbow = { - PARENT: "genericTank", - LABEL: "Crossbow", - DANGER: 7, - BODY: { - FOV: base.FOV * 1.225 - }, - GUNS: [ - { - POSITION: [12.5, 2.5, 1, 0, 3.5, 35, 1], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.rifle, g.crossbow, { recoil: 0.5 }]), - TYPE: "bullet" - } - }, - { - POSITION: [12.5, 2.5, 1, 0, -3.5, -35, 1], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.rifle, g.crossbow, { recoil: 0.5 }]), - TYPE: "bullet" - } - }, - { - POSITION: [15, 2.5, 1, 0, 3.5, 35/2, 2/3], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.rifle, g.crossbow, { recoil: 0.5 }]), - TYPE: "bullet" - } - }, - { - POSITION: [15, 2.5, 1, 0, -3.5, -35/2, 2/3], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.rifle, g.crossbow, { speed: 0.7, maxSpeed: 0.7 }, { recoil: 0.5 }]), - TYPE: "bullet" - } - }, - { - POSITION: [20, 3.5, 1, 0, 4, 0, 1/3], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.rifle, g.crossbow, { speed: 0.7, maxSpeed: 0.7 }, { recoil: 0.5 }]), - TYPE: "bullet" - } - }, - { - POSITION: [20, 3.5, 1, 0, -4, 0, 1/3], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.rifle, g.crossbow, { speed: 0.7, maxSpeed: 0.7 }, { recoil: 0.5 }]), - TYPE: "bullet" - } - }, - { - POSITION: [24, 7, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.rifle, g.crossbow, { speed: 0.7, maxSpeed: 0.7 }, { recoil: 0.5 }]), - TYPE: "bullet" - } - } - ] -} - -// Machine Gun upgrades -Class.minigun = { - PARENT: "genericTank", - LABEL: "Minigun", - DANGER: 6, - BODY: { - FOV: base.FOV * 1.2 - }, - GUNS: [ - { - POSITION: [21, 8, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.minigun]), - TYPE: "bullet" - } - }, - { - POSITION: [19, 8, 1, 0, 0, 0, 1/3], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.minigun]), - TYPE: "bullet" - } - }, - { - POSITION: [17, 8, 1, 0, 0, 0, 2/3], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.minigun]), - TYPE: "bullet" - } - } - ] -} -Class.gunner = { - PARENT: "genericTank", - LABEL: "Gunner", - DANGER: 6, - GUNS: [ - { - POSITION: [12, 3.5, 1, 0, 7.25, 0, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.gunner, { speed: 1.2 }]), - TYPE: "bullet" - } - }, - { - POSITION: [12, 3.5, 1, 0, -7.25, 0, 0.75], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.gunner, { speed: 1.2 }]), - TYPE: "bullet" - } - }, - { - POSITION: [16, 3.5, 1, 0, 3.75, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.gunner, { speed: 1.2 }]), - TYPE: "bullet" - } - }, - { - POSITION: [16, 3.5, 1, 0, -3.75, 0, 0.25], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.gunner, { speed: 1.2 }]), - TYPE: "bullet" - } - } - ] -} -Class.sprayer = { - PARENT: "genericTank", - LABEL: "Sprayer", - DANGER: 6, - GUNS: [ - { - POSITION: [23, 7, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.lowPower, g.pelleter, { recoil: 1.15 }]), - TYPE: "bullet" - } - }, - { - POSITION: [12, 10, 1.4, 8, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.machineGun]), - TYPE: "bullet" - } - } - ] -} - -// Minigun upgrades -Class.streamliner = { - PARENT: "genericTank", - LABEL: "Streamliner", - DANGER: 7, - BODY: { - FOV: 1.3, - }, - GUNS: [ - { - POSITION: [25, 8, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.streamliner]), - TYPE: "bullet", - }, - }, - { - POSITION: [23, 8, 1, 0, 0, 0, 0.2], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.streamliner]), - TYPE: "bullet", - }, - }, - { - POSITION: [21, 8, 1, 0, 0, 0, 0.4], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.streamliner]), - TYPE: "bullet", - }, - }, - { - POSITION: [19, 8, 1, 0, 0, 0, 0.6], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.streamliner]), - TYPE: "bullet", - }, - }, - { - POSITION: [17, 8, 1, 0, 0, 0, 0.8], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.streamliner]), - TYPE: "bullet", - }, - }, - ], -} -Class.barricade = { - PARENT: "genericTank", - DANGER: 7, - LABEL: "Barricade", - STAT_NAMES: statnames.trap, - BODY: { - FOV: 1.15, - }, - GUNS: [ - { - POSITION: [24, 8, 1, 0, 0, 0, 0], - }, - { - POSITION: [4, 8, 1.3, 22, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.minigun, { range: 0.5 }]), - TYPE: "trap", - STAT_CALCULATOR: gunCalcNames.trap, - }, - }, - { - POSITION: [4, 8, 1.3, 18, 0, 0, 1/3], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.minigun, { range: 0.5 }]), - TYPE: "trap", - STAT_CALCULATOR: gunCalcNames.trap, - }, - }, - { - POSITION: [4, 8, 1.3, 14, 0, 0, 2/3], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.minigun, { range: 0.5 }]), - TYPE: "trap", - STAT_CALCULATOR: gunCalcNames.trap, - }, - }, - ], -} - -// Gunner upgrades -Class.nailgun = { - PARENT: "genericTank", - LABEL: "Nailgun", - DANGER: 7, - BODY: { - FOV: base.FOV * 1.1, - SPEED: base.SPEED * 0.9, - }, - GUNS: [ - { - POSITION: [19, 2, 1, 0, -2.5, 0, 0.25], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.power, g.twin, g.nailgun]), - TYPE: "bullet", - }, - }, - { - POSITION: [19, 2, 1, 0, 2.5, 0, 0.75], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.power, g.twin, g.nailgun]), - TYPE: "bullet", - }, - }, - { - POSITION: [20, 2, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.power, g.twin, g.nailgun]), - TYPE: "bullet", - }, - }, - { - POSITION: [5.5, 7, -1.8, 6.5, 0, 0, 0], - }, - ], -} -Class.machineGunner = { - PARENT: "genericTank", - LABEL: "Machine Gunner", - DANGER: 7, - BODY: { - SPEED: 0.9 * base.SPEED, - }, - GUNS: [ - { - POSITION: [14, 3, 4, -3, 5, 0, 0.6], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.gunner, g.machineGunner]), - TYPE: "bullet", - }, - }, - { - POSITION: [14, 3, 4, -3, -5, 0, 0.8], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.gunner, g.machineGunner]), - TYPE: "bullet", - }, - }, - { - POSITION: [14, 3, 4, 0, 2.5, 0, 0.4], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.gunner, g.machineGunner]), - TYPE: "bullet", - }, - }, - { - POSITION: [14, 3, 4, 0, -2.5, 0, 0.2], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.gunner, g.machineGunner]), - TYPE: "bullet", - }, - }, - { - POSITION: [14, 3, 4, 3, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.gunner, g.machineGunner]), - TYPE: "bullet", - }, - }, - ], -} - -// Sprayer upgrades -Class.redistributor = { - PARENT: "genericTank", - LABEL: "Redistributor", - DANGER: 7, - GUNS: [ - { - POSITION: [26, 7, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.lowPower, g.machineGun, { recoil: 1.15 }]), - TYPE: "bullet", - }, - }, - { - POSITION: [23, 10, 1, 0, 0, 0, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.lowPower, g.machineGun, { recoil: 1.15 }]), - TYPE: "bullet", - }, - }, - { - POSITION: [12, 10, 1.4, 8, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.machineGun]), - TYPE: "bullet", - }, - }, - ], -} -Class.atomizer = { - PARENT: "genericTank", - LABEL: "Atomizer", - DANGER: 7, - GUNS: [ - { - POSITION: [5, 7.5, 1.3, 18.5, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.lowPower, g.machineGun, { recoil: 1.15 }, g.atomizer]), - TYPE: "bullet", - }, - }, - { - POSITION: [12, 10, 1.4, 8, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.machineGun]), - TYPE: "bullet", - }, - }, - ], -} -Class.focal = { - PARENT: "genericTank", - LABEL: "Focal", - DANGER: 7, - GUNS: [ - { - POSITION: [25, 7, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.lowPower, g.machineGun, { recoil: 1.15 }]), - TYPE: "bullet", - }, - }, - { - POSITION: [14, 10, 1.3, 8, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.focal]), - TYPE: "bullet", - }, - }, - ], -} - -// Flank Guard upgrades -Class.hexaTank = { - PARENT: "genericTank", - LABEL: "Hexa Tank", - DANGER: 6, - GUNS: weaponArray([ - { - POSITION: [18, 8, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.flankGuard]), - TYPE: "bullet" - } - }, - { - POSITION: [18, 8, 1, 0, 0, 180, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.flankGuard]), - TYPE: "bullet" - } - } - ], 3) -} -Class.triAngle = { - PARENT: "genericTank", - LABEL: "Tri-Angle", - BODY: { - HEALTH: 0.8 * base.HEALTH, - SHIELD: 0.8 * base.SHIELD, - DENSITY: 0.6 * base.DENSITY, - }, - DANGER: 6, - GUNS: [ - { - POSITION: [18, 8, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.triAngleFront, { recoil: 4 }]), - TYPE: "bullet", - LABEL: "Front", - }, - }, - { - POSITION: [16, 8, 1, 0, 0, 150, 0.1], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), - TYPE: "bullet", - LABEL: gunCalcNames.thruster, - }, - }, - { - POSITION: [16, 8, 1, 0, 0, 210, 0.1], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), - TYPE: "bullet", - LABEL: gunCalcNames.thruster, - }, - }, - ], -} -Class.auto3 = makeRadialAuto("autoTankGun", {isTurret: true, danger: 6, label: "Auto-3"}) - -// Hexa Tank upgrades -Class.octoTank = { - PARENT: "genericTank", - LABEL: "Octo Tank", - DANGER: 7, - GUNS: weaponArray([ - { - POSITION: [18, 8, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.flankGuard, g.spam]), - TYPE: "bullet" - } - }, - { - POSITION: [18, 8, 1, 0, 0, 45, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.flankGuard, g.spam]), - TYPE: "bullet" - } - } - ], 4) -} -Class.cyclone = { - PARENT: "genericTank", - LABEL: "Cyclone", - DANGER: 7, - GUNS: weaponArray([ - { - POSITION: [15, 3.5, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.gunner, g.cyclone]), - TYPE: "bullet" - } - }, - { - POSITION: [15, 3.5, 1, 0, 0, 30, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.gunner, g.cyclone]), - TYPE: "bullet" - } - }, - { - POSITION: [15, 3.5, 1, 0, 0, 60, 0.25], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.gunner, g.cyclone]), - TYPE: "bullet" - } - }, - { - POSITION: [15, 3.5, 1, 0, 0, 90, 0.75], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.gunner, g.cyclone]), - TYPE: "bullet" - } - } - ], 3) -} - -// Tri-Angle upgrades -Class.fighter = { - PARENT: "genericTank", - LABEL: "Fighter", - BODY: { - DENSITY: 0.6 * base.DENSITY, - }, - DANGER: 7, - GUNS: [ - { - POSITION: [18, 8, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.triAngleFront, { recoil: 4 }]), - TYPE: "bullet", - LABEL: "Front", - }, - }, - { - POSITION: [16, 8, 1, 0, -1, 90, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.triAngleFront]), - TYPE: "bullet", - LABEL: "Side", - }, - }, - { - POSITION: [16, 8, 1, 0, 1, -90, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.triAngleFront]), - TYPE: "bullet", - LABEL: "Side", - }, - }, - { - POSITION: [16, 8, 1, 0, 0, 150, 0.1], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), - TYPE: "bullet", - LABEL: gunCalcNames.thruster, - }, - }, - { - POSITION: [16, 8, 1, 0, 0, 210, 0.1], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), - TYPE: "bullet", - LABEL: gunCalcNames.thruster, - }, - }, - ], -} -Class.booster = { - PARENT: "genericTank", - LABEL: "Booster", - BODY: { - HEALTH: base.HEALTH * 0.4, - SHIELD: base.SHIELD * 0.4, - DENSITY: base.DENSITY * 0.3 - }, - DANGER: 7, - GUNS: [ - { - POSITION: [18, 8, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.triAngleFront, { recoil: 4 }]), - TYPE: "bullet", - LABEL: "Front" - } - }, - { - POSITION: [14, 8, 1, 0, -1, 140, 0.6], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), - TYPE: "bullet", - LABEL: gunCalcNames.thruster - } - }, - { - POSITION: [14, 8, 1, 0, 1, -140, 0.6], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), - TYPE: "bullet", - LABEL: gunCalcNames.thruster - } - }, - { - POSITION: [16, 8, 1, 0, 0, 150, 0.1], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), - TYPE: "bullet", - LABEL: gunCalcNames.thruster - } - }, - { - POSITION: [16, 8, 1, 0, 0, -150, 0.1], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), - TYPE: "bullet", - LABEL: gunCalcNames.thruster - } - } - ] -} -Class.surfer = { - PARENT: "genericTank", - LABEL: "Surfer", - BODY: { - DENSITY: 0.6 * base.DENSITY, - }, - DANGER: 7, - GUNS: [ - { - POSITION: [18, 8, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.triAngleFront]), - TYPE: "bullet", - LABEL: "Front", - }, - }, - { - POSITION: [7, 7.5, 0.6, 7, -1, 90, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm]), - TYPE: "autoswarm", - STAT_CALCULATOR: gunCalcNames.swarm, - }, - }, - { - POSITION: [7, 7.5, 0.6, 7, 1, -90, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm]), - TYPE: "autoswarm", - STAT_CALCULATOR: gunCalcNames.swarm, - }, - }, - { - POSITION: [16, 8, 1, 0, 0, 150, 0.1], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), - TYPE: "bullet", - LABEL: gunCalcNames.thruster, - }, - }, - { - POSITION: [16, 8, 1, 0, 0, 210, 0.1], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), - TYPE: "bullet", - LABEL: gunCalcNames.thruster, - }, - }, - ], -} - -// Auto-3 upgrades -Class.auto5 = makeRadialAuto("autoTankGun", {isTurret: true, danger: 7, label: "Auto-5", count: 5}) -Class.mega3 = makeRadialAuto("megaAutoTankGun", {isTurret: true, danger: 7, size: 14, label: "Mega-5", body: {SPEED: 0.95 * base.SPEED}}) -Class.auto4 = makeRadialAuto("auto4gun", {isTurret: true, danger: 7, size: 13, x: 6, angle: 45, label: "Auto-4", count: 4}) -Class.banshee = makeRadialAuto("bansheegun", {isTurret: true, danger: 7, size: 10, arc: 80, label: "Banshee", body: {SPEED: 0.8 * base.SPEED, FOV: 1.1 * base.FOV}}) -Class.banshee.GUNS = weaponArray({ - POSITION: [6, 11, 1.2, 8, 0, 60, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.overseer]), - TYPE: "drone", - AUTOFIRE: true, - SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.drone, - WAIT_TO_CYCLE: true, - MAX_CHILDREN: 2, - }, -}, 3) - -// Director upgrades -Class.overseer = { - PARENT: "genericTank", - LABEL: "Overseer", - DANGER: 6, - STAT_NAMES: statnames.drone, - BODY: { - SPEED: 0.9 * base.SPEED, - FOV: 1.1 * base.FOV, - }, - MAX_CHILDREN: 8, - GUNS: weaponArray({ - POSITION: [6, 12, 1.2, 8, 0, 90, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.overseer]), - TYPE: "drone", - AUTOFIRE: true, - SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.drone, - WAIT_TO_CYCLE: true - } - }, 2) -} -Class.cruiser = { - PARENT: "genericTank", - LABEL: "Cruiser", - DANGER: 6, - FACING_TYPE: "locksFacing", - STAT_NAMES: statnames.swarm, - BODY: { - FOV: 1.2 * base.FOV, - }, - GUNS: [ - { - POSITION: [7, 7.5, 0.6, 7, 4, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm]), - TYPE: "swarm", - STAT_CALCULATOR: gunCalcNames.swarm, - }, - }, - { - POSITION: [7, 7.5, 0.6, 7, -4, 0, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm]), - TYPE: "swarm", - STAT_CALCULATOR: gunCalcNames.swarm, - }, - }, - ], -} -Class.underseer = { - PARENT: "genericTank", - LABEL: "Underseer", - DANGER: 6, - STAT_NAMES: statnames.drone, - BODY: { - SPEED: 0.9 * base.SPEED, - }, - SHAPE: 4, - MAX_CHILDREN: 14, - GUNS: weaponArray({ - POSITION: [5.25, 12, 1.2, 8, 0, 90, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.sunchip]), - TYPE: "sunchip", - AUTOFIRE: true, - SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.necro, - } - }, 2) -} -Class.spawner = { - PARENT: "genericTank", - LABEL: "Spawner", - DANGER: 6, - STAT_NAMES: statnames.drone, - BODY: { - SPEED: base.SPEED * 0.8, - FOV: 1.1, - }, - GUNS: [ - { - POSITION: [4.5, 10, 1, 10.5, 0, 0, 0], - }, - { - POSITION: [1, 12, 1, 15, 0, 0, 0], - PROPERTIES: { - MAX_CHILDREN: 4, - SHOOT_SETTINGS: combineStats([g.factory, g.babyfactory]), - TYPE: "minion", - STAT_CALCULATOR: gunCalcNames.drone, - AUTOFIRE: true, - SYNCS_SKILLS: true, - }, - }, - { - POSITION: [11.5, 12, 1, 0, 0, 0, 0], - }, - ], -} -Class.manager = { - PARENT: "genericTank", - LABEL: "Manager", - DANGER: 7, - STAT_NAMES: statnames.drone, - BODY: { - SPEED: 0.85 * base.SPEED, - FOV: 1.1 * base.FOV, - }, - INVISIBLE: [0.08, 0.03], - TOOLTIP: "Stay still to turn invisible.", - MAX_CHILDREN: 8, - GUNS: [ - { - POSITION: [6, 12, 1.2, 8, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.overseer, { reload: 0.5 }]), - TYPE: "drone", - AUTOFIRE: true, - SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.drone, - }, - }, - ], -} -Class.bigCheese = { - PARENT: "genericTank", - LABEL: "Big Cheese", - STAT_NAMES: statnames.drone, - DANGER: 7, - BODY: { - FOV: base.FOV * 1.1, - }, - GUNS: [ - { - POSITION: [16, 16, 1.4, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.bigCheese]), - TYPE: "drone", - AUTOFIRE: true, - SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.drone, - MAX_CHILDREN: 1, - }, - }, - ], -} - -// Overseer upgrades -Class.overlord = { - PARENT: "genericTank", - LABEL: "Overlord", - DANGER: 7, - STAT_NAMES: statnames.drone, - BODY: { - SPEED: 0.8 * base.SPEED, - FOV: 1.1 * base.FOV, - }, - MAX_CHILDREN: 8, - GUNS: weaponArray({ - POSITION: [6, 12, 1.2, 8, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.overseer]), - TYPE: "drone", - AUTOFIRE: true, - SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.drone, - WAIT_TO_CYCLE: true - } - }, 4) -} -Class.overdrive = { - PARENT: "genericTank", - LABEL: "Overdrive", - DANGER: 7, - STAT_NAMES: statnames.drone, - BODY: { - SPEED: 0.9 * base.SPEED, - FOV: 1.1 * base.FOV, - }, - TURRETS: [ - { - POSITION: [9, 0, 0, 0, 360, 1], - TYPE: "overdriveDeco", - }, - ], - GUNS: weaponArray({ - POSITION: [6, 12, 1.2, 8, 0, 90, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.overseer]), - TYPE: "turretedDrone", - AUTOFIRE: true, - SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.drone, - WAIT_TO_CYCLE: true, - MAX_CHILDREN: 4 - } - }, 2) -} -Class.commander = { - PARENT: "genericTank", - LABEL: "Commander", - STAT_NAMES: statnames.drone, - DANGER: 7, - BODY: { - FOV: base.FOV * 1.15, - }, - GUNS: weaponArray([ - { - POSITION: [8, 11, 1.3, 6, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone]), - TYPE: "drone", - AUTOFIRE: true, - SYNCS_SKILLS: true, - MAX_CHILDREN: 2, - STAT_CALCULATOR: gunCalcNames.drone, - }, - }, - { - POSITION: [7, 7.5, 0.6, 7, 0, 180, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm, g.commander]), - TYPE: "swarm", - STAT_CALCULATOR: gunCalcNames.swarm, - }, - } - ], 3) -} - -// Cruiser upgrades -Class.carrier = { - PARENT: "genericTank", - LABEL: "Carrier", - DANGER: 7, - STAT_NAMES: statnames.swarm, - FACING_TYPE: "locksFacing", - BODY: { - FOV: base.FOV * 1.2, - }, - GUNS: [ - { - POSITION: [7, 8, 0.6, 7, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm, g.battleship, g.carrier]), - TYPE: "swarm", - STAT_CALCULATOR: gunCalcNames.swarm, - }, - }, - { - POSITION: [7, 8, 0.6, 7, 2, 30, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm, g.battleship, g.carrier]), - TYPE: "swarm", - STAT_CALCULATOR: gunCalcNames.swarm, - }, - }, - { - POSITION: [7, 8, 0.6, 7, -2, -30, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm, g.battleship, g.carrier]), - TYPE: "swarm", - STAT_CALCULATOR: gunCalcNames.swarm, - }, - }, - ], -} -Class.battleship = { - PARENT: "genericTank", - LABEL: "Battleship", - DANGER: 7, - STAT_NAMES: statnames.swarm, - FACING_TYPE: "locksFacing", - BODY: { - FOV: 1.2 * base.FOV - }, - GUNS: [ - { - POSITION: [7, 7.5, 0.6, 7, 4, 90, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm, g.battleship]), - TYPE: "swarm", - STAT_CALCULATOR: gunCalcNames.swarm, - LABEL: "Guided" - } - }, - { - POSITION: [7, 7.5, 0.6, 7, -4, 90, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm]), - TYPE: "autoswarm", - STAT_CALCULATOR: gunCalcNames.swarm, - LABEL: "Autonomous" - } - }, - { - POSITION: [7, 7.5, 0.6, 7, 4, 270, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm]), - TYPE: "autoswarm", - STAT_CALCULATOR: gunCalcNames.swarm, - LABEL: "Autonomous" - } - }, - { - POSITION: [7, 7.5, 0.6, 7, -4, 270, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm, g.battleship]), - TYPE: "swarm", - STAT_CALCULATOR: gunCalcNames.swarm, - LABEL: "Guided" - } - } - ] -} -Class.fortress = { - PARENT: "genericTank", - LABEL: "Fortress", - DANGER: 7, - STAT_NAMES: statnames.mixed, - BODY: { - SPEED: 0.8 * base.SPEED, - FOV: 1.2 * base.FOV, - }, - GUNS: [ - { - POSITION: [7, 7.5, 0.6, 7, 0, 60, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm]), - TYPE: "swarm", - STAT_CALCULATOR: gunCalcNames.swarm, - }, - }, - { - POSITION: [7, 7.5, 0.6, 7, 0, 180, 1 / 3], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm]), - TYPE: "swarm", - STAT_CALCULATOR: gunCalcNames.swarm, - }, - }, - { - POSITION: [7, 7.5, 0.6, 7, 0, 300, 2 / 3], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm]), - TYPE: "swarm", - STAT_CALCULATOR: gunCalcNames.swarm, - }, - }, - ...weaponArray([ - { - POSITION: [14, 9, 1, 0, 0, 0, 0], - }, - { - POSITION: [4, 9, 1.5, 14, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, { range: 0.5, speed: 0.7, maxSpeed: 0.7 }]), - TYPE: "trap", - STAT_CALCULATOR: gunCalcNames.trap, - }, - } - ], 3) - ], -} - -// Underseer upgrades -Class.necromancer = { - PARENT: "genericTank", - LABEL: "Necromancer", - DANGER: 7, - STAT_NAMES: statnames.necro, - BODY: { - SPEED: 0.8 * base.SPEED, - }, - SHAPE: 4, - MAX_CHILDREN: 14, - GUNS: [ - { - POSITION: [5.25, 12, 1.2, 8, 0, 90, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.sunchip]), - TYPE: "sunchip", - AUTOFIRE: true, - SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.necro, - }, - }, - { - POSITION: [5.25, 12, 1.2, 8, 0, 270, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.sunchip]), - TYPE: "sunchip", - AUTOFIRE: true, - SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.necro, - }, - }, - { - POSITION: [5.25, 12, 1.2, 8, 0, 0, 0.25], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.sunchip]), - TYPE: "sunchip", - AUTOFIRE: true, - SYNCS_SKILLS: true, - MAX_CHILDREN: 4, - STAT_CALCULATOR: gunCalcNames.necro, - }, - }, - { - POSITION: [5.25, 12, 1.2, 8, 0, 180, 0.75], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.sunchip]), - TYPE: "sunchip", - AUTOFIRE: true, - SYNCS_SKILLS: true, - MAX_CHILDREN: 4, - STAT_CALCULATOR: gunCalcNames.necro, - }, - }, - ], -} -Class.maleficitor = { - PARENT: "genericTank", - LABEL: "Maleficitor", - DANGER: 7, - TOOLTIP: "Press R and wait to turn your drones invisible.", - STAT_NAMES: statnames.necro, - BODY: { - SPEED: base.SPEED * 0.85, - }, - SHAPE: 4, - MAX_CHILDREN: 20, - GUNS: [ - { - POSITION: [5.25, 12, 1.2, 8, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.sunchip, g.maleficitor]), - TYPE: [ - "sunchip", - { - INVISIBLE: [0.06, 0.03], - }, - ], - AUTOFIRE: true, - SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.necro, - }, - }, - ], -} -Class.infestor = { - PARENT: "genericTank", - LABEL: "Infestor", - DANGER: 7, - STAT_NAMES: statnames.drone, - BODY: { - SPEED: base.SPEED * 0.9, - }, - MAX_CHILDREN: 20, - GUNS: weaponArray([ - { - POSITION: [7.25, 6, 1.2, 6, -5, 90, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.sunchip]), - TYPE: "eggchip", - AUTOFIRE: true, - SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.necro - } - }, - { - POSITION: [7.25, 6, 1.2, 6, 5, 90, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.drone, g.sunchip]), - TYPE: "eggchip", - AUTOFIRE: true, - SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.necro - } - } - ], 2) -} - -// Spawner upgrades -Class.factory = { - PARENT: "genericTank", - LABEL: "Factory", - DANGER: 7, - STAT_NAMES: statnames.drone, - BODY: { - SPEED: base.SPEED * 0.8, - FOV: 1.1, - }, - MAX_CHILDREN: 6, - GUNS: [ - { - POSITION: [5, 11, 1, 10.5, 0, 0, 0], - }, - { - POSITION: [2, 14, 1, 15.5, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.factory]), - TYPE: "minion", - STAT_CALCULATOR: gunCalcNames.drone, - AUTOFIRE: true, - SYNCS_SKILLS: true, - }, - }, - { - POSITION: [12, 14, 1, 0, 0, 0, 0], - }, - ], -} - -// Pounder upgrades -Class.destroyer = { - PARENT: "genericTank", - LABEL: "Destroyer", - DANGER: 6, - GUNS: [ - { - POSITION: [21, 14, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.destroyer]), - TYPE: "bullet", - }, - }, - ], -} -Class.artillery = { - PARENT: "genericTank", - LABEL: "Artillery", - DANGER: 6, - GUNS: [ - { - POSITION: [17, 3, 1, 0, -6, -7, 0.25], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery]), - TYPE: "bullet", - LABEL: "Secondary", - }, - }, - { - POSITION: [17, 3, 1, 0, 6, 7, 0.75], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery]), - TYPE: "bullet", - LABEL: "Secondary", - }, - }, - { - POSITION: [19, 12, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.artillery]), - TYPE: "bullet", - LABEL: "Heavy", - }, - }, - ], -} -Class.launcher = { - PARENT: "genericTank", - LABEL: "Launcher", - DANGER: 6, - BODY: { - FOV: base.FOV * 1.1, - }, - GUNS: [ - { - POSITION: [10, 9, 1, 9, 0, 0, 0], - }, - { - POSITION: [17, 13, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.launcher]), - TYPE: "minimissile", - STAT_CALCULATOR: gunCalcNames.sustained, - }, - }, - ], -} -Class.shotgun = { - PARENT: "genericTank", - LABEL: "Shotgun", - DANGER: 7, - GUNS: [ - { - POSITION: [4, 3, 1, 11, -3, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.shotgun]), - TYPE: "bullet", - }, - }, - { - POSITION: [4, 3, 1, 11, 3, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.shotgun]), - TYPE: "bullet", - }, - }, - { - POSITION: [4, 4, 1, 13, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.shotgun]), - TYPE: "casing", - }, - }, - { - POSITION: [1, 4, 1, 12, -1, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.shotgun]), - TYPE: "casing", - }, - }, - { - POSITION: [1, 4, 1, 11, 1, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.shotgun]), - TYPE: "casing", - }, - }, - { - POSITION: [1, 3, 1, 13, -1, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.shotgun]), - TYPE: "bullet", - }, - }, - { - POSITION: [1, 3, 1, 13, 1, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.shotgun]), - TYPE: "bullet", - }, - }, - { - POSITION: [1, 2, 1, 13, 2, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.shotgun]), - TYPE: "casing", - }, - }, - { - POSITION: [1, 2, 1, 13, -2, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.shotgun]), - TYPE: "casing", - }, - }, - { - POSITION: [15, 14, 1, 6, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.shotgun, g.fake]), - TYPE: "casing", - }, - }, - { - POSITION: [8, 14, -1.3, 4, 0, 0, 0], - }, - ], -} - -// Destroyer upgrades -Class.annihilator = { - PARENT: "genericTank", - LABEL: "Annihilator", - DANGER: 7, - GUNS: [ - { - POSITION: [20.5, 19.5, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.destroyer, g.annihilator]), - TYPE: "bullet", - }, - }, - ], -} - -// Artillery upgrades -Class.mortar = { - PARENT: "genericTank", - LABEL: "Mortar", - DANGER: 7, - GUNS: [ - { - POSITION: [13, 3, 1, 0, -8, -7, 0.6], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery, g.twin]), - TYPE: "bullet", - LABEL: "Secondary", - }, - }, - { - POSITION: [13, 3, 1, 0, 8, 7, 0.8], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery, g.twin]), - TYPE: "bullet", - LABEL: "Secondary", - }, - }, - { - POSITION: [17, 3, 1, 0, -6, -7, 0.2], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery, g.twin]), - TYPE: "bullet", - LABEL: "Secondary", - }, - }, - { - POSITION: [17, 3, 1, 0, 6, 7, 0.4], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery, g.twin]), - TYPE: "bullet", - LABEL: "Secondary", - }, - }, - { - POSITION: [19, 12, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.artillery]), - TYPE: "bullet", - LABEL: "Heavy", - }, - }, - ], -} -Class.ordnance = { - PARENT: "genericTank", - LABEL: "Ordnance", - DANGER: 7, - BODY: { - SPEED: base.SPEED * 0.9, - FOV: base.FOV * 1.25, - }, - CONTROLLERS: ["zoom"], - TOOLTIP: "Hold right click to zoom.", - GUNS: [ - { - POSITION: [17, 3, 1, 0, -5.75, -6, 0.25], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery]), - TYPE: "bullet", - LABEL: "Secondary", - }, - }, - { - POSITION: [17, 3, 1, 0, 5.75, 6, 0.75], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery]), - TYPE: "bullet", - LABEL: "Secondary", - }, - }, - { - POSITION: [24, 8, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.hunterSecondary]), - TYPE: "bullet", - }, - }, - { - POSITION: [21, 11, 1, 0, 0, 0, 0.25], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter]), - TYPE: "bullet", - }, - }, - ], -} -Class.beekeeper = { - PARENT: "genericTank", - LABEL: "Beekeeper", - DANGER: 7, - GUNS: [ - { - POSITION: [14, 3, 1, 0, -6, -7, 0.25], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm, g.bee]), - TYPE: ["bee", { INDEPENDENT: true }], - SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.drone, - WAIT_TO_CYCLE: true, - LABEL: "Secondary", - }, - }, - { - POSITION: [14, 3, 1, 0, 6, 7, 0.75], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm, g.bee]), - TYPE: ["bee", { INDEPENDENT: true }], - SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.drone, - WAIT_TO_CYCLE: true, - LABEL: "Secondary", - }, - }, - { - POSITION: [19, 12, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.artillery]), - TYPE: "bullet", - LABEL: "Heavy", - }, - }, - ], -} -Class.fieldGun = { - PARENT: "genericTank", - LABEL: "Field Gun", - BODY: { - FOV: base.FOV * 1.1, - }, - DANGER: 7, - GUNS: [ - { - POSITION: [15, 3, 1, 0, -6, -7, 0.25], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery]), - TYPE: "bullet", - LABEL: "Secondary", - }, - }, - { - POSITION: [15, 3, 1, 0, 6, 7, 0.75], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery]), - TYPE: "bullet", - LABEL: "Secondary", - }, - }, - { - /*** LENGTH WIDTH ASPECT X Y ANGLE DELAY */ - POSITION: [10, 9, 1, 9, 0, 0, 0], - }, - { - POSITION: [17, 13, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.artillery, g.artillery]), - TYPE: "minimissile", - STAT_CALCULATOR: gunCalcNames.sustained, - }, - }, - ], -} - -// Launcher upgrades -Class.skimmer = { - PARENT: "genericTank", - LABEL: "Skimmer", - DANGER: 7, - BODY: { - FOV: 1.15 * base.FOV, - }, - GUNS: [ - { - POSITION: [10, 14, -0.5, 9, 0, 0, 0], - }, - { - POSITION: [17, 15, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.artillery, g.artillery, g.skimmer]), - TYPE: "missile", - STAT_CALCULATOR: gunCalcNames.sustained, - }, - }, - ], -} -Class.twister = { - PARENT: "genericTank", - LABEL: "Twister", - TOOLTIP: "Hold right click to reverse missile rotation.", - DANGER: 7, - BODY: { - FOV: 1.1 * base.FOV, - }, - GUNS: [ - { - POSITION: [10, 13, -0.5, 9, 0, 0, 0], - }, - { - POSITION: [17, 14, -1.4, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.artillery, g.artillery, g.skimmer, { reload: 4/3 }]), - TYPE: "spinmissile", - STAT_CALCULATOR: gunCalcNames.sustained, - }, - }, - ], -} -Class.swarmer = { - PARENT: "genericTank", - DANGER: 7, - LABEL: "Swarmer", - GUNS: [ - { - POSITION: [15, 14, -1.2, 5, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.destroyer, g.hive]), - TYPE: "hive", - }, - }, - { - POSITION: [15, 12, 1, 5, 0, 0, 0], - }, - ], -} -Class.rocketeer = { - PARENT: "genericTank", - LABEL: "Rocketeer", - BODY: { - FOV: 1.15 * base.FOV, - }, - DANGER: 7, - GUNS: [ - { - POSITION: [10, 12.5, -0.7, 10, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.launcher, g.rocketeer]), - TYPE: "rocketeerMissile", - STAT_CALCULATOR: gunCalcNames.sustained, - }, - }, - { - POSITION: [17, 18, 0.65, 0, 0, 0, 0], - }, - ], -} - -// Trapper upgrades -Class.builder = { - PARENT: "genericTank", - LABEL: "Builder", - DANGER: 6, - STAT_NAMES: statnames.trap, - BODY: { - SPEED: 0.8 * base.SPEED, - FOV: 1.15 * base.FOV - }, - GUNS: [ - { - POSITION: [18, 12, 1, 0, 0, 0, 0], - }, - { - POSITION: [2, 12, 1.1, 18, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.setTrap]), - TYPE: "setTrap", - STAT_CALCULATOR: gunCalcNames.block - } - } - ] -} -Class.triTrapper = { - PARENT: "genericTank", - LABEL: "Tri-Trapper", - DANGER: 6, - STAT_NAMES: statnames.trap, - GUNS: weaponArray([ - { - POSITION: [15, 7, 1, 0, 0, 0, 0], - }, - { - POSITION: [3, 7, 1.7, 15, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.flankGuard]), - TYPE: "trap", - STAT_CALCULATOR: gunCalcNames.trap - } - } - ], 3) -} -Class.trapGuard = makeGuard({ - PARENT: "genericTank", - LABEL: "Trap", - STAT_NAMES: statnames.mixed, - GUNS: [ - { - POSITION: [20, 8, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.flankGuard]), - TYPE: "bullet" - } - } - ] -}) - -// Builder upgrades -Class.construct = { // it's "construct" and not "constructor" because "constructor" breaks things - PARENT: "genericTank", - LABEL: "Constructor", - STAT_NAMES: statnames.trap, - DANGER: 7, - BODY: { - SPEED: 0.7 * base.SPEED, - FOV: 1.15 * base.FOV - }, - GUNS: [ - { - POSITION: [18, 18, 1, 0, 0, 0, 0], - }, - { - POSITION: [2, 18, 1.2, 18, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.setTrap, g.construct]), - TYPE: "setTrap", - STAT_CALCULATOR: gunCalcNames.block - } - } - ] -} -Class.engineer = { - PARENT: "genericTank", - DANGER: 7, - LABEL: "Engineer", - STAT_NAMES: statnames.trap, - BODY: { - SPEED: 0.75 * base.SPEED, - FOV: 1.15 * base.FOV, - }, - GUNS: [ - { - POSITION: [5, 11, 1, 10.5, 0, 0, 0], - }, - { - POSITION: [3, 14, 1, 15.5, 0, 0, 0], - }, - { - POSITION: [2, 14, 1.3, 18, 0, 0, 0], - PROPERTIES: { - MAX_CHILDREN: 6, - SHOOT_SETTINGS: combineStats([g.trap, g.setTrap]), - TYPE: "pillbox", - SYNCS_SKILLS: true, - DESTROY_OLDEST_CHILD: true, - STAT_CALCULATOR: gunCalcNames.block - }, - }, - { - POSITION: [4, 14, 1, 8, 0, 0, 0], - }, - ], -} -Class.boomer = { - PARENT: "genericTank", - DANGER: 7, - LABEL: "Boomer", - STAT_NAMES: statnames.trap, - FACING_TYPE: "locksFacing", - BODY: { - SPEED: base.SPEED * 0.8, - FOV: base.FOV * 1.15, - }, - GUNS: [ - { - POSITION: [5, 10, 1, 14, 0, 0, 0], - }, - { - POSITION: [6, 10, -1.5, 7, 0, 0, 0], - }, - { - POSITION: [2, 10, 1.3, 18, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.setTrap, g.boomerang]), - TYPE: "boomerang", - STAT_CALCULATOR: gunCalcNames.block - }, - }, - ], -} -Class.assembler = { - PARENT: "genericTank", - DANGER: 7, - LABEL: 'Assembler', - STAT_NAMES: statnames.trap, - BODY: { - SPEED: 0.8 * base.SPEED, - FOV: 1.15 * base.FOV, - }, - GUNS: [ - { - POSITION: [18, 12, 1, 0, 0, 0, 0], - }, - { - POSITION: [2, 12, 1.1, 18, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.setTrap]), - TYPE: 'assemblerTrap', - MAX_CHILDREN: 8, - STAT_CALCULATOR: gunCalcNames.block, - } - } - ], - TURRETS: [ - { - /** SIZE X Y ANGLE ARC */ - POSITION: [2.5, 14, 0, 0, 360, 1], - TYPE: 'assemblerDot' - } - ] -} - -// Tri-Trapper upgrades -Class.hexaTrapper = makeAuto({ - PARENT: "genericTank", - LABEL: "Hexa-Trapper", - DANGER: 7, - BODY: { - SPEED: 0.8 * base.SPEED, - }, - STAT_NAMES: statnames.trap, - HAS_NO_RECOIL: true, - GUNS: weaponArray([ - { - POSITION: [15, 7, 1, 0, 0, 0, 0], - }, - { - POSITION: [3, 7, 1.7, 15, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.hexaTrapper]), - TYPE: "trap", - STAT_CALCULATOR: gunCalcNames.trap, - }, - }, - { - POSITION: [15, 7, 1, 0, 0, 180, 0.5], - }, - { - POSITION: [3, 7, 1.7, 15, 0, 180, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.hexaTrapper]), - TYPE: "trap", - STAT_CALCULATOR: gunCalcNames.trap, - }, - }, - ], 3), -}) -Class.septaTrapper = { - PARENT: "genericTank", - LABEL: "Septa-Trapper", - DANGER: 7, - BODY: { - SPEED: base.SPEED * 0.8, - }, - STAT_NAMES: statnames.trap, - HAS_NO_RECOIL: true, - GUNS: [ - { - POSITION: [15, 7, 1, 0, 0, 0, 0], - }, - { - POSITION: [3, 7, 1.7, 15, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.hexaTrapper]), - TYPE: "trap", - STAT_CALCULATOR: gunCalcNames.trap, - }, - }, - { - POSITION: [15, 7, 1, 0, 0, 360 / 7, 0], - }, - { - POSITION: [3, 7, 1.7, 15, 0, 360 / 7, 1 / 3], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.hexaTrapper]), - TYPE: "trap", - STAT_CALCULATOR: gunCalcNames.trap, - }, - }, - { - POSITION: [15, 7, 1, 0, 0, -360 / 7, 0], - }, - { - POSITION: [3, 7, 1.7, 15, 0, -360 / 7, 1 / 3], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.hexaTrapper]), - TYPE: "trap", - STAT_CALCULATOR: gunCalcNames.trap, - }, - }, - { - POSITION: [15, 7, 1, 0, 0, 360 / 7 * 2, 0], - }, - { - POSITION: [3, 7, 1.7, 15, 0, 360 / 7 * 2, 2 / 3], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.hexaTrapper]), - TYPE: "trap", - STAT_CALCULATOR: gunCalcNames.trap, - }, - }, - { - POSITION: [15, 7, 1, 0, 0, -360 / 7 * 2, 0], - }, - { - POSITION: [3, 7, 1.7, 15, 0, -360 / 7 * 2, 2 / 3], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.hexaTrapper]), - TYPE: "trap", - STAT_CALCULATOR: gunCalcNames.trap, - }, - }, - { - POSITION: [15, 7, 1, 0, 0, 360 / 7 * 3, 0], - }, - { - POSITION: [3, 7, 1.7, 15, 0, 360 / 7 * 3, 1], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.hexaTrapper]), - TYPE: "trap", - STAT_CALCULATOR: gunCalcNames.trap, - }, - }, - { - POSITION: [15, 7, 1, 0, 0, -360 / 7 * 3, 0], - }, - { - POSITION: [3, 7, 1.7, 15, 0, -360 / 7 * 3, 1], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.hexaTrapper]), - TYPE: "trap", - STAT_CALCULATOR: gunCalcNames.trap, - }, - }, - ], -} -Class.architect = makeRadialAuto("architectGun", {isTurret: true, danger: 7, size: 12, label: "Architect", body: {SPEED: 1.1 * base.SPEED}}) - -// Trap Guard upgrades -Class.bushwhacker = makeGuard("sniper", "Bushwhacker") -Class.gunnerTrapper = { - PARENT: "genericTank", - LABEL: "Gunner Trapper", - DANGER: 7, - STAT_NAMES: statnames.mixed, - BODY: { - FOV: 1.25 * base.FOV, - }, - GUNS: [ - { - POSITION: [19, 2, 1, 0, -2.5, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.power, g.twin, { recoil: 4 }, { recoil: 1.8 }]), - TYPE: "bullet", - }, - }, - { - POSITION: [19, 2, 1, 0, 2.5, 0, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.power, g.twin, { recoil: 4 }, { recoil: 1.8 }]), - TYPE: "bullet", - }, - }, - { - POSITION: [12, 11, 1, 0, 0, 0, 0], - }, - { - POSITION: [13, 11, 1, 0, 0, 180, 0], - }, - { - POSITION: [4, 11, 1.7, 13, 0, 180, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, { speed: 1.2 }, { recoil: 0.5 }]), - TYPE: "trap", - STAT_CALCULATOR: gunCalcNames.trap, - }, - }, - ], -} -Class.bomber = { - PARENT: "genericTank", - LABEL: "Bomber", - BODY: { - DENSITY: base.DENSITY * 0.6, - }, - DANGER: 7, - GUNS: [ - { - POSITION: [20, 8, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.triAngleFront]), - TYPE: "bullet", - LABEL: "Front", - }, - }, - { - POSITION: [18, 8, 1, 0, 0, 130, 0.1], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle]), - TYPE: "bullet", - LABEL: "Wing", - }, - }, - { - POSITION: [18, 8, 1, 0, 0, 230, 0.1], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle]), - TYPE: "bullet", - LABEL: "Wing", - }, - }, - { - POSITION: [13, 8, 1, 0, 0, 180, 0], - }, - { - POSITION: [4, 8, 1.7, 13, 0, 180, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap]), - TYPE: "trap", - STAT_CALCULATOR: gunCalcNames.trap, - }, - }, - ], -} -Class.conqueror = { - PARENT: "genericTank", - DANGER: 7, - LABEL: "Conqueror", - STAT_NAMES: statnames.mixed, - BODY: { - SPEED: 0.8 * base.SPEED, - }, - REVERSE_TARGET_WITH_TANK: true, - GUNS: [ - { - POSITION: [21, 14, 1, 0, 0, 180, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.destroyer]), - TYPE: "bullet", - }, - }, - { - POSITION: [18, 12, 1, 0, 0, 0, 0], - }, - { - POSITION: [2, 12, 1.1, 18, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.setTrap]), - TYPE: "setTrap", - STAT_CALCULATOR: gunCalcNames.block - }, - }, - ], -} -Class.bulwark = { - PARENT: "genericTank", - LABEL: "Bulwark", - STAT_NAMES: statnames.mixed, - DANGER: 7, - GUNS: [ - { - POSITION: [20, 8, 1, 0, 5.5, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.flankGuard, g.twin]), - TYPE: "bullet", - }, - }, - { - POSITION: [20, 8, 1, 0, -5.5, 0, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.flankGuard, g.twin]), - TYPE: "bullet", - }, - }, - { - POSITION: [14, 8, 1, 0, 5.5, 185, 0], - }, - { - POSITION: [3, 9, 1.5, 14, 5.5, 185, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.twin]), - TYPE: "trap", - STAT_CALCULATOR: gunCalcNames.trap, - }, - }, - { - POSITION: [14, 8, 1, 0, -5.5, 175, 0], - }, - { - POSITION: [3, 9, 1.5, 14, -5.5, 175, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.twin]), - TYPE: "trap", - STAT_CALCULATOR: gunCalcNames.trap, - }, - }, - ], -} - -// Desmos upgrades -Class.helix = { - PARENT: "genericTank", - LABEL: "Helix", - DANGER: 6, - STAT_NAMES: statnames.desmos, - GUNS: [ - { - POSITION: [20, 8, 0.75, 0, -5, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.desmos]), - TYPE: ["bullet", {MOTION_TYPE: ["desmos", {invert: false}]}] - }, - }, - { - POSITION: [20, 8, 0.75, 0, 5, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.desmos]), - TYPE: ["bullet", {MOTION_TYPE: ["desmos", {invert: true}]}] - }, - }, - { - POSITION: [3.625, 7.5, 2.75, 5.75, -6.75, 90, 0], - }, - { - POSITION: [3.625, 7.5, 2.75, 5.75, 6.75, -90, 0], - }, - { - POSITION: [6, 8, 0.25, 10.5, 0, 0, 0], - }, - ], -} -Class.sidewinder = { - PARENT: "genericTank", - LABEL: "Sidewinder", - DANGER: 6, - STAT_NAMES: statnames.desmos, - UPGRADE_TOOLTIP: "[DEV NOTE] This tank does not function as intended yet!", - GUNS: [ - { - POSITION: [10, 8.5, 1.4, 7, 0, 0, 0] - }, - { - POSITION: [20, 10, 0.8, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.desmos]), - TYPE: ["bullet", {MOTION_TYPE: "desmos"}] - } - }, - { - POSITION: [4.25, 11, 2, 2.25, -4.25, 92.5, 0] - }, - { - POSITION: [4.25, 11, 2, 2.25, 4.25, -92.5, 0] - } - ] -} -Class.undertow = { - PARENT: "genericTank", - LABEL: "Undertow", - DANGER: 6, - UPGRADE_TOOLTIP: "[DEV NOTE] This tank does not function as intended yet!", - GUNS: [ - { - POSITION: [14, 12, 0.8, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.desmos, { reload: 1.2 }]), - TYPE: "bullet" - } - }, - { - POSITION: [11.25, 8, 0.15, 4.25, 4, 13.5, 0] - }, - { - POSITION: [11.25, 8, 0.15, 4.25, -4, -13.5, 0] - } - ] -} -Class.repeater = { - PARENT: "genericTank", - LABEL: "Repeater", - GUNS: [ - { - POSITION: [20, 10, 0.8, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.desmos]), - TYPE: ["splitterBullet", {MOTION_TYPE: "desmos"}] - } - }, - { - POSITION: [4.625, 9.5, 2, 0.375, -8, 91.5, 0] - }, - { - POSITION: [4.625, 9.5, 2, 0.375, 8, -91.5, 0] - }, - { - POSITION: [3.75, 10, 2.125, 0, -4.75, 50, 0] - }, - { - POSITION: [3.75, 10, 2.125, 0, 4.75, -50, 0] - } - ] -} - -// Helix upgrades -Class.triplex = { - PARENT: "genericTank", - LABEL: "Triplex", - DANGER: 7, - STAT_NAMES: statnames.desmos, - GUNS: [ - { - POSITION: [18, 10, 0.7, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.tripleShot, g.desmos]), - TYPE: "bullet", - }, - }, - { - POSITION: [18, 10, 0.7, 0, 0, 45, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.tripleShot, g.desmos]), - TYPE: ["bullet", {MOTION_TYPE: "desmos"}] - }, - }, - { - POSITION: [18, 10, 0.7, 0, 0, -45, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.tripleShot, g.desmos]), - TYPE: ["bullet", {MOTION_TYPE: ["desmos", {invert: true}]}] - }, - }, - { - POSITION: [3.75, 10, 2.125, 1, -4.25, 10, 0], - }, - { - POSITION: [3.75, 10, 2.125, 1, 4.25, -10, 0], - }, - { - POSITION: [5, 6, 0.5, 10.5, 0, 22.5, 0], - }, - { - POSITION: [5, 6, 0.5, 10.5, 0, -22.5, 0], - }, - ], -} -Class.quadruplex = { - PARENT: "genericTank", - LABEL: "Quadruplex", - DANGER: 7, - STAT_NAMES: statnames.desmos, - GUNS: [ - { - POSITION: [20, 10, 0.8, 0, 0, 45, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.desmos]), - TYPE: ["bullet", {MOTION_TYPE: ["desmos", {amplitude: 25}]}] - } - }, - { - POSITION: [3.75, 10, 2.125, 1.25, -6.25, 135, 0] - }, - { - POSITION: [3.75, 10, 2.125, 1.25, 6.25, -45, 0] - }, - { - POSITION: [20, 10, 0.8, 0, 0, -45, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.desmos]), - TYPE: ["bullet", {MOTION_TYPE: ["desmos", {amplitude: 25, invert: true}]}] - } - }, - { - POSITION: [3.75, 10, 2.125, 1.25, -6.25, 45, 0] - }, - { - POSITION: [3.75, 10, 2.125, 1.25, 6.25, -135, 0] - }, - { - POSITION: [20, 10, 0.8, 0, 0, 135, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.desmos]), - TYPE: ["bullet", {MOTION_TYPE: ["desmos", {period: 7, amplitude: 10}]}] - } - }, - { - POSITION: [3.75, 10, 2.125, 1.25, -6.25, -135, 0] - }, - { - POSITION: [3.75, 10, 2.125, 1.25, 6.25, 45, 0] - }, - { - POSITION: [20, 10, 0.8, 0, 0, -135, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.desmos]), - TYPE: ["bullet", {MOTION_TYPE: ["desmos", {period: 7, amplitude: 10, invert: true}]}] - } - }, - { - POSITION: [3.75, 10, 2.125, 1.25, -6.25, -45, 0] - }, - { - POSITION: [3.75, 10, 2.125, 1.25, 6.25, 135, 0] - }, - ], -} - -// Sidewinder upgrades -Class.coil = { - PARENT: "genericTank", - LABEL: "Coil", - DANGER: 7, - STAT_NAMES: statnames.desmos, - UPGRADE_TOOLTIP: "[DEV NOTE] This tank does not function as intended yet!", - GUNS: [ - { - POSITION: [20, 8, 0.75, 0, -5, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.desmos]), - TYPE: ["bullet", {MOTION_TYPE: ["desmos", {invert: false}]}] - }, - }, - { - POSITION: [20, 8, 0.75, 0, 5, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.desmos]), - TYPE: ["bullet", {MOTION_TYPE: ["desmos", {invert: true}]}] - }, - }, - { - POSITION: [21, 4, 0.75, 0, -5, 0, 0] - }, - { - POSITION: [21, 4, 0.75, 0, 5, 0, 0] - }, - { - POSITION: [3.625, 7.5, 2.75, 5.75, -6.75, 90, 0], - }, - { - POSITION: [3.625, 7.5, 2.75, 5.75, 6.75, -90, 0], - }, - { - POSITION: [6, 8, 0.25, 10.5, 0, 0, 0], - } - ] -} -Class.python = { - PARENT: "genericTank", - LABEL: "Python", - DANGER: 7, - STAT_NAMES: statnames.desmos, - UPGRADE_TOOLTIP: "[DEV NOTE] This tank is a placeholder!" -} -Class.ranch = { - PARENT: "genericTank", - LABEL: "Ranch", - DANGER: 7, - STAT_NAMES: statnames.drone, - UPGRADE_TOOLTIP: "[DEV NOTE] This tank does not function as intended yet!", - BODY: { - SPEED: base.SPEED * 0.8, - FOV: 1.1, - }, - GUNS: [ - { - POSITION: [4.5, 10, 1, 10.5, 0, 0, 0], - }, - { - POSITION: [1, 12, 1, 15, 0, 0, 0], - PROPERTIES: { - MAX_CHILDREN: 3, - SHOOT_SETTINGS: combineStats([g.factory, g.babyfactory]), - TYPE: "minion", - STAT_CALCULATOR: gunCalcNames.drone, - AUTOFIRE: true, - SYNCS_SKILLS: true, - }, - }, - { - POSITION: [11.5, 12, 1, 0, 0, 0, 0], - }, - { - POSITION: [5, 7.5, 2.5, 1, -4.5, 95, 0], - }, - { - POSITION: [5, 7.5, 2.5, 1, 4.5, -95, 0], - }, - ], -} -Class.oroboros = { - PARENT: "genericTank", - LABEL: "Oroboros", - DANGER: 7, - STAT_NAMES: statnames.desmos, - UPGRADE_TOOLTIP: "[DEV NOTE] This tank is a placeholder!" -} -Class.cocci = { - PARENT: "genericSmasher", - LABEL: "Cocci", - UPGRADE_TOOLTIP: "[DEV NOTE] This tank is a placeholder!", - TURRETS: [ - { - POSITION: [21.5, 0, 0, 0, 360, 0], - TYPE: "smasherBody" - } - ] -} - -// Undertow upgrades -Class.riptide = { - PARENT: "genericTank", - LABEL: "Riptide", - DANGER: 7, - UPGRADE_TOOLTIP: "[DEV NOTE] This tank does not function as intended yet!", - GUNS: [ - { - POSITION: [6.5, 23.5, 0.25, 3, 0, 180, 0], - }, - { - POSITION: [18, 16, 0.75, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.desmos, { size: 0.9, reload: 1.2 }]), - TYPE: "bullet" - } - }, - { - POSITION: [17, 16, 0.1, 0.25, 4, 13.5, 0] - }, - { - POSITION: [17, 16, 0.1, 0.25, -4, -13.5, 0] - } - ] -} - -// Repeater upgrades -Class.iterator = { - PARENT: "genericTank", - LABEL: "Iterator", - DANGER: 7, - STAT_NAMES: statnames.desmos, - GUNS: [ - { - POSITION: [22, 10, 0.8, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.desmos]), - TYPE: ["superSplitterBullet", {MOTION_TYPE: "desmos"}] - } - }, - { - POSITION: [4.625, 10.5, 2.75, 0.375, -7, 91.5, 0] - }, - { - POSITION: [4.625, 10.5, 2.75, 0.375, 7, -91.5, 0] - }, - { - POSITION: [4, 9, 3, 1.5, -5, 95, 0] - }, - { - POSITION: [4, 9, 3, 1.5, 5, -95, 0] - }, - { - POSITION: [3.75, 10, 2.125, -1.5, -5.25, 50, 0] - }, - { - POSITION: [3.75, 10, 2.125, -1.5, 5.25, -50, 0] - } - ] -} -Class.duplicator = { - PARENT: "genericTank", - LABEL: "Duplicator", - DANGER: 7, - STAT_NAMES: statnames.desmos, - GUNS: [ - { - POSITION: [20, 10, 0.8, 0, 0, 20, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.desmos]), - TYPE: ["splitterBullet", {MOTION_TYPE: ["desmos", {invert: false}]}] - } - }, - { - POSITION: [20, 10, 0.8, 0, 0, -20, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.desmos]), - TYPE: ["splitterBullet", {MOTION_TYPE: ["desmos", {invert: true}]}] - } - }, - { - POSITION: [5.625, 9.5, 2, 0.375-1, -8, 111.5, 0] - }, - { - POSITION: [3.75, 10, 2.125, 0, 4.75, -30, 0] - }, - { - POSITION: [5.625, 9.5, 2, 0.375-1, 8, -111.5, 0] - }, - { - POSITION: [3.75, 10, 2.125, 0, -4.75, 30, 0] - }, - { - POSITION: [17, 8, 0.65, 0, 0, 0, 0] - }, - { - POSITION: [18, 8, 0.25, 0, 0, 0, 0] - }, - ] -} - -// Smasher upgrades -Class.megaSmasher = { - PARENT: "genericSmasher", - LABEL: "Mega-Smasher", - BODY: { - SPEED: 1.05 * base.SPEED, - FOV: 1.1 * base.FOV, - DENSITY: 4 * base.DENSITY, - }, - TURRETS: [ - { - POSITION: [25, 0, 0, 0, 360, 0], - TYPE: "smasherBody", - }, - ], -} -Class.spike = { - PARENT: "genericSmasher", - LABEL: "Spike", - BODY: { - SPEED: base.SPEED * 0.9, - DAMAGE: base.DAMAGE * 1.1, - }, - TURRETS: [ - { - POSITION: [18.5, 0, 0, 0, 360, 0], - TYPE: "spikeBody", - }, - { - POSITION: [18.5, 0, 0, 90, 360, 0], - TYPE: "spikeBody", - }, - { - POSITION: [18.5, 0, 0, 180, 360, 0], - TYPE: "spikeBody", - }, - { - POSITION: [18.5, 0, 0, 270, 360, 0], - TYPE: "spikeBody", - }, - ], -} -Class.landmine = { - PARENT: "genericSmasher", - LABEL: "Landmine", - INVISIBLE: [0.06, 0.01], - TOOLTIP: "Stay still to turn invisible.", - BODY: { - SPEED: 1.1 * base.SPEED - }, - TURRETS: [ - { - POSITION: [21.5, 0, 0, 0, 360, 0], - TYPE: "smasherBody" - }, - { - POSITION: [21.5, 0, 0, 30, 360, 0], - TYPE: "landmineBody" - } - ] -} - -// Healer upgrades -Class.medic = { - PARENT: "genericTank", - LABEL: "Medic", - BODY: { - FOV: base.FOV * 1.2, - }, - TURRETS: [ - { - POSITION: [13, 0, 0, 0, 360, 1], - TYPE: "healerSymbol", - }, - ], - GUNS: [ - { - POSITION: [8, 9, -0.5, 16.5, 0, 0, 0], - }, - { - POSITION: [22, 10, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.healer, g.sniper]), - TYPE: "healerBullet", - }, - }, - ], - STAT_NAMES: statnames.heal, -} -Class.ambulance = { - PARENT: "genericTank", - LABEL: "Ambulance", - BODY: { - HEALTH: base.HEALTH * 0.8, - SHIELD: base.SHIELD * 0.8, - DENSITY: base.DENSITY * 0.6, - }, - TURRETS: [ - { - POSITION: [13, 0, 0, 0, 360, 1], - TYPE: "healerSymbol", - }, - ], - GUNS: [ - { - POSITION: [8, 9, -0.5, 12.5, 0, 0, 0], - }, - { - POSITION: [18, 10, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.triAngleFront, { recoil: 4 }, g.healer]), - TYPE: "healerBullet", - LABEL: "Front", - }, - }, - { - POSITION: [16, 8, 1, 0, 0, 150, 0.1], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), - TYPE: "bullet", - LABEL: gunCalcNames.thruster, - }, - }, - { - POSITION: [16, 8, 1, 0, 0, 210, 0.1], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), - TYPE: "bullet", - LABEL: gunCalcNames.thruster, - }, - }, - ], - STAT_NAMES: statnames.heal, -} -Class.surgeon = { - PARENT: "genericTank", - LABEL: "Surgeon", - STAT_NAMES: statnames.trap, - BODY: { - SPEED: base.SPEED * 0.75, - FOV: base.FOV * 1.15, - }, - TURRETS: [ - { - POSITION: [13, 0, 0, 0, 360, 1], - TYPE: "healerSymbol", - }, - ], - GUNS: [ - { - POSITION: [5, 11, 1, 10.5, 0, 0, 0], - }, - { - POSITION: [3, 14, 1, 15.5, 0, 0, 0], - }, - { - POSITION: [2, 14, 1.3, 18, 0, 0, 0], - PROPERTIES: { - MAX_CHILDREN: 2, - SHOOT_SETTINGS: combineStats([g.trap, g.setTrap, { speed: 0.7, maxSpeed: 0.7 }]), - TYPE: "surgeonPillbox", - SYNCS_SKILLS: true, - STAT_CALCULATOR: gunCalcNames.block - }, - }, - { - POSITION: [4, 14, 1, 8, 0, 0, 0], - }, - ], - STAT_NAMES: statnames.heal, -} -Class.paramedic = { - PARENT: "genericTank", - LABEL: "Paramedic", - BODY: { - SPEED: base.SPEED * 0.9, - }, - TURRETS: [ - { - POSITION: [13, 0, 0, 0, 360, 1], - TYPE: "healerSymbol", - }, - ], - GUNS: [ - { - POSITION: [8, 9, -0.5, 10, 0, -17.5, 0.5], - }, - { - POSITION: [15.5, 10, 1, 0, 0, -17.5, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.tripleShot, g.healer]), - TYPE: "healerBullet", - }, - }, - { - POSITION: [8, 9, -0.5, 10, 0, 17.5, 0.5], - }, - { - POSITION: [15.5, 10, 1, 0, 0, 17.5, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.tripleShot, g.healer]), - TYPE: "healerBullet", - }, - }, - { - POSITION: [8, 9, -0.5, 12.5, 0, 0, 0], - }, - { - POSITION: [18, 10, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.tripleShot, g.healer]), - TYPE: "healerBullet", - }, - }, - ], - STAT_NAMES: statnames.heal, -} - -// Bird tanks -Class.falcon = makeBird("assassin", "Falcon") -Class.vulture = makeBird({ - PARENT: "genericTank", - DANGER: 7, - BODY: { - FOV: base.FOV * 1.2, - }, - GUNS: [ - { - POSITION: [22, 7, -1.5, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.minigun]), - TYPE: "bullet" - } - }, - { - POSITION: [20, 7.5, -1.5, 0, 0, 0, 1/3], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.minigun, {size: 7/7.5}]), - TYPE: "bullet" - } - }, - { - POSITION: [18, 8, -1.5, 0, 0, 0, 2/3], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.minigun, {size: 7/8}]), - TYPE: "bullet" - } - } - ] -}, "Vulture") -Class.phoenix = makeBird("sprayer", "Phoenix") -Class.eagle = makeBird("pounder", "Eagle") - -// Hybrid tanks -Class.bentHybrid = makeOver('tripleShot', "Bent Hybrid", {count: 1, independent: true, cycle: false}) -Class.poacher = makeOver('hunter', "Poacher", {count: 1, independent: true, cycle: false}) -Class.armsman = makeOver('rifle', "Armsman", {count: 1, independent: true, cycle: false}) -Class.cropDuster = makeOver('minigun', "Crop Duster", {count: 1, independent: true, cycle: false}) -Class.hybrid = makeOver('destroyer', "Hybrid", {count: 1, independent: true, cycle: false}) - -// Over tanks -Class.overgunner = makeOver({ - PARENT: "genericTank", - LABEL: "Gunner", - DANGER: 6, - GUNS: [ - { - POSITION: [19, 2, 1, 0, -2.5, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.power, g.twin, { speed: 0.7, maxSpeed: 0.7 }, g.flankGuard, { recoil: 1.8 }]), - TYPE: "bullet", - }, - }, - { - POSITION: [19, 2, 1, 0, 2.5, 0, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.power, g.twin, { speed: 0.7, maxSpeed: 0.7 }, g.flankGuard, { recoil: 1.8 }]), - TYPE: "bullet", - }, - }, - { - POSITION: [12, 11, 1, 0, 0, 0, 0], - }, - ], -}) -Class.overtrapper = makeOver({ - PARENT: "genericTank", - LABEL: "Trapper", - DANGER: 6, - STAT_NAMES: statnames.mixed, - BODY: { - SPEED: base.SPEED * 0.8, - FOV: base.FOV * 1.2 - }, - GUNS: [ - { - POSITION: [14, 8, 1, 0, 0, 0, 0], - }, - { - POSITION: [4, 8, 1.5, 14, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap]), - TYPE: "trap", - STAT_CALCULATOR: gunCalcNames.trap - } - } - ] -}) - -// Auto tanks -Class.autoDouble = makeAuto("doubleTwin", "Auto-Double") -Class.autoAssassin = makeAuto("assassin") -Class.autoGunner = makeAuto("gunner") -Class.autoTriAngle = makeAuto("triAngle") -Class.autoOverseer = makeAuto("overseer") -Class.autoCruiser = makeAuto("cruiser") -Class.autoSpawner = makeAuto("spawner") -Class.autoBuilder = makeAuto("builder") -Class.autoSmasher = makeAuto({ - PARENT: "genericSmasher", - DANGER: 6, - TURRETS: [ - { - POSITION: [21.5, 0, 0, 0, 360, 0], - TYPE: "smasherBody" - } - ], - SKILL_CAP: [smshskl, smshskl, smshskl, smshskl, smshskl, smshskl, smshskl, smshskl, smshskl, smshskl] -}, "Auto-Smasher", {type: "autoSmasherTurret", size: 11}) - -// Upgrade paths -Class.basic.UPGRADES_TIER_1 = ["twin", "sniper", "machineGun", "flankGuard", "director", "pounder", "trapper", "desmos"] - Class.basic.UPGRADES_TIER_2 = ["smasher"] - Class.smasher.UPGRADES_TIER_3 = ["megaSmasher", "spike", "autoSmasher", "landmine", "cocci"] - Class.healer.UPGRADES_TIER_3 = ["medic", "ambulance", "surgeon", "paramedic"] - - Class.twin.UPGRADES_TIER_2 = ["doubleTwin", "tripleShot", "gunner", "hexaTank", "helix"] - Class.twin.UPGRADES_TIER_3 = ["dual", "bulwark", "musket"] - Class.doubleTwin.UPGRADES_TIER_3 = ["tripleTwin", "hewnDouble", "autoDouble", "bentDouble"] - Class.tripleShot.UPGRADES_TIER_3 = ["pentaShot", "spreadshot", "bentHybrid", "bentDouble", "triplet", "triplex"] - - Class.sniper.UPGRADES_TIER_2 = ["assassin", "hunter", "minigun", "rifle"] - Class.sniper.UPGRADES_TIER_3 = ["bushwhacker"] - Class.assassin.UPGRADES_TIER_3 = ["ranger", "falcon", "stalker", "autoAssassin", "single"] - Class.hunter.UPGRADES_TIER_3 = ["predator", "xHunter", "poacher", "ordnance", "dual"] - Class.rifle.UPGRADES_TIER_3 = ["musket", "crossbow", "armsman"] - - Class.machineGun.UPGRADES_TIER_2 = ["artillery", "minigun", "gunner", "sprayer"] - Class.minigun.UPGRADES_TIER_3 = ["streamliner", "nailgun", "cropDuster", "barricade", "vulture"] - Class.gunner.UPGRADES_TIER_3 = ["autoGunner", "nailgun", "auto4", "machineGunner", "gunnerTrapper", "cyclone", "overgunner"] - Class.sprayer.UPGRADES_TIER_3 = ["redistributor", "phoenix", "atomizer", "focal"] - - Class.flankGuard.UPGRADES_TIER_2 = ["hexaTank", "triAngle", "auto3", "trapGuard", "triTrapper"] - Class.flankGuard.UPGRADES_TIER_3 = ["tripleTwin", "quadruplex"] - Class.hexaTank.UPGRADES_TIER_3 = ["octoTank", "cyclone", "hexaTrapper"] - Class.triAngle.UPGRADES_TIER_3 = ["fighter", "booster", "falcon", "bomber", "autoTriAngle", "surfer", "eagle", "phoenix", "vulture"] - Class.auto3.UPGRADES_TIER_3 = ["auto5", "mega3", "auto4", "banshee"] - - Class.director.UPGRADES_TIER_2 = ["overseer", "cruiser", "underseer", "spawner"] - Class.director.UPGRADES_TIER_3 = ["manager", "bigCheese"] - Class.overseer.UPGRADES_TIER_3 = ["overlord", "overtrapper", "overgunner", "banshee", "autoOverseer", "overdrive", "commander"] - Class.cruiser.UPGRADES_TIER_3 = ["carrier", "battleship", "fortress", "autoCruiser", "commander"] - Class.underseer.UPGRADES_TIER_3 = ["necromancer", "maleficitor", "infestor"] - Class.spawner.UPGRADES_TIER_3 = ["factory", "autoSpawner", "ranch"] - - Class.pounder.UPGRADES_TIER_2 = ["destroyer", "builder", "artillery", "launcher"] - Class.pounder.UPGRADES_TIER_3 = ["shotgun", "eagle"] - Class.destroyer.UPGRADES_TIER_3 = ["conqueror", "annihilator", "hybrid", "construct"] - Class.artillery.UPGRADES_TIER_3 = ["mortar", "ordnance", "beekeeper", "fieldGun"] - Class.launcher.UPGRADES_TIER_3 = ["skimmer", "twister", "swarmer", "rocketeer", "fieldGun"] - - Class.trapper.UPGRADES_TIER_2 = ["builder", "triTrapper", "trapGuard"] - Class.trapper.UPGRADES_TIER_3 = ["barricade", "overtrapper"] - Class.builder.UPGRADES_TIER_3 = ["construct", "autoBuilder", "engineer", "boomer", "assembler", "architect", "conqueror"] - Class.triTrapper.UPGRADES_TIER_3 = ["fortress", "hexaTrapper", "septaTrapper", "architect"] - Class.trapGuard.UPGRADES_TIER_3 = ["bushwhacker", "gunnerTrapper", "bomber", "conqueror", "bulwark"] - - Class.desmos.UPGRADES_TIER_2 = ["helix", "sidewinder", "undertow", "repeater"] - Class.helix.UPGRADES_TIER_3 = ["triplex", "quadruplex", "coil", "duplicator"] - Class.sidewinder.UPGRADES_TIER_3 = ["coil", "python", "ranch", "oroboros", "cocci"] - Class.undertow.UPGRADES_TIER_3 = ["riptide"] - Class.repeater.UPGRADES_TIER_3 = ["iterator", "duplicator"] +const { combineStats, makeAuto, makeOver, makeDeco, makeGuard, makeBird, makeRadialAuto, weaponArray, makeCeption, makeAura } = require('../facilitators.js'); +const { base, statnames, dfltskl, smshskl } = require('../constants.js'); +require('./generics.js'); +const g = require('../gunvals.js'); + +// Basic & starting upgrades +Class.basic = { + PARENT: "genericTank", + LABEL: "Basic", + DANGER: 4, + SKILL_CAP: Array(10).fill(10), + SKILL: Array(10).fill(10), + /*BODY: { + ACCELERATION: base.ACCEL * 1, + SPEED: base.SPEED * 1, + HEALTH: base.HEALTH * 1, + DAMAGE: base.DAMAGE * 1, + PENETRATION: base.PENETRATION * 1, + SHIELD: base.SHIELD * 1, + REGEN: base.REGEN * 1, + FOV: base.FOV * 1, + DENSITY: base.DENSITY * 1, + PUSHABILITY: 1,3 + HETERO: 3 + },*/ + GUNS: [ + { + POSITION: { + LENGTH: 18, + WIDTH: 8, + ASPECT: 1, + X: 0, + Y: 0, + ANGLE: 0, + DELAY: 0 + }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic]), + TYPE: "bullet", + /*COLOR: "grey", + LABEL: "", + STAT_CALCULATOR: 0, + WAIT_TO_CYCLE: false, + AUTOFIRE: false, + SYNCS_SKILLS: false, + MAX_CHILDREN: 0, + ALT_FIRE: false, + NEGATIVE_RECOIL: false*/ + } + } + ] +} +Class.twin = { + PARENT: "genericTank", + LABEL: "Twin", + GUNS: [ + { + POSITION: { + LENGTH: 20, + WIDTH: 8, + Y: 5.5 + }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin]), + TYPE: "bullet" + } + }, + { + POSITION: { + LENGTH: 20, + WIDTH: 8, + Y: -5.5, + DELAY: 0.5 + }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin]), + TYPE: "bullet" + } + } + ] +} +Class.sniper = { + PARENT: "genericTank", + LABEL: "Sniper", + BODY: { + FOV: 1.2 * base.FOV + }, + GUNS: [ + { + POSITION: { + LENGTH: 24, + WIDTH: 8.5 + }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper]), + TYPE: "bullet" + } + } + ] +} +Class.machineGun = { + PARENT: "genericTank", + LABEL: "Machine Gun", + GUNS: [ + { + POSITION: { + LENGTH: 12, + WIDTH: 10, + ASPECT: 1.4, + X: 8 + }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun]), + TYPE: "bullet" + } + } + ] +} +Class.flankGuard = { + PARENT: "genericTank", + LABEL: "Flank Guard", + BODY: { + SPEED: 1.1 * base.SPEED + }, + GUNS: weaponArray({ + POSITION: { + LENGTH: 18, + WIDTH: 8 + }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard]), + TYPE: "bullet" + } + }, 3) +} +Class.director = { + PARENT: "genericTank", + LABEL: "Director", + STAT_NAMES: statnames.drone, + BODY: { + FOV: base.FOV * 1.1 + }, + GUNS: [ + { + POSITION: { + LENGTH: 6, + WIDTH: 11, + ASPECT: 1.3, + X: 7 + }, + POSITION: [6, 11, 1.3, 7, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone]), + TYPE: "drone", + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "drone", + MAX_CHILDREN: 6, + WAIT_TO_CYCLE: true + } + } + ] +} +Class.pounder = { + PARENT: "genericTank", + LABEL: "Pounder", + GUNS: [ + { + POSITION: { + LENGTH: 20.5, + WIDTH: 12 + }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder]), + TYPE: "bullet" + } + } + ] +} +Class.trapper = { + PARENT: "genericTank", + LABEL: "Trapper", + STAT_NAMES: statnames.trap, + GUNS: [ + { + POSITION: { + LENGTH: 15, + WIDTH: 7 + } + }, + { + POSITION: { + LENGTH: 3, + WIDTH: 7, + ASPECT: 1.7, + X: 15 + }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap]), + TYPE: "trap", + STAT_CALCULATOR: "trap" + } + } + ] +} +Class.desmos = { + PARENT: "genericTank", + LABEL: "Desmos", + STAT_NAMES: statnames.desmos, + GUNS: [ + { + POSITION: [20, 8, -4/3, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.desmos]), + TYPE: ["bullet", {MOTION_TYPE: "desmos"}] + } + }, + { + POSITION: [3.75, 10, 2.125, 1.5, -6.25, 90, 0] + }, + { + POSITION: [3.75, 10, 2.125, 1.5, 6.25, -90, 0] + } + ] +} +Class.smasher = { + PARENT: "genericSmasher", + LABEL: "Smasher", + DANGER: 6, + TURRETS: [ + { + POSITION: [21.5, 0, 0, 0, 360, 0], + TYPE: "smasherBody" + } + ] +} +Class.healer = { + PARENT: "genericTank", + LABEL: "Healer", + STAT_NAMES: statnames.heal, + TURRETS: [ + { + POSITION: [13, 0, 0, 0, 360, 1], + TYPE: "healerSymbol" + } + ], + GUNS: [ + { + POSITION: { + LENGTH: 8, + WIDTH: 9, + ASPECT: -0.5, + X: 12.5 + } + }, + { + POSITION: { + LENGTH: 18, + WIDTH: 10 + }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.healer]), + TYPE: "healerBullet" + } + } + ] +} + +// Twin upgrades +Class.doubleTwin = { + PARENT: "genericTank", + LABEL: "Double Twin", + DANGER: 6, + GUNS: weaponArray([ + { + POSITION: [20, 8, 1, 0, 5.5, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.doubleTwin]), + TYPE: "bullet" + } + }, + { + POSITION: [20, 8, 1, 0, -5.5, 0, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.doubleTwin]), + TYPE: "bullet" + } + } + ], 2) +} +Class.tripleShot = { + PARENT: "genericTank", + LABEL: "Triple Shot", + DANGER: 6, + BODY: { + SPEED: base.SPEED * 0.9 + }, + GUNS: [ + { + POSITION: { + LENGTH: 19, + WIDTH: 8, + Y: -2, + ANGLE: -17.5, + DELAY: 0.5 + }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.tripleShot]), + TYPE: "bullet" + } + }, + { + POSITION: { + LENGTH: 19, + WIDTH: 8, + Y: 2, + ANGLE: 17.5, + DELAY: 0.5 + }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.tripleShot]), + TYPE: "bullet" + } + }, + { + POSITION: { + LENGTH: 22, + WIDTH: 8 + }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.tripleShot]), + TYPE: "bullet" + } + } + ] +} + +// Double Twin upgrades +Class.tripleTwin = { + PARENT: "genericTank", + LABEL: "Triple Twin", + DANGER: 7, + GUNS: weaponArray([ + { + POSITION: [20, 8, 1, 0, 5.5, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.spam, g.doubleTwin]), + TYPE: "bullet" + } + }, + { + POSITION: [20, 8, 1, 0, -5.5, 0, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.spam, g.doubleTwin]), + TYPE: "bullet" + } + } + ], 3) +} +Class.hewnDouble = { + PARENT: "genericTank", + LABEL: "Hewn Double", + DANGER: 7, + GUNS: [ + { + POSITION: [19, 8, 1, 0, 5.5, 205, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.twin, g.doubleTwin, g.hewnDouble, { recoil: 1.15 }]), + TYPE: "bullet" + } + }, + { + POSITION: [19, 8, 1, 0, -5.5, -205, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.twin, g.doubleTwin, g.hewnDouble, { recoil: 1.15 }]), + TYPE: "bullet" + } + }, + { + POSITION: [20, 8, 1, 0, 5.5, 180, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.doubleTwin, g.hewnDouble, { recoil: 1.15 }]), + TYPE: "bullet" + } + }, + { + POSITION: [20, 8, 1, 0, -5.5, 180, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.doubleTwin, g.hewnDouble, { recoil: 1.15 }]), + TYPE: "bullet" + } + }, + { + POSITION: [20, 8, 1, 0, 5.5, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.doubleTwin, g.hewnDouble]), + TYPE: "bullet" + } + }, + { + POSITION: [20, 8, 1, 0, -5.5, 0, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.doubleTwin, g.hewnDouble]), + TYPE: "bullet" + } + } + ] +} + +// Triple Shot upgrades +Class.pentaShot = { + PARENT: "genericTank", + LABEL: "Penta Shot", + DANGER: 7, + BODY: { + SPEED: 0.85 * base.SPEED + }, + GUNS: [ + { + POSITION: [16, 8, 1, 0, -3, -30, 2/3], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.tripleShot]), + TYPE: "bullet" + } + }, + { + POSITION: [16, 8, 1, 0, 3, 30, 2/3], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.tripleShot]), + TYPE: "bullet" + } + }, + { + POSITION: [19, 8, 1, 0, -2, -15, 1/3], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.tripleShot]), + TYPE: "bullet" + } + }, + { + POSITION: [19, 8, 1, 0, 2, 15, 1/3], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.tripleShot]), + TYPE: "bullet" + } + }, + { + POSITION: [22, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.tripleShot]), + TYPE: "bullet" + } + } + ] +} +Class.spreadshot = { + PARENT: "genericTank", + LABEL: "Spreadshot", + DANGER: 7, + GUNS: [ + { + POSITION: [13, 4, 1, 0, -0.5, -75, 5 / 6], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery, g.twin, g.spreadshot]), + TYPE: "bullet", + LABEL: "Spread" + } + }, + { + POSITION: [13, 4, 1, 0, 0.5, 75, 5 / 6], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery, g.twin, g.spreadshot]), + TYPE: "bullet", + LABEL: "Spread" + } + }, + { + POSITION: [14.5, 4, 1, 0, -0.5, -60, 4 / 6], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery, g.twin, g.spreadshot]), + TYPE: "bullet", + LABEL: "Spread" + } + }, + { + POSITION: [14.5, 4, 1, 0, 0.5, 60, 4 / 6], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery, g.twin, g.spreadshot]), + TYPE: "bullet", + LABEL: "Spread" + } + }, + { + POSITION: [16, 4, 1, 0, -0.5, -45, 3 / 6], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery, g.twin, g.spreadshot]), + TYPE: "bullet", + LABEL: "Spread" + } + }, + { + POSITION: [16, 4, 1, 0, 0.5, 45, 3 / 6], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery, g.twin, g.spreadshot]), + TYPE: "bullet", + LABEL: "Spread" + } + }, + { + POSITION: [17.5, 4, 1, 0, -0.5, -30, 2 / 6], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery, g.twin, g.spreadshot]), + TYPE: "bullet", + LABEL: "Spread" + } + }, + { + POSITION: [17.5, 4, 1, 0, 0.5, 30, 2 / 6], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery, g.twin, g.spreadshot]), + TYPE: "bullet", + LABEL: "Spread" + } + }, + { + POSITION: [19, 4, 1, 0, -1, -15, 1 / 6], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery, g.twin, g.spreadshot]), + TYPE: "bullet", + LABEL: "Spread" + } + }, + { + POSITION: [19, 4, 1, 0, 1, 15, 1 / 6], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery, g.twin, g.spreadshot]), + TYPE: "bullet", + LABEL: "Spread" + } + }, + { + POSITION: [12, 8, 1, 8, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.spreadshotMain, g.spreadshot]), + TYPE: "bullet" + } + } + ] +} +Class.bentDouble = { + PARENT: "genericTank", + LABEL: "Bent Double", + DANGER: 7, + GUNS: weaponArray([ + { + POSITION: [19, 8, 1, 0, -2, -17.5, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.tripleShot, g.doubleTwin]), + TYPE: "bullet" + } + }, + { + POSITION: [19, 8, 1, 0, 2, 17.5, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.tripleShot, g.doubleTwin]), + TYPE: "bullet" + } + }, + { + POSITION: [22, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.tripleShot, g.doubleTwin]), + TYPE: "bullet" + } + } + ], 2) +} +Class.triplet = { + PARENT: "genericTank", + DANGER: 7, + LABEL: "Triplet", + BODY: { + FOV: 1.05 * base.FOV + }, + GUNS: [ + { + POSITION: [18, 10, 1, 0, 5, 0, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.triplet]), + TYPE: "bullet" + } + }, + { + POSITION: [18, 10, 1, 0, -5, 0, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.triplet]), + TYPE: "bullet" + } + }, + { + POSITION: [21, 10, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.triplet]), + TYPE: "bullet" + } + } + ] +} + +// Sniper upgrades +Class.assassin = { + PARENT: "genericTank", + DANGER: 6, + LABEL: "Assassin", + BODY: { + SPEED: 0.85 * base.SPEED, + FOV: 1.4 * base.FOV + }, + GUNS: [ + { + POSITION: [27, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.assassin]), + TYPE: "bullet" + } + }, + { + POSITION: [5, 8, -1.4, 8, 0, 0, 0] + } + ] +} +Class.hunter = { + PARENT: "genericTank", + LABEL: "Hunter", + DANGER: 6, + BODY: { + SPEED: base.SPEED * 0.9, + FOV: base.FOV * 1.25 + }, + CONTROLLERS: ["zoom"], + TOOLTIP: "Hold right click to zoom.", + GUNS: [ + { + POSITION: [24, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.hunterSecondary]), + TYPE: "bullet" + } + }, + { + POSITION: [21, 12, 1, 0, 0, 0, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter]), + TYPE: "bullet" + } + } + ] +} +Class.rifle = { + PARENT: "genericTank", + LABEL: "Rifle", + DANGER: 6, + BODY: { + FOV: base.FOV * 1.225 + }, + GUNS: [ + { + POSITION: [20, 12, 1, 0, 0, 0, 0] + }, + { + POSITION: [24, 7, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.rifle]), + TYPE: "bullet" + } + } + ] +} +Class.marksman = { + PARENT: "genericTank", + LABEL: "Marksman", + DANGER: 6, + BODY: { + FOV: 1.2 * base.FOV + }, + UPGRADE_TOOLTIP: "[DEV NOTE] This tank does not function as intended yet!", + GUNS: [ + { + POSITION: { + LENGTH: 5, + WIDTH: 8.5, + ASPECT: 1.3, + X: 8 + } + }, + { + POSITION: { + LENGTH: 5, + WIDTH: 8.5, + ASPECT: 1.3, + X: 13 + } + }, + { + POSITION: { + LENGTH: 5, + WIDTH: 8.5, + ASPECT: 1.3, + X: 18 + } + }, + { + POSITION: { + LENGTH: 24, + WIDTH: 8.5 + }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper]), + TYPE: "bullet" + } + } + ] +} + +// Assassin upgrades +Class.ranger = { + PARENT: "genericTank", + LABEL: "Ranger", + DANGER: 7, + BODY: { + SPEED: 0.8 * base.SPEED, + FOV: 1.5 * base.FOV, + }, + GUNS: [ + { + POSITION: [32, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.assassin]), + TYPE: "bullet", + }, + }, + { + POSITION: [5, 8, -1.4, 8, 0, 0, 0], + }, + ], +} +Class.stalker = { + PARENT: "genericTank", + DANGER: 7, + LABEL: "Stalker", + BODY: { + SPEED: 0.85 * base.SPEED, + FOV: 1.35 * base.FOV + }, + INVISIBLE: [0.08, 0.03], + TOOLTIP: "Stay still to turn invisible.", + GUNS: [ + { + POSITION: [27, 8, -1.8, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.assassin]), + TYPE: "bullet" + } + } + ] +} +Class.single = { + PARENT: "genericTank", + LABEL: "Single", + DANGER: 7, + GUNS: [ + { + POSITION: [19, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.single]), + TYPE: "bullet" + } + }, + { + POSITION: [5.5, 8, -1.8, 6.5, 0, 0, 0] + } + ] +} + +// Hunter upgrades +Class.predator = { + PARENT: "genericTank", + LABEL: "Predator", + DANGER: 7, + BODY: { + SPEED: base.SPEED * 0.9, + FOV: base.FOV * 1.25 + }, + CONTROLLERS: ["zoom"], + TOOLTIP: "Hold right click to zoom.", + GUNS: [ + { + POSITION: [24, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.hunterSecondary, g.hunterSecondary, g.predator]), + TYPE: "bullet" + } + }, + { + POSITION: [21, 12, 1, 0, 0, 0, 0.15], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.hunterSecondary, g.predator]), + TYPE: "bullet" + } + }, + { + POSITION: [18, 16, 1, 0, 0, 0, 0.3], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.predator]), + TYPE: "bullet" + } + } + ] +} +Class.xHunter = { + PARENT: "genericTank", + LABEL: "X-Hunter", + DANGER: 7, + BODY: { + SPEED: base.SPEED * 0.9, + FOV: base.FOV * 1.25 + }, + CONTROLLERS: [["zoom", { distance: 550 }]], + TOOLTIP: "Hold right click to zoom.", + GUNS: [ + { + POSITION: [24, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.hunterSecondary]), + TYPE: "bullet" + } + }, + { + POSITION: [21, 12, 1, 0, 0, 0, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter]), + TYPE: "bullet" + } + }, + { + POSITION: [5, 12, -1.2, 7, 0, 0, 0] + } + ] +} +Class.dual = { + PARENT: "genericTank", + LABEL: "Dual", + DANGER: 7, + BODY: { + FOV: 1.1 * base.FOV + }, + CONTROLLERS: ["zoom"], + TOOLTIP: "Hold right click to zoom.", + GUNS: [ + { + POSITION: [18, 7, 1, 0, 5.5, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.dual, g.lowPower]), + TYPE: "bullet", + LABEL: "Small" + } + }, + { + POSITION: [18, 7, 1, 0, -5.5, 0, .5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.dual, g.lowPower]), + TYPE: "bullet", + LABEL: "Small" + } + }, + { + POSITION: [16, 8.5, 1, 0, 5.5, 0, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.dual]), + TYPE: "bullet" + } + }, + { + POSITION: [16, 8.5, 1, 0, -5.5, 0, .75], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.dual]), + TYPE: "bullet" + } + } + ] +} + +// Rifle upgrades +Class.musket = { + PARENT: "genericTank", + LABEL: "Musket", + DANGER: 7, + BODY: { + FOV: base.FOV * 1.225 + }, + GUNS: [ + { + POSITION: [16, 19, 1, 0, 0, 0, 0], + }, + { + POSITION: [18, 7, 1, 0, 4, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.rifle, g.twin]), + TYPE: "bullet" + } + }, + { + POSITION: [18, 7, 1, 0, -4, 0, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.rifle, g.twin]), + TYPE: "bullet" + } + } + ] +} +Class.crossbow = { + PARENT: "genericTank", + LABEL: "Crossbow", + DANGER: 7, + BODY: { + FOV: base.FOV * 1.225 + }, + GUNS: [ + { + POSITION: [12.5, 2.5, 1, 0, 3.5, 35, 1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.rifle, g.crossbow, { recoil: 0.5 }]), + TYPE: "bullet" + } + }, + { + POSITION: [12.5, 2.5, 1, 0, -3.5, -35, 1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.rifle, g.crossbow, { recoil: 0.5 }]), + TYPE: "bullet" + } + }, + { + POSITION: [15, 2.5, 1, 0, 3.5, 35/2, 2/3], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.rifle, g.crossbow, { recoil: 0.5 }]), + TYPE: "bullet" + } + }, + { + POSITION: [15, 2.5, 1, 0, -3.5, -35/2, 2/3], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.rifle, g.crossbow, { speed: 0.7, maxSpeed: 0.7 }, { recoil: 0.5 }]), + TYPE: "bullet" + } + }, + { + POSITION: [20, 3.5, 1, 0, 4, 0, 1/3], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.rifle, g.crossbow, { speed: 0.7, maxSpeed: 0.7 }, { recoil: 0.5 }]), + TYPE: "bullet" + } + }, + { + POSITION: [20, 3.5, 1, 0, -4, 0, 1/3], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.rifle, g.crossbow, { speed: 0.7, maxSpeed: 0.7 }, { recoil: 0.5 }]), + TYPE: "bullet" + } + }, + { + POSITION: [24, 7, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.rifle, g.crossbow, { speed: 0.7, maxSpeed: 0.7 }, { recoil: 0.5 }]), + TYPE: "bullet" + } + } + ] +} +// Marksman upgrades +Class.deadeye = { + PARENT: "genericTank", + LABEL: "Deadeye", + DANGER: 7, + BODY: { + SPEED: 0.85 * base.SPEED, + FOV: 1.4 * base.FOV + }, + GUNS: [ + { + POSITION: { + LENGTH: 5, + WIDTH: 8, + ASPECT: 1.3, + X: 10 + } + }, + { + POSITION: { + LENGTH: 5, + WIDTH: 8, + ASPECT: 1.3, + X: 15 + } + }, + { + POSITION: { + LENGTH: 23, + WIDTH: 8, + }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.assassin, { pen: 2 }]), + TYPE: "bullet" + } + }, + { + POSITION: [5, 8, -1.4, 8, 0, 0, 0] + } + ] +} +Class.nimrod = { + PARENT: "genericTank", + LABEL: "Nimrod", + DANGER: 7, + BODY: { + SPEED: base.SPEED * 0.9, + FOV: base.FOV * 1.25 + }, + CONTROLLERS: ["zoom"], + TOOLTIP: "Hold right click to zoom.", + GUNS: [ + { + POSITION: { + LENGTH: 5, + WIDTH: 12, + ASPECT: 1.25, + X: 8 + } + }, + { + POSITION: { + LENGTH: 5, + WIDTH: 12, + ASPECT: 1.25, + X: 13 + } + }, + { + POSITION: { + LENGTH: 24, + WIDTH: 8 + }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.hunterSecondary, { pen: 2 }]), + TYPE: "bullet" + } + }, + { + POSITION: { + LENGTH: 21, + WIDTH: 12, + DELAY: 0.25 + }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, { pen: 2 }]), + TYPE: "bullet" + } + } + ] +} +Class.revolver = { + PARENT: "genericTank", + LABEL: "Revolver", + DANGER: 7, + BODY: { + FOV: base.FOV * 1.225 + }, + GUNS: [ + { + POSITION: { + LENGTH: 5, + WIDTH: 12, + ASPECT: 1.25, + X: 8 + } + }, + { + POSITION: { + LENGTH: 5, + WIDTH: 12, + ASPECT: 1.25, + X: 13 + } + }, + { + POSITION: { + LENGTH: 20, + WIDTH: 12 + } + }, + { + POSITION: { + LENGTH: 24, + WIDTH: 7 + }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.rifle, { pen: 2 }]), + TYPE: "bullet" + } + } + ] +} +Class.fork = { + PARENT: "genericTank", + LABEL: "Fork", + DANGER: 7, + BODY: { + FOV: 1.2 * base.FOV + }, + GUNS: [ + { + POSITION: { + LENGTH: 5, + WIDTH: 8.5, + ASPECT: 1.3, + X: 8 + } + }, + { + POSITION: { + LENGTH: 5, + WIDTH: 8.5, + ASPECT: 1.3, + X: 13 + } + }, + { + POSITION: { + LENGTH: 5, + WIDTH: 8.5, + ASPECT: 1.3, + X: 18 + } + }, + { + POSITION: { + LENGTH: 5, + WIDTH: 8.5, + ASPECT: 1.3, + X: 23 + } + }, + { + POSITION: { + LENGTH: 29, + WIDTH: 8.5 + }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, { pen: 2, reload: 3.5 }]), + TYPE: "forkSplitterBullet" + } + } + ] +} + +// Machine Gun upgrades +Class.minigun = { + PARENT: "genericTank", + LABEL: "Minigun", + DANGER: 6, + BODY: { + FOV: base.FOV * 1.2 + }, + GUNS: [ + { + POSITION: [21, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun]), + TYPE: "bullet" + } + }, + { + POSITION: [19, 8, 1, 0, 0, 0, 1/3], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun]), + TYPE: "bullet" + } + }, + { + POSITION: [17, 8, 1, 0, 0, 0, 2/3], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun]), + TYPE: "bullet" + } + } + ] +} +Class.gunner = { + PARENT: "genericTank", + LABEL: "Gunner", + DANGER: 6, + GUNS: [ + { + POSITION: [12, 3.5, 1, 0, 7.25, 0, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.gunner, { speed: 1.2 }]), + TYPE: "bullet" + } + }, + { + POSITION: [12, 3.5, 1, 0, -7.25, 0, 0.75], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.gunner, { speed: 1.2 }]), + TYPE: "bullet" + } + }, + { + POSITION: [16, 3.5, 1, 0, 3.75, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.gunner, { speed: 1.2 }]), + TYPE: "bullet" + } + }, + { + POSITION: [16, 3.5, 1, 0, -3.75, 0, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.gunner, { speed: 1.2 }]), + TYPE: "bullet" + } + } + ] +} +Class.sprayer = { + PARENT: "genericTank", + LABEL: "Sprayer", + DANGER: 6, + GUNS: [ + { + POSITION: [23, 7, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.lowPower, g.pelleter, { recoil: 1.15 }]), + TYPE: "bullet" + } + }, + { + POSITION: [12, 10, 1.4, 8, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun]), + TYPE: "bullet" + } + } + ] +} + +// Minigun upgrades +Class.streamliner = { + PARENT: "genericTank", + LABEL: "Streamliner", + DANGER: 7, + BODY: { + FOV: 1.3, + }, + GUNS: [ + { + POSITION: [25, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.streamliner]), + TYPE: "bullet", + }, + }, + { + POSITION: [23, 8, 1, 0, 0, 0, 0.2], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.streamliner]), + TYPE: "bullet", + }, + }, + { + POSITION: [21, 8, 1, 0, 0, 0, 0.4], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.streamliner]), + TYPE: "bullet", + }, + }, + { + POSITION: [19, 8, 1, 0, 0, 0, 0.6], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.streamliner]), + TYPE: "bullet", + }, + }, + { + POSITION: [17, 8, 1, 0, 0, 0, 0.8], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.streamliner]), + TYPE: "bullet", + }, + }, + ], +} +Class.barricade = { + PARENT: "genericTank", + DANGER: 7, + LABEL: "Barricade", + STAT_NAMES: statnames.trap, + BODY: { + FOV: 1.15, + }, + GUNS: [ + { + POSITION: [24, 8, 1, 0, 0, 0, 0], + }, + { + POSITION: [4, 8, 1.3, 22, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, g.minigun, { range: 0.5 }]), + TYPE: "trap", + STAT_CALCULATOR: "trap", + }, + }, + { + POSITION: [4, 8, 1.3, 18, 0, 0, 1/3], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, g.minigun, { range: 0.5 }]), + TYPE: "trap", + STAT_CALCULATOR: "trap", + }, + }, + { + POSITION: [4, 8, 1.3, 14, 0, 0, 2/3], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, g.minigun, { range: 0.5 }]), + TYPE: "trap", + STAT_CALCULATOR: "trap", + }, + }, + ], +} + +// Gunner upgrades +Class.nailgun = { + PARENT: "genericTank", + LABEL: "Nailgun", + DANGER: 7, + BODY: { + FOV: base.FOV * 1.1, + SPEED: base.SPEED * 0.9, + }, + GUNS: [ + { + POSITION: [19, 2, 1, 0, -2.5, 0, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.power, g.twin, g.nailgun]), + TYPE: "bullet", + }, + }, + { + POSITION: [19, 2, 1, 0, 2.5, 0, 0.75], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.power, g.twin, g.nailgun]), + TYPE: "bullet", + }, + }, + { + POSITION: [20, 2, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.power, g.twin, g.nailgun]), + TYPE: "bullet", + }, + }, + { + POSITION: [5.5, 7, -1.8, 6.5, 0, 0, 0], + }, + ], +} +Class.machineGunner = { + PARENT: "genericTank", + LABEL: "Machine Gunner", + DANGER: 7, + BODY: { + SPEED: 0.9 * base.SPEED, + }, + GUNS: [ + { + POSITION: [14, 3, 4, -3, 5, 0, 0.6], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.gunner, g.machineGunner]), + TYPE: "bullet", + }, + }, + { + POSITION: [14, 3, 4, -3, -5, 0, 0.8], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.gunner, g.machineGunner]), + TYPE: "bullet", + }, + }, + { + POSITION: [14, 3, 4, 0, 2.5, 0, 0.4], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.gunner, g.machineGunner]), + TYPE: "bullet", + }, + }, + { + POSITION: [14, 3, 4, 0, -2.5, 0, 0.2], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.gunner, g.machineGunner]), + TYPE: "bullet", + }, + }, + { + POSITION: [14, 3, 4, 3, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.gunner, g.machineGunner]), + TYPE: "bullet", + }, + }, + ], +} + +// Sprayer upgrades +Class.redistributor = { + PARENT: "genericTank", + LABEL: "Redistributor", + DANGER: 7, + GUNS: [ + { + POSITION: [26, 7, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.lowPower, g.machineGun, { recoil: 1.15 }]), + TYPE: "bullet", + }, + }, + { + POSITION: [23, 10, 1, 0, 0, 0, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.lowPower, g.machineGun, { recoil: 1.15 }]), + TYPE: "bullet", + }, + }, + { + POSITION: [12, 10, 1.4, 8, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun]), + TYPE: "bullet", + }, + }, + ], +} +Class.atomizer = { + PARENT: "genericTank", + LABEL: "Atomizer", + DANGER: 7, + GUNS: [ + { + POSITION: [5, 7.5, 1.3, 18.5, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.lowPower, g.machineGun, { recoil: 1.15 }, g.atomizer]), + TYPE: "bullet", + }, + }, + { + POSITION: [12, 10, 1.4, 8, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun]), + TYPE: "bullet", + }, + }, + ], +} +Class.focal = { + PARENT: "genericTank", + LABEL: "Focal", + DANGER: 7, + GUNS: [ + { + POSITION: [25, 7, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.lowPower, g.machineGun, { recoil: 1.15 }]), + TYPE: "bullet", + }, + }, + { + POSITION: [14, 10, 1.3, 8, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.focal]), + TYPE: "bullet", + }, + }, + ], +} + +// Flank Guard upgrades +Class.hexaTank = { + PARENT: "genericTank", + LABEL: "Hexa Tank", + DANGER: 6, + GUNS: weaponArray({ + POSITION: [18, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.flankGuard]), + TYPE: "bullet" + } + }, 6, 0.5) +} +Class.triAngle = { + PARENT: "genericTank", + LABEL: "Tri-Angle", + BODY: { + HEALTH: 0.8 * base.HEALTH, + SHIELD: 0.8 * base.SHIELD, + DENSITY: 0.6 * base.DENSITY, + }, + DANGER: 6, + GUNS: [ + { + POSITION: [18, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.triAngleFront, { recoil: 4 }]), + TYPE: "bullet", + LABEL: "Front", + }, + }, + { + POSITION: [16, 8, 1, 0, 0, 150, 0.1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), + TYPE: "bullet", + LABEL: "thruster", + }, + }, + { + POSITION: [16, 8, 1, 0, 0, 210, 0.1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), + TYPE: "bullet", + LABEL: "thruster", + }, + }, + ], +} +Class.auto3 = makeRadialAuto("autoTankGun", {isTurret: true, danger: 6, label: "Auto-3"}) + +// Hexa Tank upgrades +Class.octoTank = { + PARENT: "genericTank", + LABEL: "Octo Tank", + DANGER: 7, + GUNS: weaponArray([ + // Must be kept like this to preserve visual layering + { + POSITION: [18, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.flankGuard, g.spam]), + TYPE: "bullet" + } + }, + { + POSITION: [18, 8, 1, 0, 0, 45, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.flankGuard, g.spam]), + TYPE: "bullet" + } + } + ], 4) +} +Class.cyclone = { + PARENT: "genericTank", + LABEL: "Cyclone", + DANGER: 7, + GUNS: weaponArray([ + { + POSITION: [15, 3.5, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.gunner, g.cyclone]), + TYPE: "bullet" + } + }, + { + POSITION: [15, 3.5, 1, 0, 0, 30, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.gunner, g.cyclone]), + TYPE: "bullet" + } + }, + { + POSITION: [15, 3.5, 1, 0, 0, 60, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.gunner, g.cyclone]), + TYPE: "bullet" + } + }, + { + POSITION: [15, 3.5, 1, 0, 0, 90, 0.75], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.gunner, g.cyclone]), + TYPE: "bullet" + } + } + ], 3) +} + +// Tri-Angle upgrades +Class.fighter = { + PARENT: "genericTank", + LABEL: "Fighter", + BODY: { + DENSITY: 0.6 * base.DENSITY, + }, + DANGER: 7, + GUNS: [ + { + POSITION: [18, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.triAngleFront, { recoil: 4 }]), + TYPE: "bullet", + LABEL: "Front", + }, + }, + { + POSITION: [16, 8, 1, 0, -1, 90, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.triAngleFront]), + TYPE: "bullet", + LABEL: "Side", + }, + }, + { + POSITION: [16, 8, 1, 0, 1, -90, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.triAngleFront]), + TYPE: "bullet", + LABEL: "Side", + }, + }, + { + POSITION: [16, 8, 1, 0, 0, 150, 0.1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), + TYPE: "bullet", + LABEL: "thruster", + }, + }, + { + POSITION: [16, 8, 1, 0, 0, 210, 0.1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), + TYPE: "bullet", + LABEL: "thruster", + }, + }, + ], +} +Class.booster = { + PARENT: "genericTank", + LABEL: "Booster", + BODY: { + HEALTH: base.HEALTH * 0.4, + SHIELD: base.SHIELD * 0.4, + DENSITY: base.DENSITY * 0.3 + }, + DANGER: 7, + GUNS: [ + { + POSITION: [18, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.triAngleFront, { recoil: 4 }]), + TYPE: "bullet", + LABEL: "Front" + } + }, + { + POSITION: [14, 8, 1, 0, -1, 140, 0.6], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), + TYPE: "bullet", + LABEL: "thruster" + } + }, + { + POSITION: [14, 8, 1, 0, 1, -140, 0.6], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), + TYPE: "bullet", + LABEL: "thruster" + } + }, + { + POSITION: [16, 8, 1, 0, 0, 150, 0.1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), + TYPE: "bullet", + LABEL: "thruster" + } + }, + { + POSITION: [16, 8, 1, 0, 0, -150, 0.1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), + TYPE: "bullet", + LABEL: "thruster" + } + } + ] +} +Class.surfer = { + PARENT: "genericTank", + LABEL: "Surfer", + BODY: { + DENSITY: 0.6 * base.DENSITY, + }, + DANGER: 7, + GUNS: [ + { + POSITION: [18, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.triAngleFront]), + TYPE: "bullet", + LABEL: "Front", + }, + }, + { + POSITION: [7, 7.5, 0.6, 7, -1, 90, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.swarm]), + TYPE: "autoswarm", + STAT_CALCULATOR: "swarm", + }, + }, + { + POSITION: [7, 7.5, 0.6, 7, 1, -90, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.swarm]), + TYPE: "autoswarm", + STAT_CALCULATOR: "swarm", + }, + }, + { + POSITION: [16, 8, 1, 0, 0, 150, 0.1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), + TYPE: "bullet", + LABEL: "thruster", + }, + }, + { + POSITION: [16, 8, 1, 0, 0, 210, 0.1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), + TYPE: "bullet", + LABEL: "thruster", + }, + }, + ], +} + +// Auto-3 upgrades +Class.auto5 = makeRadialAuto("autoTankGun", {isTurret: true, danger: 7, label: "Auto-5", count: 5}) +Class.mega3 = makeRadialAuto("megaAutoTankGun", {isTurret: true, danger: 7, size: 14, label: "Mega-3", body: {SPEED: 0.95 * base.SPEED}}) +Class.auto4 = makeRadialAuto("auto4gun", {isTurret: true, danger: 7, size: 13, x: 6, angle: 45, label: "Auto-4", count: 4}) +Class.banshee = makeRadialAuto("bansheegun", {isTurret: true, danger: 7, size: 10, arc: 80, label: "Banshee", body: {SPEED: 0.8 * base.SPEED, FOV: 1.1 * base.FOV}}) +Class.banshee.GUNS = weaponArray({ + POSITION: [6, 11, 1.2, 8, 0, 60, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, g.overseer]), + TYPE: "drone", + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "drone", + WAIT_TO_CYCLE: true, + MAX_CHILDREN: 2, + }, +}, 3) + +// Director upgrades +Class.overseer = { + PARENT: "genericTank", + LABEL: "Overseer", + DANGER: 6, + STAT_NAMES: statnames.drone, + BODY: { + SPEED: 0.9 * base.SPEED, + FOV: 1.1 * base.FOV, + }, + MAX_CHILDREN: 8, + GUNS: weaponArray({ + POSITION: [6, 12, 1.2, 8, 0, 90, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, g.overseer]), + TYPE: "drone", + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "drone", + WAIT_TO_CYCLE: true + } + }, 2) +} +Class.cruiser = { + PARENT: "genericTank", + LABEL: "Cruiser", + DANGER: 6, + FACING_TYPE: "locksFacing", + STAT_NAMES: statnames.swarm, + BODY: { + FOV: 1.2 * base.FOV, + }, + GUNS: [ + { + POSITION: [7, 7.5, 0.6, 7, 4, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.swarm]), + TYPE: "swarm", + STAT_CALCULATOR: "swarm", + }, + }, + { + POSITION: [7, 7.5, 0.6, 7, -4, 0, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.swarm]), + TYPE: "swarm", + STAT_CALCULATOR: "swarm", + }, + }, + ], +} +Class.underseer = { + PARENT: "genericTank", + LABEL: "Underseer", + DANGER: 6, + NECRO: true, + STAT_NAMES: statnames.drone, + BODY: { + SPEED: base.SPEED * 0.9, + FOV: base.FOV * 1.1, + }, + SHAPE: 4, + MAX_CHILDREN: 14, + GUNS: weaponArray({ + POSITION: [5.25, 12, 1.2, 8, 0, 90, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, g.sunchip, {reload: 0.8}]), + TYPE: "sunchip", + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "necro", + WAIT_TO_CYCLE: true, + DELAY_SPAWN: false, + } + }, 2) +} +Class.spawner = { + PARENT: "genericTank", + LABEL: "Spawner", + DANGER: 6, + STAT_NAMES: statnames.drone, + BODY: { + SPEED: base.SPEED * 0.8, + FOV: 1.1, + }, + GUNS: [ + { + POSITION: [4.5, 10, 1, 10.5, 0, 0, 0], + }, + { + POSITION: [1, 12, 1, 15, 0, 0, 0], + PROPERTIES: { + MAX_CHILDREN: 4, + SHOOT_SETTINGS: combineStats([g.factory, g.babyfactory]), + TYPE: "minion", + STAT_CALCULATOR: "drone", + AUTOFIRE: true, + SYNCS_SKILLS: true, + }, + }, + { + POSITION: [11.5, 12, 1, 0, 0, 0, 0], + }, + ], +} +Class.manager = { + PARENT: "genericTank", + LABEL: "Manager", + DANGER: 7, + STAT_NAMES: statnames.drone, + BODY: { + SPEED: 0.85 * base.SPEED, + FOV: 1.1 * base.FOV, + }, + INVISIBLE: [0.08, 0.03], + TOOLTIP: "Stay still to turn invisible.", + MAX_CHILDREN: 8, + GUNS: [ + { + POSITION: [6, 12, 1.2, 8, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, g.overseer, { reload: 0.5 }]), + TYPE: "drone", + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "drone", + }, + }, + ], +} +Class.bigCheese = { + PARENT: "genericTank", + LABEL: "Big Cheese", + STAT_NAMES: statnames.drone, + DANGER: 7, + BODY: { + FOV: base.FOV * 1.1, + }, + GUNS: [ + { + POSITION: [16, 16, 1.4, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, g.bigCheese]), + TYPE: "drone", + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "drone", + MAX_CHILDREN: 1, + }, + }, + ], +} + +// Overseer upgrades +Class.overlord = { + PARENT: "genericTank", + LABEL: "Overlord", + DANGER: 7, + STAT_NAMES: statnames.drone, + BODY: { + SPEED: 0.8 * base.SPEED, + FOV: 1.1 * base.FOV, + }, + MAX_CHILDREN: 8, + GUNS: weaponArray({ + POSITION: [6, 12, 1.2, 8, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, g.overseer]), + TYPE: "drone", + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "drone", + WAIT_TO_CYCLE: true + } + }, 4) +} +Class.overdrive = { + PARENT: "genericTank", + LABEL: "Overdrive", + DANGER: 7, + STAT_NAMES: statnames.drone, + BODY: { + SPEED: 0.9 * base.SPEED, + FOV: 1.1 * base.FOV, + }, + TURRETS: [ + { + POSITION: [9, 0, 0, 0, 360, 1], + TYPE: "overdriveDeco", + }, + ], + GUNS: weaponArray({ + POSITION: [6, 12, 1.2, 8, 0, 90, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, g.overseer]), + TYPE: "turretedDrone", + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "drone", + WAIT_TO_CYCLE: true, + MAX_CHILDREN: 4 + } + }, 2) +} +Class.commander = { + PARENT: "genericTank", + LABEL: "Commander", + STAT_NAMES: statnames.drone, + DANGER: 7, + BODY: { + FOV: base.FOV * 1.15, + }, + GUNS: [ + ...weaponArray({ + POSITION: [8, 11, 1.3, 6, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone]), + TYPE: "drone", + AUTOFIRE: true, + SYNCS_SKILLS: true, + MAX_CHILDREN: 2, + STAT_CALCULATOR: "drone", + }, + }, 3), + ...weaponArray({ + POSITION: [7, 7.5, 0.6, 7, 0, 60, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.swarm, g.commander]), + TYPE: "swarm", + STAT_CALCULATOR: "swarm", + }, + }, 3, 1/3), + ] +} + +// Cruiser upgrades +Class.carrier = { + PARENT: "genericTank", + LABEL: "Carrier", + DANGER: 7, + STAT_NAMES: statnames.swarm, + FACING_TYPE: "locksFacing", + BODY: { + FOV: base.FOV * 1.2, + }, + GUNS: [ + { + POSITION: [7, 8, 0.6, 7, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.swarm, g.battleship, g.carrier]), + TYPE: "swarm", + STAT_CALCULATOR: "swarm", + }, + }, + { + POSITION: [7, 8, 0.6, 7, 2, 30, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.swarm, g.battleship, g.carrier]), + TYPE: "swarm", + STAT_CALCULATOR: "swarm", + }, + }, + { + POSITION: [7, 8, 0.6, 7, -2, -30, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.swarm, g.battleship, g.carrier]), + TYPE: "swarm", + STAT_CALCULATOR: "swarm", + }, + }, + ], +} +Class.battleship = { + PARENT: "genericTank", + LABEL: "Battleship", + DANGER: 7, + STAT_NAMES: statnames.swarm, + FACING_TYPE: "locksFacing", + BODY: { + FOV: 1.2 * base.FOV + }, + GUNS: [ + { + POSITION: [7, 7.5, 0.6, 7, 4, 90, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.swarm, g.battleship]), + TYPE: "swarm", + STAT_CALCULATOR: "swarm", + LABEL: "Guided" + } + }, + { + POSITION: [7, 7.5, 0.6, 7, -4, 90, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.swarm]), + TYPE: "autoswarm", + STAT_CALCULATOR: "swarm", + LABEL: "Autonomous" + } + }, + { + POSITION: [7, 7.5, 0.6, 7, 4, 270, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.swarm]), + TYPE: "autoswarm", + STAT_CALCULATOR: "swarm", + LABEL: "Autonomous" + } + }, + { + POSITION: [7, 7.5, 0.6, 7, -4, 270, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.swarm, g.battleship]), + TYPE: "swarm", + STAT_CALCULATOR: "swarm", + LABEL: "Guided" + } + } + ] +} +Class.fortress = { + PARENT: "genericTank", + LABEL: "Fortress", + DANGER: 7, + STAT_NAMES: statnames.mixed, + BODY: { + SPEED: 0.8 * base.SPEED, + FOV: 1.2 * base.FOV, + }, + GUNS: [ + ...weaponArray( + { + POSITION: [7, 7.5, 0.6, 7, 0, 60, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.swarm]), + TYPE: "swarm", + STAT_CALCULATOR: "swarm", + }, + }, 3, 1/3), + ...weaponArray([ + { + POSITION: [14, 9, 1, 0, 0, 0, 0], + }, + { + POSITION: [4, 9, 1.5, 14, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, { range: 0.5, speed: 0.7, maxSpeed: 0.7 }]), + TYPE: "trap", + STAT_CALCULATOR: "trap", + }, + } + ], 3) + ], +} + +// Underseer upgrades +Class.necromancer = { + PARENT: "genericTank", + LABEL: "Necromancer", + DANGER: 7, + NECRO: true, + STAT_NAMES: statnames.necro, + BODY: { + SPEED: 0.8 * base.SPEED, + FOV: base.FOV * 1.1, + }, + SHAPE: 4, + MAX_CHILDREN: 14, + GUNS: weaponArray({ + POSITION: [5.25, 12, 1.2, 8, 0, 0, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, g.sunchip]), + TYPE: "sunchip", + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "necro", + WAIT_TO_CYCLE: true, + DELAY_SPAWN: false, + }, + }, 4, 0.75), +} +Class.maleficitor = { + PARENT: "genericTank", + LABEL: "Maleficitor", + DANGER: 7, + NECRO: true, + TOOLTIP: "Press R and wait to turn your drones invisible.", + STAT_NAMES: statnames.necro, + BODY: { + SPEED: base.SPEED * 0.85, + FOV: base.FOV * 1.1, + }, + SHAPE: 4, + MAX_CHILDREN: 20, + GUNS: [ + { + POSITION: [5.25, 12, 1.2, 8, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, g.sunchip, g.maleficitor]), + TYPE: [ + "sunchip", + { + INVISIBLE: [0.06, 0.03], + }, + ], + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "necro", + WAIT_TO_CYCLE: true, + DELAY_SPAWN: false, + }, + }, + ], +} +Class.infestor = { + PARENT: "genericTank", + LABEL: "Infestor", + DANGER: 7, + NECRO: true, + STAT_NAMES: statnames.drone, + BODY: { + SPEED: base.SPEED * 0.9, + FOV: base.FOV * 1.1, + }, + MAX_CHILDREN: 20, + GUNS: weaponArray([ + { + POSITION: [7.25, 6, 1.2, 6, -5, 90, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, g.sunchip, {reload: 0.5}]), + TYPE: "eggchip", + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "necro", + WAIT_TO_CYCLE: true, + DELAY_SPAWN: false, + } + }, + { + POSITION: [7.25, 6, 1.2, 6, 5, 90, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, g.sunchip, {reload: 0.5}]), + TYPE: "eggchip", + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "necro", + WAIT_TO_CYCLE: true, + DELAY_SPAWN: false, + } + } + ], 2) +} + +// Spawner upgrades +Class.factory = { + PARENT: "genericTank", + LABEL: "Factory", + DANGER: 7, + STAT_NAMES: statnames.drone, + BODY: { + SPEED: base.SPEED * 0.8, + FOV: 1.1, + }, + GUNS: [ + { + POSITION: [5, 11, 1, 10.5, 0, 0, 0], + }, + { + POSITION: [2, 14, 1, 15.5, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.factory]), + TYPE: "minion", + MAX_CHILDREN: 6, + STAT_CALCULATOR: "drone", + AUTOFIRE: true, + SYNCS_SKILLS: true, + }, + }, + { + POSITION: [12, 14, 1, 0, 0, 0, 0], + }, + ], +} + +// Pounder upgrades +Class.destroyer = { + PARENT: "genericTank", + LABEL: "Destroyer", + DANGER: 6, + GUNS: [ + { + POSITION: [21, 14, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.destroyer]), + TYPE: "bullet", + }, + }, + ], +} +Class.artillery = { + PARENT: "genericTank", + LABEL: "Artillery", + DANGER: 6, + GUNS: [ + { + POSITION: [17, 3, 1, 0, -6, -7, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery]), + TYPE: "bullet", + LABEL: "Secondary", + }, + }, + { + POSITION: [17, 3, 1, 0, 6, 7, 0.75], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery]), + TYPE: "bullet", + LABEL: "Secondary", + }, + }, + { + POSITION: [19, 12, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.artillery]), + TYPE: "bullet", + LABEL: "Heavy", + }, + }, + ], +} +Class.launcher = { + PARENT: "genericTank", + LABEL: "Launcher", + DANGER: 6, + BODY: { + FOV: base.FOV * 1.1, + }, + GUNS: [ + { + POSITION: [10, 9, 1, 9, 0, 0, 0], + }, + { + POSITION: [17, 13, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.launcher]), + TYPE: "minimissile", + STAT_CALCULATOR: "sustained", + }, + }, + ], +} +Class.shotgun = { + PARENT: "genericTank", + LABEL: "Shotgun", + DANGER: 7, + GUNS: [ + { + POSITION: [4, 3, 1, 11, -3, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.shotgun]), + TYPE: "bullet", + }, + }, + { + POSITION: [4, 3, 1, 11, 3, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.shotgun]), + TYPE: "bullet", + }, + }, + { + POSITION: [4, 4, 1, 13, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.shotgun]), + TYPE: "casing", + }, + }, + { + POSITION: [1, 4, 1, 12, -1, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.shotgun]), + TYPE: "casing", + }, + }, + { + POSITION: [1, 4, 1, 11, 1, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.shotgun]), + TYPE: "casing", + }, + }, + { + POSITION: [1, 3, 1, 13, -1, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.shotgun]), + TYPE: "bullet", + }, + }, + { + POSITION: [1, 3, 1, 13, 1, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.shotgun]), + TYPE: "bullet", + }, + }, + { + POSITION: [1, 2, 1, 13, 2, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.shotgun]), + TYPE: "casing", + }, + }, + { + POSITION: [1, 2, 1, 13, -2, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.shotgun]), + TYPE: "casing", + }, + }, + { + POSITION: [15, 14, 1, 6, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.shotgun, g.fake]), + TYPE: "casing", + }, + }, + { + POSITION: [8, 14, -1.3, 4, 0, 0, 0], + }, + ], +} + +// Destroyer upgrades +Class.annihilator = { + PARENT: "genericTank", + LABEL: "Annihilator", + DANGER: 7, + GUNS: [ + { + POSITION: [20.5, 19.5, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.destroyer, g.annihilator]), + TYPE: "bullet", + }, + }, + ], +} + +// Artillery upgrades +Class.mortar = { + PARENT: "genericTank", + LABEL: "Mortar", + DANGER: 7, + GUNS: [ + { + POSITION: [13, 3, 1, 0, -8, -7, 0.6], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery, g.twin]), + TYPE: "bullet", + LABEL: "Secondary", + }, + }, + { + POSITION: [13, 3, 1, 0, 8, 7, 0.8], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery, g.twin]), + TYPE: "bullet", + LABEL: "Secondary", + }, + }, + { + POSITION: [17, 3, 1, 0, -6, -7, 0.2], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery, g.twin]), + TYPE: "bullet", + LABEL: "Secondary", + }, + }, + { + POSITION: [17, 3, 1, 0, 6, 7, 0.4], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery, g.twin]), + TYPE: "bullet", + LABEL: "Secondary", + }, + }, + { + POSITION: [19, 12, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.artillery]), + TYPE: "bullet", + LABEL: "Heavy", + }, + }, + ], +} +Class.ordnance = { + PARENT: "genericTank", + LABEL: "Ordnance", + DANGER: 7, + BODY: { + SPEED: base.SPEED * 0.9, + FOV: base.FOV * 1.25, + }, + CONTROLLERS: ["zoom"], + TOOLTIP: "Hold right click to zoom.", + GUNS: [ + { + POSITION: [17, 3, 1, 0, -5.75, -6, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery]), + TYPE: "bullet", + LABEL: "Secondary", + }, + }, + { + POSITION: [17, 3, 1, 0, 5.75, 6, 0.75], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery]), + TYPE: "bullet", + LABEL: "Secondary", + }, + }, + { + POSITION: [24, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter, g.hunterSecondary]), + TYPE: "bullet", + }, + }, + { + POSITION: [21, 11, 1, 0, 0, 0, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.hunter]), + TYPE: "bullet", + }, + }, + ], +} +Class.beekeeper = { + PARENT: "genericTank", + LABEL: "Beekeeper", + DANGER: 7, + GUNS: [ + { + POSITION: [14, 3, 1, 0, -6, -7, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.swarm, g.bee]), + TYPE: ["bee", { INDEPENDENT: true }], + SYNCS_SKILLS: true, + STAT_CALCULATOR: "drone", + WAIT_TO_CYCLE: true, + LABEL: "Secondary", + }, + }, + { + POSITION: [14, 3, 1, 0, 6, 7, 0.75], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.swarm, g.bee]), + TYPE: ["bee", { INDEPENDENT: true }], + SYNCS_SKILLS: true, + STAT_CALCULATOR: "drone", + WAIT_TO_CYCLE: true, + LABEL: "Secondary", + }, + }, + { + POSITION: [19, 12, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.artillery]), + TYPE: "bullet", + LABEL: "Heavy", + }, + }, + ], +} +Class.fieldGun = { + PARENT: "genericTank", + LABEL: "Field Gun", + BODY: { + FOV: base.FOV * 1.1, + }, + DANGER: 7, + GUNS: [ + { + POSITION: [15, 3, 1, 0, -6, -7, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery]), + TYPE: "bullet", + LABEL: "Secondary", + }, + }, + { + POSITION: [15, 3, 1, 0, 6, 7, 0.75], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery]), + TYPE: "bullet", + LABEL: "Secondary", + }, + }, + { + POSITION: [10, 9, 1, 9, 0, 0, 0], + }, + { + POSITION: [17, 13, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.artillery, g.artillery]), + TYPE: "minimissile", + STAT_CALCULATOR: "sustained", + }, + }, + ], +} + +// Launcher upgrades +Class.skimmer = { + PARENT: "genericTank", + LABEL: "Skimmer", + DANGER: 7, + BODY: { + FOV: 1.15 * base.FOV, + }, + GUNS: [ + { + POSITION: [10, 14, -0.5, 9, 0, 0, 0], + }, + { + POSITION: [17, 15, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.artillery, g.artillery, g.skimmer]), + TYPE: "missile", + STAT_CALCULATOR: "sustained", + }, + }, + ], +} +Class.twister = { + PARENT: "genericTank", + LABEL: "Twister", + TOOLTIP: "Hold right click to reverse missile rotation.", + DANGER: 7, + BODY: { + FOV: 1.1 * base.FOV, + }, + GUNS: [ + { + POSITION: [10, 13, -0.5, 9, 0, 0, 0], + }, + { + POSITION: [17, 14, -1.4, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.artillery, g.artillery, g.skimmer, { reload: 4/3 }]), + TYPE: "spinmissile", + STAT_CALCULATOR: "sustained", + }, + }, + ], +} +Class.swarmer = { + PARENT: "genericTank", + DANGER: 7, + LABEL: "Swarmer", + GUNS: [ + { + POSITION: [15, 14, -1.2, 5, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.destroyer, g.hive]), + TYPE: "hive", + }, + }, + { + POSITION: [15, 12, 1, 5, 0, 0, 0], + }, + ], +} +Class.rocketeer = { + PARENT: "genericTank", + LABEL: "Rocketeer", + BODY: { + FOV: 1.15 * base.FOV, + }, + DANGER: 7, + GUNS: [ + { + POSITION: [10, 12.5, -0.7, 10, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.launcher, g.rocketeer]), + TYPE: "rocketeerMissile", + STAT_CALCULATOR: "sustained", + }, + }, + { + POSITION: [17, 18, 0.65, 0, 0, 0, 0], + }, + ], +} + +// Trapper upgrades +Class.builder = { + PARENT: "genericTank", + LABEL: "Builder", + DANGER: 6, + STAT_NAMES: statnames.trap, + BODY: { + SPEED: 0.8 * base.SPEED, + FOV: 1.15 * base.FOV + }, + GUNS: [ + { + POSITION: [18, 12, 1, 0, 0, 0, 0], + }, + { + POSITION: [2, 12, 1.1, 18, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, g.setTrap]), + TYPE: "setTrap", + STAT_CALCULATOR: "block" + } + } + ] +} +Class.triTrapper = { + PARENT: "genericTank", + LABEL: "Tri-Trapper", + DANGER: 6, + STAT_NAMES: statnames.trap, + GUNS: weaponArray([ + { + POSITION: [15, 7, 1, 0, 0, 0, 0], + }, + { + POSITION: [3, 7, 1.7, 15, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, g.flankGuard]), + TYPE: "trap", + STAT_CALCULATOR: "trap" + } + } + ], 3) +} +Class.trapGuard = makeGuard({ + PARENT: "genericTank", + LABEL: "Trap", + STAT_NAMES: statnames.mixed, + GUNS: [ + { + POSITION: [20, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.flankGuard]), + TYPE: "bullet" + } + } + ] +}) + +// Builder upgrades +Class.construct = { // it's "construct" and not "constructor" because "constructor" breaks things + PARENT: "genericTank", + LABEL: "Constructor", + STAT_NAMES: statnames.trap, + DANGER: 7, + BODY: { + SPEED: 0.7 * base.SPEED, + FOV: 1.15 * base.FOV + }, + GUNS: [ + { + POSITION: [18, 18, 1, 0, 0, 0, 0], + }, + { + POSITION: [2, 18, 1.2, 18, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, g.setTrap, g.construct]), + TYPE: "setTrap", + STAT_CALCULATOR: "block" + } + } + ] +} +Class.engineer = { + PARENT: "genericTank", + DANGER: 7, + LABEL: "Engineer", + STAT_NAMES: statnames.trap, + BODY: { + SPEED: 0.75 * base.SPEED, + FOV: 1.15 * base.FOV, + }, + GUNS: [ + { + POSITION: [5, 11, 1, 10.5, 0, 0, 0], + }, + { + POSITION: [3, 14, 1, 15.5, 0, 0, 0], + }, + { + POSITION: [2, 14, 1.3, 18, 0, 0, 0], + PROPERTIES: { + MAX_CHILDREN: 6, + SHOOT_SETTINGS: combineStats([g.trap, g.setTrap]), + TYPE: "pillbox", + SYNCS_SKILLS: true, + DESTROY_OLDEST_CHILD: true, + STAT_CALCULATOR: "block" + }, + }, + { + POSITION: [4, 14, 1, 8, 0, 0, 0], + }, + ], +} +Class.boomer = { + PARENT: "genericTank", + DANGER: 7, + LABEL: "Boomer", + STAT_NAMES: statnames.trap, + FACING_TYPE: "locksFacing", + BODY: { + SPEED: base.SPEED * 0.8, + FOV: base.FOV * 1.15, + }, + GUNS: [ + { + POSITION: [5, 10, 1, 13, 0, 0, 0], + }, + { + POSITION: [6, 10, -1.5, 7, 0, 0, 0], + }, + { + POSITION: [2, 10, 1.3, 18, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, g.setTrap, g.boomerang]), + TYPE: "boomerang", + STAT_CALCULATOR: "block" + }, + }, + ], +} +Class.assembler = { + PARENT: "genericTank", + DANGER: 7, + LABEL: 'Assembler', + STAT_NAMES: statnames.trap, + BODY: { + SPEED: 0.8 * base.SPEED, + FOV: 1.15 * base.FOV, + }, + GUNS: [ + { + POSITION: [18, 12, 1, 0, 0, 0, 0], + }, + { + POSITION: [2, 12, 1.1, 18, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, g.setTrap]), + TYPE: 'assemblerTrap', + MAX_CHILDREN: 8, + STAT_CALCULATOR: "block", + } + } + ], + TURRETS: [ + { + POSITION: [2.5, 14, 0, 0, 360, 1], + TYPE: 'assemblerDot' + } + ] +} +Class.ramrod = { + PARENT: "genericTank", + LABEL: "RamRod (BETA)", + DANGER: 6, + STAT_NAMES: statnames.trap, + MAX_CHILDREN: 1, + BODY: { + SPEED: 0.8 * base.SPEED, + FOV: 1.2 * base.FOV + }, + GUNS: [ + { + POSITION: [18, 12, 1, 0, 0, 0, 0], + }, { + POSITION: [2, 12, 1.1, 18, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, g.setTrap, {size: 2, health: 1.5, damage: 0.7}]), + TYPE: "ramrodTrap", + STAT_CALCULATOR: "block" + } + } + ] +} + +for (let i = 0; i < 2; i++) { + Class.ramrod.GUNS.push( + { + POSITION: [3, 3, 0.001, -5, 14 - (i * 3), -90, 0] + }, { + POSITION: [3, 3, 0.001, -5, -14 + (i * 3), 90, 0] + } + ) +} + +Class.ramrod.GUNS.push( + { + POSITION: [15, 2, 1, 0, -6, 0, 0] + }, { + POSITION: [15, 2, 1, 0, 6, 0, 0] + } +) + +// Tri-Trapper upgrades +Class.hexaTrapper = makeAuto({ + PARENT: "genericTank", + DANGER: 7, + BODY: { + SPEED: 0.8 * base.SPEED, + }, + STAT_NAMES: statnames.trap, + HAS_NO_RECOIL: true, + GUNS: weaponArray([ + { + POSITION: [15, 7, 1, 0, 0, 0, 0], + }, + { + POSITION: [3, 7, 1.7, 15, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, g.hexaTrapper]), + TYPE: "trap", + STAT_CALCULATOR: "trap", + }, + }, + ], 6, 0.5), +}, "Hexa-Trapper") +Class.septaTrapper = { + PARENT: "genericTank", + LABEL: "Septa-Trapper", + DANGER: 7, + BODY: { + SPEED: base.SPEED * 0.8, + }, + STAT_NAMES: statnames.trap, + HAS_NO_RECOIL: true, + GUNS: weaponArray([ + { + POSITION: [15, 7, 1, 0, 0, 0, 0], + }, + { + POSITION: [3, 7, 1.7, 15, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, g.hexaTrapper]), + TYPE: "trap", + STAT_CALCULATOR: "trap", + }, + }, + ], 7, 4/7), +} +Class.architect = makeRadialAuto("architectGun", {isTurret: true, danger: 7, size: 12, label: "Architect", body: {SPEED: 1.1 * base.SPEED}}) + +// Trap Guard upgrades +Class.bushwhacker = makeGuard("sniper", "Bushwhacker") +Class.gunnerTrapper = { + PARENT: "genericTank", + LABEL: "Gunner Trapper", + DANGER: 7, + STAT_NAMES: statnames.mixed, + BODY: { + FOV: 1.25 * base.FOV, + }, + GUNS: [ + { + POSITION: [19, 2, 1, 0, -2.5, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.power, g.twin, { recoil: 4 }, { recoil: 1.8 }]), + TYPE: "bullet", + }, + }, + { + POSITION: [19, 2, 1, 0, 2.5, 0, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.power, g.twin, { recoil: 4 }, { recoil: 1.8 }]), + TYPE: "bullet", + }, + }, + { + POSITION: [12, 11, 1, 0, 0, 0, 0], + }, + { + POSITION: [13, 11, 1, 0, 0, 180, 0], + }, + { + POSITION: [4, 11, 1.7, 13, 0, 180, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, { speed: 1.2 }, { recoil: 0.5 }]), + TYPE: "trap", + STAT_CALCULATOR: "trap", + }, + }, + ], +} +Class.bomber = { + PARENT: "genericTank", + LABEL: "Bomber", + BODY: { + DENSITY: base.DENSITY * 0.6, + }, + DANGER: 7, + GUNS: [ + { + POSITION: [20, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.triAngleFront]), + TYPE: "bullet", + LABEL: "Front", + }, + }, + { + POSITION: [18, 8, 1, 0, 0, 130, 0.1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle]), + TYPE: "bullet", + LABEL: "Wing", + }, + }, + { + POSITION: [18, 8, 1, 0, 0, 230, 0.1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle]), + TYPE: "bullet", + LABEL: "Wing", + }, + }, + { + POSITION: [13, 8, 1, 0, 0, 180, 0], + }, + { + POSITION: [4, 8, 1.7, 13, 0, 180, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap]), + TYPE: "trap", + STAT_CALCULATOR: "trap", + }, + }, + ], +} +Class.conqueror = { + PARENT: "genericTank", + DANGER: 7, + LABEL: "Conqueror", + STAT_NAMES: statnames.mixed, + BODY: { + SPEED: 0.8 * base.SPEED, + }, + REVERSE_TARGET_WITH_TANK: true, + GUNS: [ + { + POSITION: [21, 14, 1, 0, 0, 180, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.destroyer]), + TYPE: "bullet", + }, + }, + { + POSITION: [18, 12, 1, 0, 0, 0, 0], + }, + { + POSITION: [2, 12, 1.1, 18, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, g.setTrap]), + TYPE: "setTrap", + STAT_CALCULATOR: "block" + }, + }, + ], +} +Class.bulwark = { + PARENT: "genericTank", + LABEL: "Bulwark", + STAT_NAMES: statnames.mixed, + DANGER: 7, + GUNS: [ + { + POSITION: [20, 8, 1, 0, 5.5, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.flankGuard, g.twin]), + TYPE: "bullet", + }, + }, + { + POSITION: [20, 8, 1, 0, -5.5, 0, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.flankGuard, g.twin]), + TYPE: "bullet", + }, + }, + { + POSITION: [14, 8, 1, 0, 5.5, 185, 0], + }, + { + POSITION: [3, 9, 1.5, 14, 5.5, 185, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, g.twin]), + TYPE: "trap", + STAT_CALCULATOR: "trap", + }, + }, + { + POSITION: [14, 8, 1, 0, -5.5, 175, 0], + }, + { + POSITION: [3, 9, 1.5, 14, -5.5, 175, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, g.twin]), + TYPE: "trap", + STAT_CALCULATOR: "trap", + }, + }, + ], +} + +// Desmos upgrades +Class.helix = { + PARENT: "genericTank", + LABEL: "Helix", + DANGER: 6, + STAT_NAMES: statnames.desmos, + GUNS: [ + { + POSITION: [20, 6, -4/3, 0, -5, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.desmos, {shudder: 0, spray: 0, size: 0.8}]), + TYPE: ["bullet", {MOTION_TYPE: ["desmos", {invert: false}]}] + }, + }, + { + POSITION: [20, 6, -4/3, 0, 5, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.desmos]), + TYPE: ["bullet", {MOTION_TYPE: ["desmos", {invert: true}]}] + }, + }, + { + POSITION: [3.625, 7.5, 2.75, 5.75, -6.75, 90, 0], + }, + { + POSITION: [3.625, 7.5, 2.75, 5.75, 6.75, -90, 0], + }, + { + POSITION: [6, 8, 0.25, 10.5, 0, 0, 0], + }, + ], +} +Class.sidewinder = { + PARENT: "genericTank", + LABEL: "Sidewinder", + DANGER: 6, + STAT_NAMES: statnames.desmos, + UPGRADE_TOOLTIP: "[DEV NOTE] This tank does not function as intended yet!", + GUNS: [ + { + POSITION: [10, 8.5, 1.4, 7, 0, 0, 0] + }, + { + POSITION: [20, 8, -4/3, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sidewinder2]), + TYPE: ["bullet", {CONTROLLERS: ['snake']}] + }, + }, + { + POSITION: [4.25, 11, 2, 2.25, -4.25, 92.5, 0] + }, + { + POSITION: [4.25, 11, 2, 2.25, 4.25, -92.5, 0] + } + ] +} +Class.undertowEffect = { + PARENT: 'genericTank', + TYPE: 'undertowEffect', + SIZE: 5, + COLOR: 1, + HITS_OWN_TYPE: "never", + GIVE_KILL_MESSAGE: false, + ACCEPTS_SCORE: false, + DRAW_HEALTH: false, + DIE_AT_RANGE: true, + BODY: { + HEALTH: 9e99, + DAMAGE: 0, + RANGE: 5, + PUSHABILITY: 0, + } + }; + Class.undertowBullet = { + PARENT: 'bullet', + ON: [ + { + event: "tick", + handler: ({ body }) => { + for (let instance of entities) { + let diffX = instance.x - body.x, + diffY = instance.y - body.y, + dist2 = diffX ** 2 + diffY ** 2; + if (dist2 <= ((body.size / 12)*250) ** 1.9) { + if ((instance.team != body.team || (instance.type == "undertowEffect" && instance.master.id == body.master.id)) && instance.type != "wall" && instance.isTurret != true) { + if (instance.type == "undertowEffect") { + forceMulti = 1 + } + else if (instance.type == "food") { + forceMulti = (6 / instance.size) + } + else { + forceMulti = (2 / instance.size) + } + instance.velocity.x += util.clamp(body.x - instance.x, -90, 90) * instance.damp * forceMulti;//0.05 + instance.velocity.y += util.clamp(body.y - instance.y, -90, 90) * instance.damp * forceMulti;//0.05 + if (instance.type != "undertowEffect" && instance.type != "bullet" && instance.type != "swarm" && instance.type != "drone" && instance.type != "trap" && instance.type != "dominator") { + let o = new Entity({x: instance.x, y: instance.y}) + o.define('undertowEffect') + o.team = body.team; + o.color = instance.color; + o.alpha = 0.3; + o.master = body.master; + } + } + } + if (dist2 < body.size ** 3 + instance.size ** 3) { + if (instance.master.id == body.master.id) { + if (instance.type == "undertowEffect") + { + instance.kill(); + } + } + } + } + } + } + ], + } + Class.undertow = { + PARENT: "genericTank", + LABEL: "Undertow", + DANGER: 6, + GUNS: [ + { + POSITION: [14, 12, 0.8, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { size: 0.8, reload: 1.2 }]), + TYPE: 'undertowBullet' + } + }, + { + POSITION: [11.25, 8, 0.15, 4.25, 4, 13.5, 0] + }, + { + POSITION: [11.25, 8, 0.15, 4.25, -4, -13.5, 0] + } + ] + } +Class.repeater = { + PARENT: "genericTank", + LABEL: "Repeater", + GUNS: [ + { + POSITION: [20, 10, 0.8, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.desmos, g.repeater]), + TYPE: ["splitterBullet", {MOTION_TYPE: "desmos"}] + } + }, + { + POSITION: [4.625, 9.5, 2, 0.375, -8, 91.5, 0] + }, + { + POSITION: [4.625, 9.5, 2, 0.375, 8, -91.5, 0] + }, + { + POSITION: [3.75, 10, 2.125, 0, -4.75, 50, 0] + }, + { + POSITION: [3.75, 10, 2.125, 0, 4.75, -50, 0] + } + ] +} + +// Helix upgrades +Class.triplex = { + PARENT: "genericTank", + LABEL: "Triplex", + DANGER: 7, + STAT_NAMES: statnames.desmos, + GUNS: [ + { + POSITION: [18, 10, 0.7, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.tripleShot, g.desmos]), + TYPE: "bullet", + }, + }, + { + POSITION: [18, 10, 0.7, 0, 0, 45, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.tripleShot, g.desmos]), + TYPE: ["bullet", {MOTION_TYPE: "desmos"}] + }, + }, + { + POSITION: [18, 10, 0.7, 0, 0, -45, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.tripleShot, g.desmos]), + TYPE: ["bullet", {MOTION_TYPE: ["desmos", {invert: true}]}] + }, + }, + { + POSITION: [3.75, 10, 2.125, 1, -4.25, 10, 0], + }, + { + POSITION: [3.75, 10, 2.125, 1, 4.25, -10, 0], + }, + { + POSITION: [5, 6, 0.5, 10.5, 0, 22.5, 0], + }, + { + POSITION: [5, 6, 0.5, 10.5, 0, -22.5, 0], + }, + ], +} +Class.quadruplex = { + PARENT: "genericTank", + LABEL: "Quadruplex", + DANGER: 7, + STAT_NAMES: statnames.desmos, + GUNS: [ + { + POSITION: [20, 10, 0.8, 0, 0, 45, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.desmos, g.twin, { reload: 2 }]), + TYPE: ["bullet", {MOTION_TYPE: ["desmos", {amplitude: 25}]}] + } + }, + { + POSITION: [3.75, 10, 2.125, 1.25, -6.25, 135, 0] + }, + { + POSITION: [3.75, 10, 2.125, 1.25, 6.25, -45, 0] + }, + { + POSITION: [20, 10, 0.8, 0, 0, -45, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.desmos, g.twin, { reload: 2 }]), + TYPE: ["bullet", {MOTION_TYPE: ["desmos", {amplitude: 25, invert: true}]}] + } + }, + { + POSITION: [3.75, 10, 2.125, 1.25, -6.25, 45, 0] + }, + { + POSITION: [3.75, 10, 2.125, 1.25, 6.25, -135, 0] + }, + { + POSITION: [20, 10, 0.8, 0, 0, 135, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.desmos, g.twin, { reload: 2 }]), + TYPE: ["bullet", {MOTION_TYPE: ["desmos", {period: 7, amplitude: 12.5}]}] + } + }, + { + POSITION: [3.75, 10, 2.125, 1.25, -6.25, -135, 0] + }, + { + POSITION: [3.75, 10, 2.125, 1.25, 6.25, 45, 0] + }, + { + POSITION: [20, 10, 0.8, 0, 0, -135, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.desmos, g.twin, { reload: 2 }]), + TYPE: ["bullet", {MOTION_TYPE: ["desmos", {period: 7, amplitude: 12.5, invert: true}]}] + } + }, + { + POSITION: [3.75, 10, 2.125, 1.25, -6.25, -45, 0] + }, + { + POSITION: [3.75, 10, 2.125, 1.25, 6.25, 135, 0] + }, + ], +} + +// Sidewinder upgrades +Class.coil = { + PARENT: "genericTank", + LABEL: "Coil", + DANGER: 7, + STAT_NAMES: statnames.desmos, + UPGRADE_TOOLTIP: "[DEV NOTE] This tank does not function as intended yet!", + GUNS: [ + { + POSITION: [20, 8, 0.75, 0, -5, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.sidewinder2]), + TYPE: ["bullet", {CONTROLLERS: ['snake']}] + }, + }, + { + POSITION: [20, 8, 0.75, 0, 5, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.sidewinder2]), + TYPE: ["bullet", {CONTROLLERS: [['snake', {invert: true}]]}] + }, + }, + { + POSITION: [21, 4, 0.75, 0, -5, 0, 0] + }, + { + POSITION: [21, 4, 0.75, 0, 5, 0, 0] + }, + { + POSITION: [3.625, 7.5, 2.75, 5.75, -6.75, 90, 0], + }, + { + POSITION: [3.625, 7.5, 2.75, 5.75, 6.75, -90, 0], + }, + { + POSITION: [6, 8, 0.25, 10.5, 0, 0, 0], + } + ] +} +Class.python = { + PARENT: "sidewinderOld", + LABEL: "Python", +} +Class.ranch = { + PARENT: "genericTank", + LABEL: "Ranch", + DANGER: 7, + STAT_NAMES: statnames.drone, + UPGRADE_TOOLTIP: "[DEV NOTE] This tank does not function as intended yet!", + BODY: { + SPEED: base.SPEED * 0.8, + FOV: 1.1, + }, + GUNS: [ + { + POSITION: [4.5, 10, 1, 10.5, 0, 0, 0], + }, + { + POSITION: [1, 12, 1, 15, 0, 0, 0], + PROPERTIES: { + MAX_CHILDREN: 3, + SHOOT_SETTINGS: combineStats([g.factory, g.babyfactory, g.sidewinder2]), + TYPE: ["minion", {CONTROLLERS: ['snake']}], + STAT_CALCULATOR: "drone", + AUTOFIRE: true, + SYNCS_SKILLS: true, + }, + }, + { + POSITION: [11.5, 12, 1, 0, 0, 0, 0], + }, + { + POSITION: [5, 7.5, 2.5, 1, -4.5, 95, 0], + }, + { + POSITION: [5, 7.5, 2.5, 1, 4.5, -95, 0], + }, + ], +} +Class.oroboros = { + PARENT: "genericTank", + LABEL: "Oroboros", + DANGER: 7, + STAT_NAMES: statnames.desmos, + UPGRADE_TOOLTIP: "[DEV NOTE] This tank is a placeholder!", + GUNS: [ + { + POSITION: [10, 8.5, 1.4, 7, 0, 0, 0] + }, + { + POSITION: [20, 10, 0.8, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sidewinder2, { speed: 3 }]), + TYPE: ["bullet", {CONTROLLERS: ['snake']}] + }, + }, + { + POSITION: [4.25, 11, 2, 2.25, -4.25, 92.5, 0] + }, + { + POSITION: [4.25, 11, 2, 2.25, 4.25, -92.5, 0] + } + ] +} +Class.cocciPart1 = { + PARENT: "genericSmasher", + LABEL: "", + BODY: { + REGEN: 999999, + HEALTH: 99999, + PENETRATION: 999 + }, + TURRETS: [ + { + POSITION: [21.5, 0, 0, 0, 360, 0], + TYPE: "smasherBody" + }, + { + POSITION: [20, -22, 0, 0, 90/4, 0], + TYPE: "smasher", + VULNERABLE: true + }, + ] +} +Class.cocciPart2 = { + PARENT: "genericSmasher", + LABEL: "", + BODY: { + REGEN: 999999, + HEALTH: 99999, + PENETRATION: 999 + }, + TURRETS: [ + { + POSITION: [21.5, 0, 0, 0, 360, 0], + TYPE: "smasherBody" + }, + { + POSITION: [20, -22, 0, 0, 90/3, 0], + TYPE: "cocciPart1", + VULNERABLE: true + }, + ] +} +Class.cocciPart3 = { + PARENT: "genericSmasher", + LABEL: "", + BODY: { + REGEN: 999999, + HEALTH: 99999, + PENETRATION: 999, + }, + TURRETS: [ + { + POSITION: [21.5, 0, 0, 0, 360, 0], + TYPE: "smasherBody" + }, + { + POSITION: [20, -22, 0, 0, 90/2, 0], + TYPE: "cocciPart2", + VULNERABLE: true + }, + ] +} +Class.cocci = { + PARENT: "genericSmasher", + LABEL: "Cocci", + UPGRADE_TOOLTIP: "[DEV NOTE] this is a very early prototype and probably won't work so well lol", + TURRETS: [ + { + POSITION: [21.5, 0, 0, 0, 360, 0], + TYPE: "smasherBody" + }, + { + POSITION: [20, -22, 0, 0, 90, 0], + TYPE: "cocciPart3", + VULNERABLE: true + } + ] +} + +// Undertow upgrades +Class.riptide = { + PARENT: "genericTank", + LABEL: "Riptide", + DANGER: 7, + GUNS: [ + { + POSITION: [6.5, 23.5, 0.25, 3, 0, 180, 0], + }, + { + POSITION: [18, 16, 0.75, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { size: 0.9, reload: 1.2 }]), + TYPE: "undertowBullet" + } + }, + { + POSITION: [17, 16, 0.1, 0.25, 4, 13.5, 0] + }, + { + POSITION: [17, 16, 0.1, 0.25, -4, -13.5, 0] + } + ] +} + +// Repeater upgrades +Class.iterator = { + PARENT: "genericTank", + LABEL: "Iterator", + DANGER: 7, + STAT_NAMES: statnames.desmos, + GUNS: [ + { + POSITION: [22, 10, 0.8, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.desmos, g.repeater]), + TYPE: ["superSplitterBullet", {MOTION_TYPE: "desmos"}] + } + }, + { + POSITION: [4.625, 10.5, 2.75, 0.375, -7, 91.5, 0] + }, + { + POSITION: [4.625, 10.5, 2.75, 0.375, 7, -91.5, 0] + }, + { + POSITION: [4, 9, 3, 1.5, -5, 95, 0] + }, + { + POSITION: [4, 9, 3, 1.5, 5, -95, 0] + }, + { + POSITION: [3.75, 10, 2.125, -1.5, -5.25, 50, 0] + }, + { + POSITION: [3.75, 10, 2.125, -1.5, 5.25, -50, 0] + } + ] +} +Class.duplicator = { + PARENT: "genericTank", + LABEL: "Duplicator", + DANGER: 7, + STAT_NAMES: statnames.desmos, + GUNS: [ + { + POSITION: [20, 10, 0.8, 0, 0, 20, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.desmos]), + TYPE: ["splitterBullet", {MOTION_TYPE: ["desmos", {invert: false}]}] + } + }, + { + POSITION: [20, 10, 0.8, 0, 0, -20, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.desmos]), + TYPE: ["splitterBullet", {MOTION_TYPE: ["desmos", {invert: true}]}] + } + }, + { + POSITION: [5.625, 9.5, 2, 0.375-1, -8, 111.5, 0] + }, + { + POSITION: [3.75, 10, 2.125, 0, 4.75, -30, 0] + }, + { + POSITION: [5.625, 9.5, 2, 0.375-1, 8, -111.5, 0] + }, + { + POSITION: [3.75, 10, 2.125, 0, -4.75, 30, 0] + }, + { + POSITION: [17, 8, 0.65, 0, 0, 0, 0] + }, + { + POSITION: [18, 8, 0.25, 0, 0, 0, 0] + }, + ] +} + +// Smasher upgrades +Class.megaSmasher = { + PARENT: "genericSmasher", + LABEL: "Mega-Smasher", + BODY: { + SPEED: 1.5 * base.SPEED, + FOV: 1.1 * base.FOV, + DENSITY: 4 * base.DENSITY, + ACCELERATION: 1.5 * base.ACCEL, + }, + TURRETS: [ + { + POSITION: [25, 0, 0, 0, 360, 0], + TYPE: "smasherBody", + }, + ], +} +Class.spike = { + PARENT: "genericSmasher", + LABEL: "Spike", + BODY: { + DAMAGE: base.DAMAGE * 2, + }, + TURRETS: [ + { + POSITION: [18.5, 0, 0, 0, 360, 0], + TYPE: "spikeBody", + }, + { + POSITION: [18.5, 0, 0, 90, 360, 0], + TYPE: "spikeBody", + }, + { + POSITION: [18.5, 0, 0, 180, 360, 0], + TYPE: "spikeBody", + }, + { + POSITION: [18.5, 0, 0, 270, 360, 0], + TYPE: "spikeBody", + }, + ], +} +Class.landmine = { + PARENT: "genericSmasher", + LABEL: "Landmine", + INVISIBLE: [0.06, 0.01], + TOOLTIP: "Stay still to turn invisible.", + BODY: { + SPEED: 1.45 * base.SPEED + }, + TURRETS: [ + { + POSITION: [21.5, 0, 0, 0, 360, 0], + TYPE: "smasherBody" + }, + { + POSITION: [21.5, 0, 0, 30, 360, 0], + TYPE: "landmineBody" + } + ] +} + +// Healer upgrades +Class.medic = { + PARENT: "genericTank", + LABEL: "Medic", + BODY: { + FOV: base.FOV * 1.2, + }, + TURRETS: [ + { + POSITION: [13, 0, 0, 0, 360, 1], + TYPE: "healerSymbol", + }, + ], + GUNS: [ + { + POSITION: [8, 9, -0.5, 16.5, 0, 0, 0], + }, + { + POSITION: [22, 10, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.healer, g.sniper]), + TYPE: "healerBullet", + }, + }, + ], + STAT_NAMES: statnames.heal, +} +Class.ambulance = { + PARENT: "genericTank", + LABEL: "Ambulance", + BODY: { + HEALTH: base.HEALTH * 0.8, + SHIELD: base.SHIELD * 0.8, + DENSITY: base.DENSITY * 0.6, + }, + TURRETS: [ + { + POSITION: [13, 0, 0, 0, 360, 1], + TYPE: "healerSymbol", + }, + ], + GUNS: [ + { + POSITION: [8, 9, -0.5, 12.5, 0, 0, 0], + }, + { + POSITION: [18, 10, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.triAngleFront, { recoil: 4 }, g.healer]), + TYPE: "healerBullet", + LABEL: "Front", + }, + }, + { + POSITION: [16, 8, 1, 0, 0, 150, 0.1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), + TYPE: "bullet", + LABEL: "thruster", + }, + }, + { + POSITION: [16, 8, 1, 0, 0, 210, 0.1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), + TYPE: "bullet", + LABEL: "thruster", + }, + }, + ], + STAT_NAMES: statnames.heal, +} +Class.surgeon = { + PARENT: "genericTank", + LABEL: "Surgeon", + STAT_NAMES: statnames.trap, + BODY: { + SPEED: base.SPEED * 0.75, + FOV: base.FOV * 1.15, + }, + TURRETS: [ + { + POSITION: [13, 0, 0, 0, 360, 1], + TYPE: "healerSymbol", + }, + ], + GUNS: [ + { + POSITION: [5, 11, 1, 10.5, 0, 0, 0], + }, + { + POSITION: [3, 14, 1, 15.5, 0, 0, 0], + }, + { + POSITION: [2, 14, 1.3, 18, 0, 0, 0], + PROPERTIES: { + MAX_CHILDREN: 2, + SHOOT_SETTINGS: combineStats([g.trap, g.setTrap, { speed: 0.7, maxSpeed: 0.7 }]), + TYPE: "surgeonPillbox", + SYNCS_SKILLS: true, + STAT_CALCULATOR: "block", + }, + }, + { + POSITION: [4, 14, 1, 8, 0, 0, 0], + }, + ], + STAT_NAMES: statnames.heal, +} +Class.paramedic = { + PARENT: "genericTank", + LABEL: "Paramedic", + BODY: { + SPEED: base.SPEED * 0.9, + }, + TURRETS: [ + { + POSITION: [13, 0, 0, 0, 360, 1], + TYPE: "healerSymbol", + }, + ], + GUNS: [ + { + POSITION: [8, 9, -0.5, 10, 0, -17.5, 0.5], + }, + { + POSITION: [15.5, 10, 1, 0, 0, -17.5, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.tripleShot, g.healer]), + TYPE: "healerBullet", + }, + }, + { + POSITION: [8, 9, -0.5, 10, 0, 17.5, 0.5], + }, + { + POSITION: [15.5, 10, 1, 0, 0, 17.5, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.tripleShot, g.healer]), + TYPE: "healerBullet", + }, + }, + { + POSITION: [8, 9, -0.5, 12.5, 0, 0, 0], + }, + { + POSITION: [18, 10, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.tripleShot, g.healer]), + TYPE: "healerBullet", + }, + }, + ], + STAT_NAMES: statnames.heal, +} + +// Bird tanks +Class.falcon = makeBird("assassin", "Falcon") +Class.vulture = makeBird({ + PARENT: "genericTank", + DANGER: 7, + BODY: { + FOV: base.FOV * 1.2, + }, + GUNS: [ + { + POSITION: [22, 7, -1.5, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun]), + TYPE: "bullet" + } + }, + { + POSITION: [20, 7.5, -1.5, 0, 0, 0, 1/3], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, {size: 7/7.5}]), + TYPE: "bullet" + } + }, + { + POSITION: [18, 8, -1.5, 0, 0, 0, 2/3], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, {size: 7/8}]), + TYPE: "bullet" + } + } + ] +}, "Vulture") +Class.phoenix = makeBird("sprayer", "Phoenix") +Class.eagle = makeBird("pounder", "Eagle") + +// Over tanks +Class.overgunner = makeOver({ + PARENT: "genericTank", + LABEL: "Gunner", + DANGER: 6, + GUNS: [ + { + POSITION: [19, 2, 1, 0, -2.5, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.power, g.twin, { speed: 0.7, maxSpeed: 0.7 }, g.flankGuard, { recoil: 1.8 }]), + TYPE: "bullet", + }, + }, + { + POSITION: [19, 2, 1, 0, 2.5, 0, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.power, g.twin, { speed: 0.7, maxSpeed: 0.7 }, g.flankGuard, { recoil: 1.8 }]), + TYPE: "bullet", + }, + }, + { + POSITION: [12, 11, 1, 0, 0, 0, 0], + }, + ], +}) +Class.overtrapper = makeOver({ + PARENT: "genericTank", + LABEL: "Trapper", + DANGER: 6, + STAT_NAMES: statnames.mixed, + BODY: { + SPEED: base.SPEED * 0.8, + FOV: base.FOV * 1.2 + }, + GUNS: [ + { + POSITION: [14, 8, 1, 0, 0, 0, 0], + }, + { + POSITION: [4, 8, 1.5, 14, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap]), + TYPE: "trap", + STAT_CALCULATOR: "trap", + } + } + ] +}) + +//delta upgrades +Class.minilaser = { + PARENT: "genericTank", + LABEL: "Plasma SMG", + DANGER: 7, + BODY: { + FOV: 1.2, + }, + GUNS: [ + { + /*** LENGTH WIDTH ASPECT X Y ANGLE DELAY */ + POSITION: [21, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.doublereload, g.one_third_reload]), + TYPE: "laser", + }, + }, + { + POSITION: [19, 8, 1, 0, 0, 0, 1 / 3], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.doublereload, g.one_third_reload]), + TYPE: "laser", + }, + }, + { + POSITION: [17, 8, 1, 0, 0, 0, 2 / 3], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.doublereload, g.one_third_reload]), + TYPE: "laser", + }, + }, + { + POSITION: [24, 1, 1, 0, 0, 0, 2 / 3], + PROPERTIES: { + COLOR: 'red', + SHOOT_SETTINGS: combineStats([g.fake]), + TYPE: "laser", + }, + } + ], +} +Class.cruiserdrive = { + PARENT: "genericTank", + LABEL: "Swarmdrive", + DANGER: 6, + FACING_TYPE: "locksFacing", + STAT_NAMES: statnames.swarm, + BODY: { + FOV: 1.2 * base.FOV, + }, + GUNS: [ + { + POSITION: [7, 7.5, 0.6, 7, 4, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.swarm]), + TYPE: "autoturretswarm", + STAT_CALCULATOR: "swarm", + }, + }, + { + POSITION: [7, 7.5, 0.6, 7, -4, 0, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.swarm]), + TYPE: "autoturretswarm", + STAT_CALCULATOR: "swarm", + }, + }, + ], +} +Class.shrapnelgun = { + PARENT: "genericTank", + LABEL: "Albuquerque", + DANGER: 7, + GUNS: [{ + POSITION: [17, 13, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.artillery, g.artillery, g.halfspeed]), + TYPE: "grenade" + } + } + ], + TURRETS: [{ + POSITION: [8.2, 16.7, 0, 0, 0, 0], + TYPE: ["grenadeDeco", { MIRROR_MASTER_ANGLE: true }], + } + ] +} +Class.firecracker = { + PARENT: "genericTank", + LABEL: "Firecracker", + DANGER: 7, + GUNS: [{ + POSITION: [17, 13, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.artillery, g.artillery, g.halfspeed, g.halfspeed, { damage: 0.85, reload: 2.2 }]), + TYPE: "firecrackerbomb" + } + } + ], + TURRETS: [{ + POSITION: [8.2, 13, 0, 0, 0, 2], + TYPE: ["firecrackerDeco", { MIRROR_MASTER_ANGLE: true }], + } + ] +} +Class.inception = { + PARENT: "genericTank", + LABEL: "Inception", + DANGER: 5, + GUNS: [ + { + POSITION: [18, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic]), + TYPE: "autobullet", + } + } + ], + TURRETS: [{ + POSITION: [5.5, 18, 0, 0, 0, 0], + TYPE: ["autoTurret", { INDEPENDENT: true, MIRROR_MASTER_ANGLE: true }] + } + ] +} +Class.inceptionist = { + PARENT: "genericTank", + LABEL: "Ceptionist", + DANGER: 6, + GUNS: [ + { + POSITION: [18, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic]), + TYPE: "ceptionistbullet", + } + } + ], + TURRETS: [{ + POSITION: [10, 0, 0, 0, 0, 1], + TYPE: ["ceptionistturret", { INDEPENDENT: true, MIRROR_MASTER_ANGLE: true }] + } + ] +} +Class.twinceptionist = { + PARENT: "genericTank", + LABEL: "Twinceptionist", + DANGER: 7, + GUNS: [ + { + POSITION: [20, 8, 1, 0, 5.5, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin]), + TYPE: "ceptionistbullet" + } + }, + { + POSITION: [20, 8, 1, 0, -5.5, 0, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin]), + TYPE: "ceptionistbullet" + } + } + ], + TURRETS: [{ + POSITION: [10, 0, 0, 0, 0, 1], + TYPE: ["ceptionistturret", { INDEPENDENT: true, MIRROR_MASTER_ANGLE: true }] + } + ] +} +Class.machinception = { + PARENT: "genericTank", + LABEL: "Machceptioner", + DANGER: 6, + GUNS: [ + { + POSITION: [12, 10, 1.4, 8, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun]), + TYPE: "autobullet" + } + } + ], + TURRETS: [{ + POSITION: [6.5, 20, 0, 0, 0, 0], + TYPE: ["autoTurret", { INDEPENDENT: true, MIRROR_MASTER_ANGLE: true }] + } + ] +} +Class.machceptionist = { + PARENT: "genericTank", + LABEL: "Machceptionist", + DANGER: 7, + GUNS: [ + { + POSITION: [12, 10, 1.4, 8, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun]), + TYPE: "ceptionistbullet" + } + } + ], + TURRETS: [{ + POSITION: [10, 0, 0, 0, 0, 1], + TYPE: ["ceptionistturret", { INDEPENDENT: true, MIRROR_MASTER_ANGLE: true }] + } + ] +} +Class.flankinception = { + PARENT: "genericTank", + LABEL: "Flankceptioner", + DANGER: 6, + BODY: { + SPEED: 1.1 * base.SPEED + }, + GUNS: weaponArray({ + POSITION: [18, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard]), + TYPE: "autobullet" + } + }, 3), + TURRETS: weaponArray({ + POSITION: [5.5, 18, 0, 0, 0, 0], + TYPE: ["autoTurret", { INDEPENDENT: true, MIRROR_MASTER_ANGLE: true }] + }, 3) +} +Class.flankceptionist = { + PARENT: "genericTank", + LABEL: "Flankceptionist", + DANGER: 7, + BODY: { + SPEED: 1.1 * base.SPEED + }, + GUNS: weaponArray({ + POSITION: [18, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard]), + TYPE: "ceptionistbullet" + } + }, 3), + TURRETS: weaponArray({ + POSITION: [5.5, 18, 0, 0, 0, 0], + TYPE: ["ceptionistturret", { INDEPENDENT: true, MIRROR_MASTER_ANGLE: true }] + }, 3) +} +Class.flankdue = { + PARENT: "genericTank", + LABEL: "Flankduer", + DANGER: 6, + BODY: { + ACCELERATION: base.ACCEL * 0.9, + SPEED: base.SPEED * 1.1, + }, + GUNS: weaponArray([{ + POSITION: [23, 5, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.hunter, g.hunterSecondary]), + TYPE: "bullet" + } + }, { + POSITION: [20, 8, 1, 0, 0, 0, 0.2], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.hunter]), + TYPE: "bullet" + } + }], 3) +} +Class.tailgator = { + PARENT: "genericTank", + LABEL: "Tailgator", + DANGER: 6, + GUNS: [ + { + POSITION: [20.5, 12, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder]), + TYPE: "heavyautobullet" + } + } + ], + TURRETS: [{ + POSITION: [7.5, 20, 0, 0, 0, 0], + TYPE: ["autoTurret", { INDEPENDENT: true, MIRROR_MASTER_ANGLE: true }] + } + ] +} +Class.poundceptionist = { + PARENT: "genericTank", + LABEL: "PoundCeptionist", + DANGER: 7, + GUNS: [ + { + POSITION: [20.5, 12, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder]), + TYPE: "ceptionistbullet" + } + } + ], + TURRETS: [{ + POSITION: [10, 0, 0, 0, 0, 1], + TYPE: ["ceptionistturret", { INDEPENDENT: true, MIRROR_MASTER_ANGLE: true }] + } + ] +} +Class.interceptor = { + PARENT: "genericTank", + LABEL: "Interceptor", + DANGER: 7, + GUNS: [ + { + POSITION: [21, 14, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.destroyer]), + TYPE: "heavyautobullet" + } + } + ], + TURRETS: [{ + POSITION: [7.5, 20, 0, 0, 0, 0], + TYPE: ["autoTurret", { INDEPENDENT: true, MIRROR_MASTER_ANGLE: true }] + } + ] +} +Class.revolutionist = { + PARENT: "genericTank", + LABEL: "Revolutionist", + DANGER: 6, + GUNS: [{ + POSITION: [20, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard]), + TYPE: "bullet", + }, + }, + ], + TURRETS: [{ + POSITION: [34, 0, 0, 0, 360, 0], + TYPE: "turretBase", + }, + ], +}; +Class.proton = { + PARENT: "genericTank", + LABEL: "Proton", + DANGER: 7, + BODY: { + SPEED: 4 * base.SPEED + }, + GUNS: [{ + POSITION: [20, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard]), + TYPE: "bullet", + }, + }, + ], + TURRETS: [{ + POSITION: [34, 0, 0, 0, 360, 0], + TYPE: "protonturretBase", + }, + ], +}; +Class.baseThrower = { + PARENT: "genericTank", + LABEL: "Kivaaritehdas", + DANGER: 7, + SYNC_TURRET_SKILLS: true, + GUNS: [{ + POSITION: [20, 8, 1, 0, 0, 0, 0.2], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard]), + TYPE: "bullet" + } + }, { + POSITION: [1, 38, 1, 0, 0, 0, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, g.setTrap, g.boomerang, g.kiva]), + TYPE: ["baseBullet", { COLOR: "#FC8208", KEEP_OWN_COLOR: false }], + ALT_FIRE: true, + ALPHA: 0 + } + }], + TURRETS: [{ + POSITION: [34, 0, 0, 0, 360, 0], + TYPE: "turretBaseKiva", + }], + ON: [{ + event: "altFire", + handler: ({ body }) => { + body.define(Class.baseThrowerFire, true) + } + } + ] +}; +Class.baseThrowerFire = { + PARENT: "genericTank", + LABEL: "Kivaaritehdas", + DANGER: 7, + GUNS: [{ + POSITION: [20, 8, 1, 0, 0, 0, 0.2], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard]), + TYPE: "bullet" + } + }] +}; +Class.subverter = { + PARENT: "genericTank", + LABEL: "Subverter", + DANGER: 7, + GUNS: [{ + POSITION: [20, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard]), + TYPE: "bullet", + }, + }, + ], + TURRETS: [{ + POSITION: [34, 0, 0, 0, 360, 0], + TYPE: "subverterturretBase", + }, + ], +}; +Class.pion = { + PARENT: "genericSmasher", + LABEL: "Pion", + DANGER: 7, + BODY: { + SPEED: 2.5 * base.SPEED + }, + TURRETS: [ + { + POSITION: [21.5, 0, 0, 0, 360, 0], + TYPE: "smasherBody" + }, { + POSITION: [34, 0, 0, 0, 360, 0], + TYPE: "pionturretBase", + }] +} +Class.equilibrium = { + PARENT: "genericTank", + LABEL: "Equilibrium", + DANGER: 7, + GUNS: [ + { + POSITION: [20, 8, 1, 0, 5.5, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.twin]), + TYPE: "bullet" + } + }, + { + POSITION: [20, 8, 1, 0, -5.5, 0, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.twin]), + TYPE: "bullet" + } + } + ], + TURRETS: [{ + POSITION: [34, 0, 0, 0, 360, 0], + TYPE: "turretBase", + }, + ], +}; +Class.hadron = { + PARENT: "genericTank", + LABEL: "Hadron", + DANGER: 7, + GUNS: [{ + POSITION: [20, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard]), + TYPE: "bullet", + }, + }, + ], + TURRETS: [{ + POSITION: [34, 0, 0, 0, 360, 0], + TYPE: "hadronturretBase", + } + ], +}; +Class.hivemind = { + PARENT: "genericTank", + LABEL: "Hivemind", + DANGER: 7, + STAT_NAMES: statnames.mixed, + //CONTROLLERS: ['nearestDifferentMaster'], + GUNS: [ + { + /*** LENGTH WIDTH ASPECT X Y ANGLE DELAY */ + POSITION: [18, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.cloner]), + TYPE: "bullet" + } + }, + { + POSITION: [0, 20, 1, 0, 0, 90, 1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.slow, { reload: 5 }]), + TYPE: "hiveprobe", + MAX_CHILDREN: 1, + WAIT_TO_CYCLE: true + } + }, + { + POSITION: [0, 20, 1, 0, 0, 270, 1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.slow, { reload: 5 }]), + TYPE: "hiveprobe", + MAX_CHILDREN: 1, + WAIT_TO_CYCLE: true + } + } + ], + TURRETS: [ + { + /* SIZE X Y ANGLE ARC */ + POSITION: [27, 0, 0, 0, 360, 0], + TYPE: "mindindicator" + } + ] +}; +Class.cloner = { + PARENT: "genericTank", + LABEL: "Cloner", + STAT_NAMES: statnames.mixed, + GUNS: [ + { + /*** LENGTH WIDTH ASPECT X Y ANGLE DELAY */ + POSITION: [18, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.cloner]), + TYPE: "bullet" + } + }, + { + POSITION: [0, 20, 1, 0, 0, 270, 1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.slow, { reload: 5 }]), + TYPE: "clonerprobe", + MAX_CHILDREN: 1, + WAIT_TO_CYCLE: true + } + } + ], + TURRETS: [ + { + /* SIZE X Y ANGLE ARC */ + POSITION: [24, 0, 0, 0, 360, 0], + TYPE: "mindindicator" + } + ] +}; + Class.dictator = { + PARENT: "genericTank", + LABEL: "Dictator", + STAT_NAMES: statnames.drone, + DANGER: 7, + SHAPE: 8, + BODY: { + ACCELERATION: base.ACCEL * 0.75, + FOV: base.FOV * 1.1, + }, + MAX_CHILDREN: 4, + GUNS: [ { /*** LENGTH WIDTH ASPECT X Y ANGLE DELAY */ + POSITION: [ 6, 12, 1.2, 8, 0, 0, 0, ], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, g.overseer]), + TYPE: "fastdrone", + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "drone", + }, }, + ], + }; +Class.littleHunter = { + PARENT: "genericTank", + LABEL: "Subduer", + DANGER: 5, + BODY: { + ACCELERATION: base.ACCEL * 0.9, + FOV: 1.1 + }, + GUNS: [{ + POSITION: [23, 5, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.littleHunter, g.hunter, g.hunterSecondary]), + TYPE: "bullet" + } + }, { + POSITION: [20, 8, 1, 0, 0, 0, 0.2], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.littleHunter, g.hunter]), + TYPE: "bullet" + } + }] +}; +Class.subway = makeBird({ + PARENT: "genericTank", + DANGER: 7, + BODY: { + ACCELERATION: base.ACCEL * 0.9, + FOV: 1.05 + }, + GUNS: [{ + POSITION: [23, 5, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.littleHunter, g.flankGuard, g.triAngle, g.triAngleFront, g.hunter, g.hunterSecondary]), + TYPE: "bullet" + } + }, { + POSITION: [20, 8, 1, 0, 0, 0, 0.2], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.littleHunter, g.flankGuard, g.triAngle, g.triAngleFront, g.hunter]), + TYPE: "bullet" + } + }] +}, "Subway") +Class.cockatiel = makeBird({ + PARENT: "genericTank", + DANGER: 7, + STAT_NAMES: statnames.mixed, + BODY: { + ACCELERATION: base.ACCEL * 0.9, + FOV: 1.05 + }, + GUNS: [{ + POSITION: [21, 7, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.littleHunter, g.flankGuard, g.triAngle, g.triAngleFront, g.hunter, g.hunterSecondary]), + TYPE: "bullet" + } + }, { + POSITION: [14, 8, 1, 0, 0, 0, 0], + }, + { + POSITION: [4, 8, 1.5, 14, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, g.flankGuard, g.triAngle, g.triAngleFront]), + TYPE: "trap", + STAT_CALCULATOR: "trap", + } + }] +}, "Cockatiel") +Class.binary = { + PARENT: "genericTank", + LABEL: "Binary", + DANGER: 6, + BODY: { + ACCELERATION: base.ACCEL * 0.9, + FOV: 1.1 + }, + GUNS: [{ + POSITION: [20, 5, 1, 0, 5.5, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.littleHunter, g.twin, g.hunter, g.hunterSecondary]), + TYPE: "bullet" + } + }, { + POSITION: [17, 8, 1, 0, 5.5, 0, 0.2], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.littleHunter, g.twin, g.hunter]), + TYPE: "bullet" + } + }, { + POSITION: [20, 5, 1, 0, -5.5, 0, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.littleHunter, g.twin, g.hunter, g.hunterSecondary]), + TYPE: "bullet" + } + }, { + POSITION: [17, 8, 1, 0, -5.5, 0, 0.7], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.littleHunter, g.twin, g.hunter]), + TYPE: "bullet" + } + }] +} +Class.twincontagion = { + PARENT: "genericTank", + LABEL: "Contagiwark", + DANGER: 7, + STAT_NAMES: statnames.mixed, + GUNS: [{ + POSITION: [19, 5.5, 1, 0, -5.5, -8, 0.2], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.contagi, g.twin]), + TYPE: "bullet" + } + }, { + POSITION: [13, 8, 1, 0, -5.5, -8, 0] + }, { + POSITION: [4, 8, 1.7, 13, -5.5, -8, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, g.twin, g.halfrange]), + TYPE: "trap", + STAT_CALCULATOR: "trap", + } + }, { + POSITION: [19, 5.5, 1, 0, 5.5, 8, 0.7], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.contagi, g.twin]), + TYPE: "bullet" + } + }, { + POSITION: [13, 8, 1, 0, 5.5, 8, 0.5] + }, { + POSITION: [4, 8, 1.7, 13, 5.5, 8, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, g.twin, g.halfrange]), + TYPE: "trap", + STAT_CALCULATOR: "trap", + } + }] +} +Class.trinary = { + PARENT: "genericTank", + LABEL: 'Trinary', + DANGER: 7, + BODY: { + ACCELERATION: base.ACCEL * .7, + FOV: 1.1 + }, + GUNS: [{ + POSITION: [22, 5, 1, 0, 2, 20, .5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.littleHunter, g.hunter, g.hunterSecondary, g.twin, g.tripleShot]), + TYPE: "bullet" + } + }, { + POSITION: [19, 8, 1, 0, 2, 20, .7], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.littleHunter, g.hunter, g.twin, g.tripleShot]), + TYPE: "bullet" + } + }, { + POSITION: [22, 5, 1, 0, -2, -20, .5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.littleHunter, g.hunter, g.hunterSecondary, g.twin, g.tripleShot]), + TYPE: "bullet" + } + }, { + POSITION: [19, 8, 1, 0, -2, -20, .7], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.littleHunter, g.hunter, g.twin, g.tripleShot]), + TYPE: "bullet" + } + }, { + POSITION: [25, 5, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.littleHunter, g.hunter, g.hunterSecondary, g.twin, g.tripleShot]), + TYPE: "bullet" + } + }, { + POSITION: [22, 8, 1, 0, 0, 0, .2], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.littleHunter, g.hunter, g.twin, g.tripleShot]), + TYPE: "bullet" + } + }] +}; +Class.bigSubduer = { + PARENT: "genericTank", + LABEL: 'Mitochondrion', + DANGER: 7, + BODY: { + ACCELERATION: base.ACCEL * 0.9, + FOV: 1.1 + }, + GUNS: [{ + POSITION: [26, 2, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.littleHunter, g.hunter, g.hunterSecondary, g.hunterSecondary, g.predator]), + TYPE: "bullet" + } + }, { + POSITION: [23, 5, 1, 0, 0, 0, .15], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.littleHunter, g.hunter, g.hunterSecondary, g.predator]), + TYPE: "bullet" + } + }, { + POSITION: [20, 8, 1, 0, 0, 0, .3], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.littleHunter, g.hunter, g.predator]), + TYPE: "bullet" + } + }] +} +Class.clubbin = { + PARENT: "genericTank", + LABEL: "Clubbin", + DANGER: 7, + BODY: { + ACCELERATION: base.ACCEL * 0.9, + FOV: 1.1 + }, + GUNS: weaponArray([{ + POSITION: [26, 2, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.littleHunter, g.flankGuard, g.hunter, g.hunterSecondary, g.hunterSecondary, g.predator]), + TYPE: "bullet" + } + }, { + POSITION: [23, 5, 1, 0, 0, 0, .15], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.littleHunter, g.flankGuard, g.hunter, g.hunterSecondary, g.predator]), + TYPE: "bullet" + } + }, { + POSITION: [20, 8, 1, 0, 0, 0, .3], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.littleHunter, g.flankGuard, g.hunter, g.predator]), + TYPE: "bullet" + } + }], 3) +} +Class.biggerSubduer = { + PARENT: "genericTank", + LABEL: 'Cytochrome', + DANGER: 7, + BODY: { + ACCELERATION: base.ACCEL * 0.8, + SPEED: base.SPEED * 0.95, + FOV: 1.1 + }, + GUNS: [{ + POSITION: [29, 2, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.littleHunter, g.hunter, g.hunterSecondary, g.hunterSecondary, g.hunterSecondary, g.predator, g.lessrecoil]), + TYPE: "bullet" + } + }, { + POSITION: [26, 4, 1, 0, 0, 0, 2/15], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.littleHunter, g.hunter, g.hunterSecondary, g.hunterSecondary, g.predator, g.lessrecoil]), + TYPE: "bullet" + } + }, { + POSITION: [23, 6, 1, 0, 0, 0, 4/15], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.littleHunter, g.hunter, g.hunterSecondary, g.predator]), + TYPE: "bullet" + } + }, { + POSITION: [20, 8, 1, 0, 0, 0, 0.4], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.littleHunter, g.hunter, g.predator]), + TYPE: "bullet" + } + }] +} +Class.accelminigun = { + PARENT: "genericTank", + LABEL: "Rainmaker", + DANGER: 6, + BODY: { + FOV: base.FOV * 1.4 + }, + GUNS: [ + { + POSITION: [8, .1, -54, 21, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.fake, g.triplereload]), + TYPE: "bullet", + COLOR: 12 + } + }, + { + POSITION: [21, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.rainmaker, g.morerange, g.morerange]), + TYPE: ["bullet", { MOTION_TYPE: "accelerate" }] + } + }, + { + POSITION: [19, 8, 1, 0, 0, 0, 1/3], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.rainmaker, g.morerange, g.morerange]), + TYPE: ["bullet", { MOTION_TYPE: "accelerate" }] + } + }, + { + POSITION: [17, 8, 1, 0, 0, 0, 2/3], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun, g.rainmaker, g.morerange, g.morerange]), + TYPE: ["bullet", { MOTION_TYPE: "accelerate" }] + } + } + ] +} +Class.railgun = { + PARENT: "genericTank", + DANGER: 7, + LABEL: "Railgun", + BODY: { + SPEED: 0.9 * base.SPEED, + FOV: 1.25 * base.FOV + }, + GUNS: [ + { + /*** LENGTH WIDTH ASPECT X Y ANGLE DELAY */ + POSITION: [1, 6.5, 1, 25, 0, 0, 0.15], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.assassin, g.one_third_reload, g.fast, g.fast, g.fast, g.fast, g.railgun]), + TYPE: "bullet" + } + }, { + POSITION: [1, 6.5, 1, 10, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.assassin, g.one_third_reload, g.fast, g.fast, g.railgun]), + TYPE: "bullet" + } + }, { + POSITION: [1, 6.5, 1, 15, 0, 0, 0.05], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.assassin, g.one_third_reload, g.fast, g.fast, g.railgun]), + TYPE: "bullet" + } + }, + { + POSITION: [1, 6.5, 1, 20, 0, 0, 0.1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.assassin, g.one_third_reload, g.fast, g.fast, g.fast, g.railgun]), + TYPE: "bullet" + } + }, + { + POSITION: [22, 1.9, 1, 5, 4, 0, 0] + }, + { + POSITION: [22, 1.9, 1, 5, -4, 0, 0] + } + ] +} +Class.skater = { + PARENT: "genericSmasher", + LABEL: "Skater", + DANGER: 7, + BODY: { + SPEED: base.SPEED * 2.3, + }, + TURRETS: [ + { + POSITION: [21.5, 0, 0, 0, 360, 0], + TYPE: "smasherBody" + }, { + POSITION: [15, 0, 0, 0, 360, 1], + TYPE: ["skaterDeco", { COLOR: "#49bdde" }] + } + ] +} +Class.revodirector = { + PARENT: "genericTank", + LABEL: "Solar System", + STAT_NAMES: statnames.drone, + BODY: { + FOV: base.FOV * 1.1 + }, + GUNS: [ + { + POSITION: [6, 11, 1.3, 7, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone]), + TYPE: "revoorbitdrone", + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "drone", + MAX_CHILDREN: 5 + } + } + ], + TURRETS: [{ + POSITION: [34, 0, 0, 0, 360, 0], + TYPE: "turretBasenoguns", + }, { + POSITION: [9, 0, 0, 0, 360, 1], + TYPE: "overdriveDeco", + }, + ], +} +Class.directdrive = { + PARENT: "genericTank", + LABEL: "Motor", + STAT_NAMES: statnames.drone, + BODY: { + FOV: base.FOV * 1.1 + }, + GUNS: [ + { + POSITION: [6, 11, 1.3, 7, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone]), + TYPE: "turretedDrone", + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "drone", + MAX_CHILDREN: 6 + } + } + ], + TURRETS: [ + { + POSITION: [9, 0, 0, 0, 360, 1], + TYPE: "overdriveDeco", + }, + ] +} +Class.contagion = { + PARENT: "genericTank", + LABEL: 'Contagion', + DANGER: 6, + STAT_NAMES: statnames.mixed, + GUNS: [{ + POSITION: [19, 5.5, 1, 0, 0, 0, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.contagi]), + TYPE: "bullet" + } + }, { + POSITION: [13, 8, 1, 0, 0, 0, 0] + }, { + POSITION: [4, 8, 1.7, 13, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap]), + TYPE: "trap", + STAT_CALCULATOR: "trap", + } + }] +}; +Class.triContagion = { + PARENT: "genericTank", + LABEL: "Tri-Contagion", + DANGER: 7, + STAT_NAMES: statnames.mixed, + GUNS: weaponArray([{ + POSITION: [19, 5.5, 1, 0, 0, 0, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.contagi, g.flankGuard]), + TYPE: "bullet" + } + }, { + POSITION: [13, 8, 1, 0, 0, 0, 0] + }, { + POSITION: [4, 8, 1.7, 13, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, g.flankGuard]), + TYPE: "trap", + STAT_CALCULATOR: "trap", + } + }], 3) +} +Class.autoContagion = makeAuto("contagion"); +Class.fort = { + PARENT: "genericTank", + LABEL: "Fort", + DANGER: 7, + BODY: { + SPEED: base.SPEED * 0.8, + ACCELERATION: base.ACCEL * 0.9, + FOV: 1.15 + }, + STAT_NAMES: statnames.mixed, + GUNS: [{ + POSITION: [22, 5.5, 1, 0, 0, 0, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.contagi]), + TYPE: "bullet" + } + }, { + POSITION: [18, 12, 1, 0, 0, 0, 0] + }, { + POSITION: [2, 12, 1.1, 18, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, g.setTrap]), + TYPE: "setTrap" + } + }] +}; +Class.droneTrapper = { + PARENT: "genericTank", + LABEL: "Magician", + DANGER: 7, + BODY: { + FOV: 1.1, + ACCELERATION: base.ACCEL * .9 + }, + STAT_NAMES: statnames.mixed, + GUNS: [{ + POSITION: [6, 12, 1.2, 8, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, g.overseer, g.lesspower]), + TYPE: "drone", + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "drone", + MAX_CHILDREN: 6 + } + }, { + POSITION: [13, 8, 1, 0, 0, 0, 0] + }, { + POSITION: [4, 8, 1.7, 13, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap]), + TYPE: "trap", + STAT_CALCULATOR: "drone", + } + }] +} +Class.trojan = { + PARENT: "genericTank", + LABEL: "Trojan", + STAT_NAMES: statnames.mixed, + DANGER: 7, + BODY: { + ACCELERATION: base.ACCEL * 0.675, + SPEED: base.SPEED * 0.875, + FOV: 1.1 + }, + GUNS: [{ + POSITION: [19, 5.5, 1, 0, 0, 0, .5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.contagi, g.flankGuard]), + TYPE: "bullet" + } + }, { + POSITION: [6, 12, 1.2, 8, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, g.overseer, g.bitlessreload]), + TYPE: "drone", + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "drone", + WAIT_TO_CYCLE: true, + MAX_CHILDREN: 4 + } + }, { + POSITION: [19, 5.5, 1, 0, 0, 180, .5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.contagi, g.flankGuard]), + TYPE: "bullet" + } + }, { + POSITION: [6, 12, 1.2, 8, 0, 180, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, g.overseer, g.bitlessreload]), + TYPE: "drone", + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "drone", + WAIT_TO_CYCLE: true, + MAX_CHILDREN: 4 + } + }] +} +Class.gundirector = { + PARENT: "genericTank", + LABEL: "Pathogen", + STAT_NAMES: statnames.mixed, + DANGER: 6, + BODY: { + ACCELERATION: base.ACCEL * 0.75, + SPEED: base.SPEED * 0.95, + FOV: 1.1 + }, + GUNS: [{ + POSITION: [19, 5.5, 1, 0, 0, 0, .5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.contagi]), + TYPE: "bullet" + } + }, { + POSITION: [6, 12, 1.2, 8, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, g.bitlessreload]), + TYPE: "drone", + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "drone", + MAX_CHILDREN: 6 + } + }] +} +Class.gundirectorbig = { + PARENT: "genericTank", + LABEL: "X-Pathogen", + STAT_NAMES: statnames.mixed, + DANGER: 6, + BODY: { + ACCELERATION: base.ACCEL * 0.8, + FOV: 1.2, + }, + GUNS: [{ + POSITION: [18, 8, 1, 0, 0, 0, .5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { speed: 1.25, reload: 0.95, maxSpeed: 1.15 } ]), + TYPE: "bullet" + } + }, { + POSITION: [6, 16, 1.2, 8, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone, g.bitlessreload, { speed: 1.1, maxSpeed: 1.1 }]), + TYPE: "drone", + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "drone", + MAX_CHILDREN: 6 + } + }] +} +Class.wyrm = { + PARENT: "genericTank", + LABEL: "Wyrm", + DANGER: 7, + FACING_TYPE: "locksFacing", + STAT_NAMES: statnames.mixed, + BODY: { + FOV: 1.2 * base.FOV, + }, + GUNS: [ +{ + POSITION: [18, 5.5, 1, 0, 0, 0, .5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.contagi]), + TYPE: "bullet" + } + }, { + POSITION: [7, 7.5, 0.6, 7, 4, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.swarm]), + TYPE: "swarm", + STAT_CALCULATOR: "swarm", + }, + }, + { + POSITION: [7, 7.5, 0.6, 7, -4, 0, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.swarm]), + TYPE: "swarm", + STAT_CALCULATOR: "swarm", + }, + }, + ], +} +Class.protist = { + PARENT: "genericTank", + LABEL: "Protist", + DANGER: 7, + BODY: { + ACCELERATION: base.ACCEL * .9, + SPEED: base.SPEED * .8, + FOV: 1.1 + }, + STAT_NAMES: statnames.mixed, + GUNS: [{ + POSITION: [18, 5.5, 1, 0, 0, 0, .5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.contagi]), + TYPE: "bullet" + } + }, { + POSITION: [4.5, 10, 1, 10.5, 0, 0, 0] + }, { + POSITION: [1, 12, 1.01, 15, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.factory, g.babyfactory]), + TYPE: "minion", + STAT_CALCULATOR: "drone", + AUTOFIRE: true, + SYNCS_SKILLS: true, + MAX_CHILDREN: 4 + } + }, { + POSITION: [3.5, 12, 1, 8, 0, 0, 0] + }] +}; +Class.acid = { + PARENT: "genericTank", + LABEL: 'Acid', + DANGER: 6, + GLOW: { + RADIUS: 2, + COLOR: "green", + ALPHA: 1, + RECURSION: 4, + }, + BODY: { + ACCELERATION: base.ACCEL * 0.75, + SPEED: base.SPEED * 0.85, + FOV: base.FOV * 1.2, + }, + GUNS: [{ + POSITION: [24, 8.5, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper]), + TYPE: "poisonbullet", + } + }, { + POSITION: [13.95, 5.15, 1, 0, 0, 0, 0], + PROPERTIES: { + COLOR: "green" + } + }] +}; +Class.disintegrator = { + PARENT: "genericTank", + DANGER: 7, + LABEL: "Disintegrator", + GLOW: { + RADIUS: 2, + COLOR: "green", + ALPHA: 1, + RECURSION: 4, + }, + BODY: { + ACCELERATION: base.ACCEL * 0.75, + SPEED: 0.7 * base.SPEED, + FOV: 1.4 * base.FOV + }, + GUNS: [ + { + POSITION: [27, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.assassin]), + TYPE: "poisonbullet" + } + }, { + POSITION: [16, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + COLOR: "green" + } + }, { + POSITION: [5, 8, -1.4, 8, 0, 0, 0] + } + ] +} +Class.formaldehyde = { + PARENT: "genericTank", + LABEL: "Formaldehyde", + DANGER: 7, + BODY: { + FOV: base.FOV * 1.2 + }, + GLOW: { + RADIUS: 2, + COLOR: "green", + ALPHA: 1, + RECURSION: 4, + }, + GUNS: [ + { + POSITION: [21, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun]), + TYPE: "poisonbullet" + } + }, + { + POSITION: [19, 8, 1, 0, 0, 0, 1/3], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun]), + TYPE: "poisonbullet" + } + }, + { + POSITION: [17, 8, 1, 0, 0, 0, 2/3], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun]), + TYPE: "poisonbullet" + } + }, { + POSITION: [16, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + COLOR: "green" + } + } + ] +} +Class.icegun = { + PARENT: "genericTank", + LABEL: "Icegun", + DANGER: 7, + BODY: { + FOV: base.FOV * 1.2 + }, + GLOW: { + RADIUS: 2, + COLOR: "#28B1DE", + ALPHA: 1, + RECURSION: 4, + }, + GUNS: [ + { + POSITION: [21, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun]), + TYPE: "icebullet" + } + }, + { + POSITION: [19, 8, 1, 0, 0, 0, 1/3], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun]), + TYPE: "icebullet" + } + }, + { + POSITION: [17, 8, 1, 0, 0, 0, 2/3], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.minigun]), + TYPE: "icebullet" + } + }, { + POSITION: [16, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + COLOR: "#28B1DE" + } + } + ] +} +Class.frostbite = { + PARENT: "genericTank", + LABEL: 'Frostbite', + DANGER: 7, + GLOW: { + RADIUS: 2, + COLOR: "#28dead", + ALPHA: 1, + RECURSION: 4, + }, + BODY: { + ACCELERATION: base.ACCEL * 0.75, + SPEED: base.SPEED * 0.85, + FOV: base.FOV * 1.2, + }, + GUNS: [{ + POSITION: [24, 8.5, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper]), + TYPE: "poisonicebullet", + } + }, { + POSITION: [19, 2.5, 1, 0, 0, 0, 0], + PROPERTIES: { + COLOR: "#28B1DE" + } + }, { + POSITION: [13.95, 5.15, 1, 0, 0, 0, 0], + PROPERTIES: { + COLOR: "green" + } + }] +}; +Class.chiller = { + PARENT: "genericTank", + LABEL: 'Chiller', + DANGER: 6, + GLOW: { + RADIUS: 2, + COLOR: "#28B1DE", + ALPHA: 1, + RECURSION: 4, + }, + BODY: { + ACCELERATION: base.ACCEL * 0.7, + FOV: 1.2 + }, + GUNS: [{ + POSITION: [24, 8.5, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper]), + TYPE: "icebullet" + } + }, { + POSITION: [13.95, 5.15, 1, 0, 0, 0, 0], + PROPERTIES: { + COLOR: "#28B1DE" + } + }] +}; +Class.freezer = { + PARENT: "genericTank", + DANGER: 7, + LABEL: "Freezer", + GLOW: { + RADIUS: 2, + COLOR: "#28B1DE", + ALPHA: 1, + RECURSION: 4, + }, + BODY: { + ACCELERATION: base.ACCEL * 0.75, + SPEED: 0.7 * base.SPEED, + FOV: 1.4 * base.FOV + }, + GUNS: [ + { + POSITION: [27, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper, g.assassin]), + TYPE: "icebullet" + } + }, { + POSITION: [16, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + COLOR: "#28B1DE" + } + }, { + POSITION: [5, 8, -1.4, 8, 0, 0, 0] + } + ] +} +Class.helecopter = { + PARENT: "genericTank", + LABEL: "Attack Helicopter", + BODY: { + SPEED: 7, + PUSHABILITY: 0, + ACCELERATION: 0.8, + }, + DANGER: 6, + GUNS: [{ + POSITION: [19, 2, 1, 0, -2.5, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.power, g.twin, { speed: 0.7, maxSpeed: 0.7 }, g.flankGuard, { recoil: 1.8 }]), + TYPE: "bullet", + HAS_NO_RECOIL: true, + }, + }, + { + POSITION: [19, 2, 1, 0, 2.5, 0, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.power, g.twin, { speed: 0.7, maxSpeed: 0.7 }, g.flankGuard, { recoil: 1.8 }]), + TYPE: "bullet", + HAS_NO_RECOIL: true, + }, + }, { + POSITION: [2, 2, 1, 0, 0, 180, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.triAngle, g.thruster, g.thruster, g.fakewithrecoil]), + TYPE: "bullet", + AUTOFIRE: true, + }, + }, { + POSITION: [12, 11, 1, 0, 0, 0, 0], + }, + { + POSITION: [26.5, 8, 0.7, 0, 0, 180, 0], + }, + { + POSITION: [5.5, 8, -1.8, 6.5, 0, 180, 0], + }, + ], + TURRETS: [ + { + /* SIZE X Y ANGLE ARC */ + POSITION: [20, -27.5, 0, 0, 360, 1], + TYPE: "helecoptersblade", + }, + { + /* SIZE X Y ANGLE ARC */ + POSITION: [25, 0, 0, 0, 360, 1], + TYPE: "helecopterblade", + }, + ], +}; +Class.twinsniper = { + PARENT: "genericTank", + LABEL: "Twiper", + DANGER: 6, + BODY: { + FOV: 1.1 * base.FOV + }, + GUNS: [ + { + POSITION: [24, 8.5, 1, 0, 5.5, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.sniper]), + TYPE: "bullet" + } + }, + { + POSITION: [24, 8.5, 1, 0, -5.5, 0, .5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.sniper]), + TYPE: "bullet" + } + } + ] +} +Class.backShield = { + PARENT: "genericTank", + LABEL: 'BackShield', + BODY: { + SPEED: 2 * base.SPEED + }, + DANGER: 6, + GUNS: [{ + POSITION: [18, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic]), + TYPE: "bullet" + } + }], + TURRETS: [{ + POSITION: [18, 18, 0, 180, 360, 1], + TYPE: ["backshieldturret", { SHAPE: 12 }], + VULNERABLE: true + }] +}; +Class.bigBackShield = { + PARENT: "genericTank", + LABEL: 'Mega BackShield', + DANGER: 7, + BODY: { + SPEED: 2 * base.SPEED + }, + GUNS: [{ + POSITION: [18, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic]), + TYPE: "bullet" + } + }], + TURRETS: [{ + POSITION: [32, 25, 0, 180, 360, 1], + TYPE: ["backshieldturret", { SHAPE: 12 }], + VULNERABLE: true + }] +}; +Class.mirrorBackShield = { + PARENT: "genericTank", + LABEL: 'BackMirror', + DANGER: 7, + GUNS: [{ + POSITION: [18, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic]), + TYPE: "bullet" + } + }], + TURRETS: [{ + POSITION: [16.7, -18.5, 0, 0, 360, 1], + TYPE: ["mirrorbackshieldturret", { SHAPE: 14 }], + VULNERABLE: true + }] +}; +Class.attacker = { + PARENT: "twin", + LABEL: "Attacker", + DANGER: 7, + BODY: { + SPEED: 2 * base.SPEED + }, + TURRETS: [{ + POSITION: [18, 18, 0, 180, 360, 1], + TYPE: ["backshieldturret", { SHAPE: 12 }], + VULNERABLE: true + }] +} +Class.wark = { + PARENT: "genericTank", + LABEL: "Wark", + DANGER: 6, + STAT_NAMES: statnames.trap, + GUNS: [{ + POSITION: [13, 8, 1, 0, -5.5, -8, 0] + }, { + POSITION: [4, 8, 1.7, 13, -5.5, -8, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, g.twin, g.halfrange]), + TYPE: "trap", + STAT_CALCULATOR: "trap", + } + }, { + POSITION: [13, 8, 1, 0, 5.5, 8, 0.5] + }, { + POSITION: [4, 8, 1.7, 13, 5.5, 8, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, g.twin, g.halfrange]), + TYPE: "trap", + STAT_CALCULATOR: "trap", + } + }] +} +Class.waterfall = { + PARENT: "genericTank", + LABEL: "Waterfall", + DANGER: 7, + GUNS: [ + { + POSITION: [21, 14, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.destroyer]), + TYPE: "bullet", + }, + }, + { + POSITION: [19, 2, 1, 0, -2.5, 180, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.power, g.twin, { speed: 0.7, maxSpeed: 0.7 }, g.flankGuard, { recoil: 1.8 }]), + TYPE: "bullet", + }, + }, + { + POSITION: [19, 2, 1, 0, 2.5, 180, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.power, g.twin, { speed: 0.7, maxSpeed: 0.7 }, g.flankGuard, { recoil: 1.8 }]), + TYPE: "bullet", + }, + }, + { + POSITION: [12, 11, 1, 0, 0, 180, 0], + }, + ], +} +Class.auto2 = { + PARENT: "genericTank", + LABEL: "Auto-2", + DANGER: 5, + FACING_TYPE: ["spin", {speed: 0.02}], + TURRETS: [{ + POSITION: [11, 8, 0, 0, 190, 0], + TYPE: "autoTankGun" + }, { + POSITION: [11, 8, 0, 180, 190, 0], + TYPE: "autoTankGun" + }] +} +Class.swivel2 = { + PARENT: "genericTank", + LABEL: "Swivel-2", + DANGER: 6, + FACING_TYPE: ["spin", {speed: 0.02}], + TURRETS: [{ + POSITION: [9, 7, 0, 0, 360, 1], + TYPE: "swivelAutoGun" + }, { + POSITION: [9, 7, 0, 180, 360, 1], + TYPE: "swivelAutoGun" + }] +} +Class.swivel3 = { + PARENT: "genericTank", + LABEL: "Swivel-3", + DANGER: 7, + FACING_TYPE: ["spin", {speed: 0.02}], + TURRETS: [{ + POSITION: [9, 7, 0, 0, 360, 1], + TYPE: "swivelAutoGun" + }, { + POSITION: [9, 7, 0, 120, 360, 1], + TYPE: "swivelAutoGun" + }, { + POSITION: [9, 7, 0, 240, 360, 1], + TYPE: "swivelAutoGun" + }] +} +Class.axis4 = { + PARENT: "genericTank", + LABEL: "Axis-4", + DANGER: 7, + FACING_TYPE: ["spin", {speed: 0.02}], + TURRETS: [{ + POSITION: [9, 7, 0, 0, 360, 1], + TYPE: "swivelAutoGun" + }, { + POSITION: [9, 7, 0, 180, 360, 1], + TYPE: "swivelAutoGun" + }, { + POSITION: [11, 8, 0, 90, 190, 0], + TYPE: "autoTankGun" + }, { + POSITION: [11, 8, 0, 270, 190, 0], + TYPE: "autoTankGun" + }] +} +const timer = (run, duration) => { + let timer = setInterval(() => run(), 31.25); + setTimeout(() => { + clearInterval(timer); + }, duration * 1000); +}; + const damageOnTick = (body, instance, multiplier, duration, stopAtSetHealth, hitsOwnTeam) => { + if (!instance) return + if (!instance.damageOnTicking && !instance.godmode && !instance.invuln && (instance.type == "tank" || instance.type == "food" || instance.type == "miniboss" || instance.type == "crasher") && instance.team != body.team) { + instance.damageOnTicking = true; + setTimeout(() => { + instance.damageOnTicking = false; + }, 2 * duration * 1000); + timer(() => { + if (instance.damageOnTicking && instance.health.amount > stopAtSetHealth && instance.health.amount - (multiplier * 0.5) > stopAtSetHealth) { + instance.health.amount -= multiplier * 0.5; + } //else {if (instance.health.amount - (multiplier * 0.5) < stopAtSetHealth) {instance.health.amount === stopAtSetHealth}} + }, 2 * duration); + } +}; +const iceOnTick = (body, instance, multiplier, duration, hitsOwnTeam) => { + if (!instance) return + if (!instance.invuln && !instance.godmode && (instance.type == "tank" || instance.type == "food" || instance.type == "miniboss" || instance.type == "crasher") && instance.team != body.team) timer(() => { + instance.velocity.x /= 1.05 * multiplier; + instance.velocity.y /= 1.05 * multiplier; + }, 1.5 * duration); +}; +Class.acidsmasher = { + PARENT: "genericSmasher", + LABEL: "Injector", + DANGER: 7, + TURRETS: [ + { + POSITION: [21.8, 0, 0, 0, 360, 0], + TYPE: "greenSmasherBody", + }, { + POSITION: [22.3, 0, 0, 0, 360, -1], + TYPE: "smasherBody" + } + ], + ON: [{ + event: "damage", + handler: ({ body, damageTool }) => { + damageOnTick(body, damageTool[0], 1, 1, 1, true); + } + }] +} +Class.autoinceptionistbody = { + PARENT: "genericTank", + LABEL: "Auto-Inceptionist base", + DANGER: 4, + GUNS: [ + { + POSITION: [18, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic]), + TYPE: "ceptionistbullet", + } + } + ] +} +Class.surge = { + PARENT: "genericTank", + LABEL: 'Surge', + DANGER: 7, + BODY: { + ACCELERATION: base.ACCEL * .6, + SPEED: base.SPEED * .95, + FOV: 1.2 + }, + GUNS: [{ + POSITION: [24, 8.5, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper]), + TYPE: "bullet", + IGNORES_CANSHOOT_CHECKS: true + } + }, { + POSITION: [0, 0, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.fake, g.lance]), + TYPE: "bullet", + ALT_FIRE: true + } + }], + TURRETS: [ + { + POSITION: [9, 0, 0, 0, 360, 1], + TYPE: ["surgeDeco", { MIRROR_MASTER_ANGLE: true }], + }, + ], + VARIABLES: { + surgeMax: 88, + surgeTimer: 0, + firingStage: 1 + }, + ON: [{ + event: "altFire", + handler: ({ body, gun }) => { + if (body.variables.firingStage === 1) body.variables.firingStage = 2 + } + }, { + event: "tick", + handler: ({ body, gun }) => { + //setTimeout(() => sockets.broadcast(body.guns[0].shootSettings.toString()), 500); + switch(body.variables.firingStage) { + case 2: + body.guns[0].canShoot = false; + body.guns[0].shootSettings = combineStats([g.lance, g.emplaser, { health: 0.1, recoil: 0 }]); + body.guns[0].setBulletType('surgeempBullet'); + body.guns[0].fire(); + + body.variables.surgeTimer++; + if (body.variables.surgeTimer === body.variables.surgeMax) { + body.variables.firingStage++; + } + break; + case 3: + body.guns[0].recoilVelocity = 0; + body.guns[0].shootSettings = combineStats([g.basic, { health: 2, pen: 2.5, speed: 3, maxSpeed: 3, size: 1.2, range: 0.5, recoil: 5, damage: 0.3 }, g.tonsmorerecoil, g.noSpread]); + body.guns[0].setBulletType('lineEMP'); + body.guns[0].fire(); + body.variables.firingStage++; + break; + case 4: + body.variables.surgeTimer--; + if (body.variables.surgeTimer === 0) { + body.variables.firingStage = 1; + body.guns[0].shootSettings = combineStats([g.basic, g.sniper]); + body.guns[0].setBulletType('bullet'); + body.guns[0].canShoot = true; + } + break; + } + } + }], + GLOW: { + RADIUS: 1.2, + COLOR: "spaceGem", + ALPHA: 1, + RECURSION: 3, + } +} +Class.flashfire = { + PARENT: "genericTank", + LABEL: 'Flashfire', + DANGER: 7, + BODY: { + ACCELERATION: base.ACCEL * 0.6, + SPEED: base.SPEED * 0.95, + FOV: 1.2 + }, + GUNS: [{ + POSITION: [24, 8.5, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper]), + TYPE: "bullet", + IGNORES_CANSHOOT_CHECKS: true + } + }, { + POSITION: [0, 0, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.fake, g.lance]), + TYPE: "bullet", + ALT_FIRE: true + } + }], + TURRETS: [ + { + POSITION: [9, 0, 0, 0, 360, 1], + TYPE: ["surgeDeco", { COLOR: "#de2410", MIRROR_MASTER_ANGLE: true }], + }, + ], + VARIABLES: { + surgeMax: 88, + surgeTimer: 0, + firingStage: 1 + }, + ON: [{ + event: "altFire", + handler: ({ body, gun }) => { + if (body.variables.firingStage === 1) body.variables.firingStage = 2 + } + }, { + event: "tick", + handler: ({ body, gun }) => { + //setTimeout(() => sockets.broadcast(body.guns[0].shootSettings.toString()), 500); + switch(body.variables.firingStage) { + case 2: + body.guns[0].canShoot = false; + body.guns[0].shootSettings = combineStats([g.lance, g.emplaser, { health: 0.1, recoil: 0 }]); + body.guns[0].setBulletType('flashfireBullet'); + body.guns[0].fire(); + + body.variables.surgeTimer++; + if (body.variables.surgeTimer === body.variables.surgeMax) { + body.variables.firingStage++; + } + break; + case 3: + body.guns[0].shootSettings = combineStats([g.basic, g.pelleter, { speed: 6, maxSpeed: 6, damage: 1.2, size: 0.65, spray: 2.3, recoil: 1 }]); + body.guns[0].setBulletType('bullet'); + body.guns[0].fire(), + body.guns[0].recoilVelocity = 56; + setTimeout(() => body.guns[0].fire(), 15); + setTimeout(() => body.guns[0].fire(), 30); + setTimeout(() => body.guns[0].fire(), 45); + setTimeout(() => body.guns[0].fire(), 60); + setTimeout(() => body.guns[0].fire(), 75); + setTimeout(() => body.guns[0].fire(), 90); + setTimeout(() => body.guns[0].fire(), 105); + setTimeout(() => body.guns[0].fire(), 120); + setTimeout(() => body.guns[0].fire(), 135); + setTimeout(() => body.guns[0].fire(), 150); + setTimeout(() => body.guns[0].fire(), 165); + setTimeout(() => body.guns[0].fire(), 180); + setTimeout(() => body.guns[0].fire(), 195); + setTimeout(() => body.guns[0].fire(), 210); + setTimeout(() => body.guns[0].fire(), 225); + setTimeout(() => body.guns[0].fire(), 240); + setTimeout(() => body.guns[0].fire(), 255); + setTimeout(() => body.guns[0].fire(), 270); + setTimeout(() => body.guns[0].fire(), 285); + setTimeout(() => body.guns[0].fire(), 300); + body.variables.firingStage++; + break; + case 4: + body.variables.surgeTimer--; + if (body.variables.surgeTimer === 0) { + body.variables.firingStage = 1; + body.guns[0].shootSettings = combineStats([g.basic, g.sniper]); + body.guns[0].setBulletType('bullet'); + body.guns[0].recoilVelocity = 0; + body.guns[0].canShoot = true; + } + break; + } + } + }], + GLOW: { + RADIUS: 1.2, + COLOR: "#de2410", + ALPHA: 1, + RECURSION: 3, + } +} +Class.brella = { + PARENT: "genericTank", + LABEL: "Nero-Brella", + DANGER: 7, + SYNC_TURRET_SKILLS: true, + GUNS: [{ + POSITION: [20, 8, 1, 0, 0, 0, 0.2], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard]), + TYPE: "bullet" + } + }, { + POSITION: [1, 10, 0, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.brella]), + TYPE: "brellaShield", + ALT_FIRE: true, + MAX_CHILDREN: 1, + //ALPHA: 1 + } + }], + TURRETS: [ + { + POSITION: [5, 0, 0, 0, 360, 1], + TYPE: "brellaDeco", + }, + ], +}; +Class.lancer = { + PARENT: "genericLancer", + LABEL: "Lancer", + //UPGRADE_TOOLTIP: "Daily Tank!", + //UPGRADE_COLOR: "rainbow", + BODY: { + SPEED: base.SPEED * 1.3, + DAMAGE: base.DAMAGE * 0.9 + }, + GUNS: [ + { + POSITION: [20, 15, 0.001, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.lance, { recoil: 0 }]), + TYPE: ["bullet", { ALPHA: 0 }], + AUTOFIRE: true, + STAT_CALCULATOR: "lancer" + } + }, + { + POSITION: [25, 15, 0.001, 0, 0, 0, 0] + } + ] +} +Class.slasher = { + PARENT: "lancer", + LABEL: "Slasher", + DANGER: 7, + BODY: { + SPEED: 2.3 * base.SPEED + }, + TURRETS: [{ + POSITION: [18, 18, 0, 180, 360, 1], + TYPE: ["backshieldturret", { SHAPE: 12 }], + VULNERABLE: true + }] +} +Class.lancebrid = makeOver('lancer', "Lancebrid", {count: 1, independent: true, cycle: false}); +Class.autolancer = makeAuto('lancer', "Auto-Lancer"); +Class.autolancebrid = makeAuto('lancebrid', "Auto-Lancebrid"); +Class.chasseur = { + PARENT: "genericLancer", + LABEL: "Chasseur", + DANGER: 6, + BODY: { + SPEED: base.SPEED * 1.3, + DAMAGE: base.DAMAGE * 1.1 + }, + HAS_NO_RECOIL: true, + GUNS: [ + { + POSITION: [25, 15, 0.001, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.chasseur]), + TYPE: ["bullet", { ALPHA: 0 }], + AUTOFIRE: true, + STAT_CALCULATOR: "lancer" + } + }, + { + POSITION: [30, 15, 0.001, 0, 0, 0, 0] + } + ] +} +Class.trailblazer = { + PARENT: "genericLancer", + LABEL: "Trailblazer", + DANGER: 7, + BODY: { + HEALTH: 0.8 * base.HEALTH, + SHIELD: 0.8 * base.SHIELD, + DENSITY: 0.6 * base.DENSITY, + DAMAGE: 0.9 * base.DAMAGE + }, + HAS_NO_RECOIL: false, + GUNS: [ + { + POSITION: [20, 15, 0.001, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.lance]), + TYPE: ["bullet", { ALPHA: 0 }], + AUTOFIRE: true, + STAT_CALCULATOR: "lancer", + HAS_NO_RECOIL: true + } + }, + { + POSITION: [25, 15, 0.001, 0, 0, 0, 0] + }, + { + POSITION: [16, 8, 1, 0, 0, 150, 0.1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), + TYPE: "bullet", + LABEL: "thruster", + }, + }, + { + POSITION: [16, 8, 1, 0, 0, 210, 0.1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), + TYPE: "bullet", + LABEL: "thruster", + }, + } + ] +} +Class.katana = { + PARENT: "genericLancer", + LABEL: "Katana", + DANGER: 7, + BODY: { + SPEED: base.SPEED * 1.4, + DAMAGE: base.DAMAGE * 0.9 + }, + VARIABLES: { + dashes: 3 + }, + GUNS: [ + { + POSITION: [20, 15, 0.001, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.lance, { recoil: 0 }]), + TYPE: ["bullet", { ALPHA: 0 }], + AUTOFIRE: true, + STAT_CALCULATOR: "lancer" + } + }, + { + POSITION: [25, 15, 0.001, 0, 0, 0, 0] + }, { + POSITION: [1, 15, 1, 0, 0, 180, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { size: 1.4, range: 0.09, speed: 0, maxSpeed: 0 }]), + TYPE: "katanaparticle", + ALT_FIRE: true, + IDENTIFIER: "dash" + } + } + ], + TURRETS: [ + { + POSITION: [9, 0, 0, 0, 360, 1], + TYPE: "katanaDeco", + }, + ], + ON: [{ + event: "altFire", + handler: ({ body, gun }) => { + if (gun.identifier = "dash") { + if (body.variables.dashes > 0) { + body.variables.dashes -= 1; + if (body.variables.dashes < 1) body.guns[2].canShoot = false; + body.sendMessage(`Dashes: ${body.variables.dashes.toString()}`) + body.x += 200 * Math.cos(body.facing); + body.y += 200 * Math.sin(body.facing); + setTimeout(() => { + if (body.guns[2] !== undefined) { + body.variables.dashes += 1; + body.sendMessage(`Dashes: ${body.variables.dashes.toString()}`) + body.guns[2].canShoot = true; + } + }, 5000); + } + } + } + }] +} +Class.shadow = { + PARENT: "propel", + LABEL: "Shadow", + DANGER: 7, + VARIABLES: { + dashes: 3 + }, + BODY: { + HEALTH: 0.9 * base.HEALTH, + SHIELD: 0.9 * base.SHIELD, + DENSITY: 0.7 * base.DENSITY, + }, + GUNS: [ + { + POSITION: [18, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.triAngleFront, { recoil: 4 }]), + TYPE: "bullet", + LABEL: "Front", + }, + }, + { + POSITION: [16, 8, 1, 0, 0, 180, 0.1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), + TYPE: "bullet", + LABEL: "thruster", + }, + }, { + POSITION: [1, 15, 1, 0, 0, 180, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { size: 1.4, range: 0.09, speed: 0, maxSpeed: 0 }]), + TYPE: "shadowparticle", + ALT_FIRE: true, + IDENTIFIER: "dash" + } + } + ], + TURRETS: [ + { + POSITION: [9, 0, 0, 0, 360, 1], + TYPE: "katanaDeco", + }, + ], + ON: [{ + event: "altFire", + handler: ({ body, gun }) => { + if (gun.identifier = "dash") { + if (body.variables.dashes > 0) { + body.variables.dashes -= 1; + if (body.variables.dashes < 1) body.guns[2].canShoot = false; + body.sendMessage(`Dashes: ${body.variables.dashes.toString()}`) + body.x += 200 * Math.cos(body.facing); + body.y += 200 * Math.sin(body.facing); + setTimeout(() => { + if (body.guns[2] !== undefined) { + body.variables.dashes += 1; + body.sendMessage(`Dashes: ${body.variables.dashes.toString()}`) + body.guns[2].canShoot = true; + } + }, 5000); + } + } + } + }] +} +Class.dasher = { + PARENT: "genericLancer", + LABEL: "Dasher", + DANGER: 7, + BODY: { + SPEED: base.SPEED * 1.4, + DAMAGE: base.DAMAGE * 0.9 + }, + VARIABLES: { + dashes: 3 + }, + GUNS: [ + { + POSITION: [20, 15, 0.001, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.lance, { recoil: 0 }]), + TYPE: ["bullet", { ALPHA: 0 }], + AUTOFIRE: true, + STAT_CALCULATOR: "lancer" + } + }, + { + POSITION: [25, 15, 0.001, 0, 0, 0, 0] + }, { + POSITION: [0, 15, 1, 0, 0, 180, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.fakewithrecoil, { recoil: 10 }]), + TYPE: "katanaparticle", + ALT_FIRE: true, + IDENTIFIER: "dash" + } + } + ], + ON: [{ + event: "altFire", + handler: ({ body, gun }) => { + if (gun.identifier = "dash") { + if (body.variables.dashes > 0) { + body.variables.dashes -= 1; + sockets.broadcast(body.variables.dashes.toString()) + setTimeout(() => { + if (body.guns[2] !== undefined) { + body.variables.dashes += 1; + sockets.broadcast(body.variables.dashes.toString()) + body.guns[2].canShoot = true; + } + }, 5000); + } else { + body.guns[2].canShoot = false; + } + } + } + }] +} +Class.bayonet = { + PARENT: "genericLancer", + LABEL: "Bayonet", + DANGER: 6, + STAT_NAMES: statnames.mixed, + BODY: { + SPEED: base.SPEED * 1.3, + DAMAGE: base.DAMAGE * 0.9 + }, + HAS_NO_RECOIL: false, + GUNS: [ + { + POSITION: [20, 15, 0.001, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.lance, {recoil: 0}]), + TYPE: ["bullet", { ALPHA: 0 }], + AUTOFIRE: true, + STAT_CALCULATOR: "lancer" + } + }, + { + POSITION: [25, 15, 0.001, 0, 0, 0, 0] + }, { + POSITION: [13, 7, 1, 0, 0, 0, 0.2], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { reload: 1.3, recoil: 0 }]), + TYPE: "bullet" + } + } + ] +} +Class.wakizashi = { + PARENT: "genericLancer", + LABEL: "Wakizashi", + DANGER: 7, + BODY: { + SPEED: base.SPEED * 1.3, + DAMAGE: base.DAMAGE * 1.1 + }, + HAS_NO_RECOIL: true, + GUNS: [ + { + POSITION: [25, 15, 0.001, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.chasseur]), + TYPE: ["bullet", { ALPHA: 0 }], + AUTOFIRE: true, + STAT_CALCULATOR: "lancer" + } + }, + { + POSITION: [30, 15, 0.001, 0, 0, 0, 0] + }, { + POSITION: [13, 7, 1, 0, 0, 0, 0.2], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { reload: 1.3, recoil: 0}]), + TYPE: "bullet" + } + } + ] +} + +Class.propel = { + PARENT: "genericTank", + LABEL: "Propeller", + BODY: { + HEALTH: 0.9 * base.HEALTH, + SHIELD: 0.9 * base.SHIELD, + DENSITY: 0.7 * base.DENSITY, + }, + DANGER: 5, + GUNS: [ + { + POSITION: [18, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.triAngleFront, { recoil: 4 }]), + TYPE: "bullet", + LABEL: "Front", + }, + }, + { + POSITION: [16, 8, 1, 0, 0, 180, 0.1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), + TYPE: "bullet", + LABEL: "thruster", + }, + }, + ], +} +Class.bateau = { + PARENT: "genericTank", + LABEL: "Bateau", + BODY: { + HEALTH: 0.9 * base.HEALTH, + SHIELD: 0.9 * base.SHIELD, + DENSITY: 0.7 * base.DENSITY, + ACCELERATION: 2 * base.ACCEL, + }, + DANGER: 6, + GUNS: [ + { + POSITION: [18, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.triAngleFront, { recoil: 4 }]), + TYPE: "bullet", + LABEL: "Front", + }, + }, + { + POSITION: [16, 8, 1.3, 0, 0, 180, 2], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster, { reload: 0.6, spray: 1.5, recoil: 2.3, damage: 0.7, range: 0.5 }]), + TYPE: "bullet", + LABEL: "thruster", + }, + }, + ], +} +Class.assblaster = { + PARENT: "genericTank", + LABEL: "Ass Blaster", + BODY: { + HEALTH: 0.9 * base.HEALTH, + SHIELD: 0.9 * base.SHIELD, + DENSITY: 0.7 * base.DENSITY, + ACCELERATION: 2.2 * base.ACCEL, + }, + DANGER: 7, + GUNS: [ + { + POSITION: [18, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.triAngleFront, { recoil: 4 }]), + TYPE: "bullet", + LABEL: "Front", + }, + }, + { + POSITION: [17, 12, 1.5, 0, 0, 180, 2.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster, { reload: 0.4, spray: 2, recoil: 2.8, damage: 0.6, range: 0.35, size: 1.5 }]), + TYPE: ["bullet", { ALPHA: 0.5 }], + LABEL: "thruster", + }, + }, + ], +} +Class.rocker = { + PARENT: "genericTank", + LABEL: "Rocker", + BODY: { + HEALTH: 0.5 * base.HEALTH, + SHIELD: 0.5 * base.SHIELD, + DENSITY: 0.4 * base.DENSITY, + }, + DANGER: 7, + GUNS: [ + { + POSITION: [18, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.triAngleFront, { recoil: 4 }]), + TYPE: "bullet", + LABEL: "Front", + }, + }, + { + POSITION: [16, 8, 1.3, 0, 0, 150, 2], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster, { reload: 0.6, spray: 1.5, recoil: 2.3, damage: 0.7, range: 0.5 }]), + TYPE: "bullet", + LABEL: "thruster", + }, + }, + { + POSITION: [16, 8, 1.3, 0, 0, 210, 2], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster, { reload: 0.6, spray: 1.5, recoil: 2.3, damage: 0.7, range: 0.5 }]), + TYPE: "bullet", + LABEL: "thruster", + }, + }, + ], +} +Class.jouster = { + PARENT: "genericLancer", + LABEL: "Jouster", + DANGER: 6, + BODY: { + HEALTH: 0.7 * base.HEALTH, + SHIELD: 0.7 * base.SHIELD, + DENSITY: 0.7 * base.DENSITY, + }, + STAT_NAMES: statnames.mixed, + HAS_NO_RECOIL: false, + GUNS: [ + { + POSITION: [20, 15, 0.001, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.lance, { recoil: 2 }]), + TYPE: ["bullet", { ALPHA: 0 }], + AUTOFIRE: true, + STAT_CALCULATOR: "lancer" + } + }, + { + POSITION: [25, 15, 0.001, 0, 0, 0, 0] + }, + { + POSITION: [16, 8, 1, 0, 0, 180, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster, { recoil: 0.6 }]), + TYPE: "bullet", + LABEL: "thruster", + }, + }, + ] +} +Class.knight = { + PARENT: "genericLancer", + LABEL: "Knight", + DANGER: 7, + BODY: { + HEALTH: 0.6 * base.HEALTH, + SHIELD: 0.6 * base.SHIELD, + DENSITY: 0.7 * base.DENSITY, + ACCELERATION: 1.8 * base.ACCEL, + }, + STAT_NAMES: statnames.mixed, + HAS_NO_RECOIL: false, + GUNS: [ + { + POSITION: [20, 15, 0.001, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.lance, { recoil: 0 }]), + TYPE: ["bullet", { ALPHA: 0 }], + AUTOFIRE: true, + STAT_CALCULATOR: "lancer" + } + }, + { + POSITION: [25, 15, 0.001, 0, 0, 0, 0] + }, + { + POSITION: [16, 8, 1.3, 0, 0, 180, 2], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster, { reload: 0.6, spray: 1.5, recoil: 2, damage: 0.7, range: 0.5 }]), + TYPE: "bullet", + LABEL: "thruster", + }, + }, + ] +} +Class.fencer = { + PARENT: "genericLancer", + LABEL: "Fencer", + DANGER: 7, + BODY: { + HEALTH: 0.7 * base.HEALTH, + SHIELD: 0.7 * base.SHIELD, + DENSITY: 0.7 * base.DENSITY, + DAMAGE: base.DAMAGE * 1.1 + }, + STAT_NAMES: statnames.mixed, + HAS_NO_RECOIL: false, + GUNS: [ + { + POSITION: [25, 15, 0.001, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.chasseur, { recoil: 2 }]), + TYPE: ["bullet", { ALPHA: 0 }], + AUTOFIRE: true, + STAT_CALCULATOR: "lancer" + } + }, + { + POSITION: [30, 15, 0.001, 0, 0, 0, 0] + }, + { + POSITION: [16, 8, 1, 0, 0, 180, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster, { recoil: 0.6 }]), + TYPE: "bullet", + LABEL: "thruster", + }, + }, + ] +} +Class.arisaka = { + PARENT: "genericLancer", + LABEL: "Arisaka", + DANGER: 7, + BODY: { + HEALTH: 0.7 * base.HEALTH, + SHIELD: 0.7 * base.SHIELD, + DENSITY: 0.7 * base.DENSITY, + DAMAGE: base.DAMAGE * 1.1 + }, + STAT_NAMES: statnames.mixed, + HAS_NO_RECOIL: false, + GUNS: [ + { + POSITION: [20, 15, 0.001, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.lance, { recoil: 2 }]), + TYPE: ["bullet", { ALPHA: 0 }], + AUTOFIRE: true, + STAT_CALCULATOR: "lancer" + } + }, + { + POSITION: [25, 15, 0.001, 0, 0, 0, 0] + }, { + POSITION: [13, 7, 1, 0, 0, 0, 0.2], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { reload: 1.3, recoil: 0 }]), + TYPE: "bullet" + } + }, + { + POSITION: [16, 8, 1, 0, 0, 180, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster, { recoil: 0.6 }]), + TYPE: "bullet", + LABEL: "thruster", + }, + }, + ] +} +Class.saturn = { + PARENT: "genericSmasher", + LABEL: "Saturn", + BODY: { + DENSITY: 2 * base.DENSITY + }, + TURRETS: [ + { + POSITION: [21.5, 0, 0, 0, 360, 0], + TYPE: "smasherBody" + }, + { + POSITION: [3, 0, 0, 0, 360, 1], + TYPE: "saturnDeco" + }, + { + POSITION: [34, 0, 0, 0, 360, 0], + TYPE: "saturnturretBase" + } + ], +} +Class.choker = { + PARENT: "genericTank", + LABEL: "Choker", + DANGER: 7, + STAT_NAMES: statnames.mixed, + GUNS: [ + { + POSITION: [14, 12, 0.8, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { size: 0.8, reload: 1.2 }]), + TYPE: 'undertowBullet' + } + }, + { + POSITION: [11.25, 8, 0.15, 4.25, 4, 13.5, 0] + }, + { + POSITION: [11.25, 8, 0.15, 4.25, -4, -13.5, 0] + }, + { + POSITION: [20, 15, 0.001, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.lance, { recoil: 0 }]), + TYPE: ["bullet", { ALPHA: 0 }], + AUTOFIRE: true, + STAT_CALCULATOR: "lancer" + } + }, + ] + } +Class.noble = { + PARENT: "director", + LABEL: "Noble", + DANGER: 6, + BODY: { + ACCELERATION: base.ACCEL * 2, + SPEED: base.SPEED * 1.8 + }, + TURRETS: [{ + POSITION: [14, 0, 0, 0, 360, 2], + TYPE: ["turretBasenoguns", { COLOR: "#a2c4fc" }], + } + ], +} +Class.helium = { + PARENT: "overseer", + LABEL: "Helium", + DANGER: 7, + BODY: { + ACCELERATION: base.ACCEL * 2, + SPEED: base.SPEED * 1.8 + }, + TURRETS: [{ + POSITION: [14, 0, 0, 0, 360, 2], + TYPE: ["turretBasenoguns", { COLOR: "#a2c4fc" }], + } + ], +} +Class.neon = { + PARENT: "cruiser", + LABEL: "Neon", + DANGER: 7, + BODY: { + ACCELERATION: base.ACCEL * 2, + SPEED: base.SPEED * 1.8 + }, + TURRETS: [{ + POSITION: [14, 0, 0, 0, 360, 2], + TYPE: ["turretBasenoguns", { COLOR: "#a2c4fc" }], + } + ], +} +Class.argon = { + PARENT: "underseer", + LABEL: "Argon", + DANGER: 7, + BODY: { + ACCELERATION: base.ACCEL * 2, + SPEED: base.SPEED * 1.8 + }, + TURRETS: [{ + POSITION: [14, 0, 0, 0, 360, 2], + TYPE: ["turretBasenoguns", { COLOR: "#a2c4fc" }], + } + ], +} +Class.krypton = { + PARENT: "gundirector", + LABEL: "Krypton", + DANGER: 7, + BODY: { + ACCELERATION: base.ACCEL * 2, + SPEED: base.SPEED * 1.8 + }, + TURRETS: [{ + POSITION: [14, 0, 0, 0, 360, 2], + TYPE: ["turretBasenoguns", { COLOR: "#a2c4fc" }], + } + ], +} +Class.xenon = { + PARENT: "spawner", + LABEL: "Xenon", + DANGER: 7, + BODY: { + ACCELERATION: base.ACCEL * 2, + SPEED: base.SPEED * 1.8 + }, + TURRETS: [{ + POSITION: [14, 0, 0, 0, 360, 2], + TYPE: ["turretBasenoguns", { COLOR: "#a2c4fc" }], + } + ], +} +Class.radon = { + PARENT: "directdrive", + LABEL: "Radon", + DANGER: 7, + BODY: { + ACCELERATION: base.ACCEL * 2, + SPEED: base.SPEED * 1.8 + }, + TURRETS: [{ + POSITION: [14, 0, 0, 0, 360, 2], + TYPE: ["turretBasenoguns", { COLOR: "#a2c4fc" }], + }, { + POSITION: [9, 0, 0, 0, 360, 1], + TYPE: "overdriveDeco", + }, + ], +} +Class.accelmachinegun = { + PARENT: "genericTank", + LABEL: "Watt", + DANGER: 6, + GUNS: [ + { + POSITION: [8, .1, -54, 19, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.fake]), + TYPE: "bullet", + COLOR: 12 + } + }, + { + POSITION: [12, 10, 1.4, 8, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.rainmaker]), + TYPE: ["bullet", { MOTION_TYPE: "accelerate" }] + } + } + ] +} +Class.accelArtillery = { + PARENT: "genericTank", + LABEL: "Cannon", + DANGER: 7, + GUNS: [ + { + POSITION: [8, .1, -37, 19, -6, -7, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery, g.fake]), + TYPE: "bullet", + COLOR: 12 + } + }, + { + POSITION: [8, .1, -37, 19, 6, 7, 0.75], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery, g.fake]), + TYPE: "bullet", + COLOR: 12 + } + }, + { + POSITION: [17, 3, 1, 0, -6, -7, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery, g.rainmaker]), + TYPE: "bullet", + LABEL: "Secondary", + MOTION_TYPE: "accelerate" + }, + }, + { + POSITION: [17, 3, 1, 0, 6, 7, 0.75], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery, g.rainmaker]), + TYPE: "bullet", + LABEL: "Secondary", + MOTION_TYPE: "accelerate" + }, + }, + { + POSITION: [19, 12, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.artillery]), + TYPE: "bullet", + LABEL: "Heavy", + }, + }, + ], +} +Class.gatlinggun = { + PARENT: "genericTank", + LABEL: "Gatling Gun", + DANGER: 6, + GUNS: [{ + POSITION: [14, 10, 1.3, 8, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.focal]), + TYPE: "bullet", + }, + }, + ], +} +Class.accelgatlinggun = { + PARENT: "genericTank", + LABEL: "Charger", + DANGER: 7, + BODY: { + FOV: base.FOV * 1.2 + }, + GUNS: [ + { + POSITION: [8, .1, -54, 21, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.focal, g.fake]), + TYPE: "bullet", + COLOR: 12 + } + }, + { + POSITION: [14, 10, 1.3, 8, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.focal, g.rainmaker]), + TYPE: ["bullet", { MOTION_TYPE: "accelerate" }] + }, + }, + ] +} +Class.Gatlinception = { + PARENT: "genericTank", + LABEL: "Gatceptioner", + DANGER: 7, + GUNS: [ +{ + POSITION: [14, 10, 1.3, 8, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.focal]), + TYPE: "autobullet", + }, + }, + ], + TURRETS: [{ + POSITION: [6.5, 22, 0, 0, 0, 0], + TYPE: ["autoTurret", { INDEPENDENT: true, MIRROR_MASTER_ANGLE: true }] + } + ] +} +Class.Sprayinception = { + PARENT: "genericTank", + LABEL: "Sprayceptioner", + DANGER: 7, + GUNS: [ + { + POSITION: [23, 7, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.lowPower, g.pelleter, { recoil: 1.15 }]), + TYPE: "bullet" + } + }, + { + POSITION: [12, 10, 1.4, 8, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun]), + TYPE: "autobullet" + } + }, + ], + TURRETS: [{ + POSITION: [6.5, 20, 0, 0, 0, 0], + TYPE: ["autoTurret", { INDEPENDENT: true, MIRROR_MASTER_ANGLE: true }] + } + ] +} +Class.polygun = { + PARENT: "genericTank", + LABEL: 'Software', + SHAPE: 8, + DANGER: 7, + STAT_NAMES: statnames.mixed, + BODY: { + SPEED: base.SPEED * 0.8, + FOV: 1.1 + }, + GUNS: [{ + POSITION: [18, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard]), + TYPE: "bullet" + } + }, { + POSITION: [5, 16.5, 1, 10.5, 0, 180, 0] + }, { + POSITION: [2, 19.5, 1.01, 15.5, 0, 180, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.factory, { health: 0.9 }]), + TYPE: "polygunMinion", + STAT_CALCULATOR: "drone", + AUTOFIRE: true, + SYNCS_SKILLS: true, + MAX_CHILDREN: 1 + } + }, { + POSITION: [12, 19.5, 1, 0, 0, 180, 0] + }] +}; +Class.ak47 = { + PARENT: "genericTank", + LABEL: "AK-47", + DANGER: 7, + GUNS: [ + { + POSITION: [22, 2, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.power, { reload: 1.25, speed: 1.1, maxSpeed: 1.1, damage: 0.5, health: 1.3, pen: 1.4 }]), + TYPE: "bullet", + }, + }, + { + POSITION: [5.5, 7, -1.8, 6.5, 0, 0, 0], + }, + ], +} +Class.icetrapper = { + PARENT: "genericTank", + LABEL: "Ice Trapper", + STAT_NAMES: statnames.trap, + DANGER: 6, + GUNS: [ + { + POSITION: { + LENGTH: 15, + WIDTH: 7 + } + }, + { + POSITION: { + LENGTH: 3, + WIDTH: 7, + ASPECT: 1.7, + X: 15 + }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap]), + TYPE: "icetrap", + STAT_CALCULATOR: "trap" + } + }, { + POSITION: [13.95, 5.15, 1, 0, 0, 0, 0], + PROPERTIES: { + COLOR: "#28B1DE" + } + } + ] +} +Class.icebuilder = { + PARENT: "genericTank", + LABEL: "Igloo", + STAT_NAMES: statnames.trap, + DANGER: 7, + BODY: { + SPEED: 0.7 * base.SPEED, + FOV: 1.15 * base.FOV + }, + GUNS: [ + { + POSITION: [18, 12, 1, 0, 0, 0, 0], + }, + { + POSITION: [2, 12, 1.1, 18, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, g.setTrap]), + TYPE: "setIceTrap", + STAT_CALCULATOR: "block" + } + }, { + POSITION: [13.95, 5.15, 1, 0, 0, 0, 0], + PROPERTIES: { + COLOR: "#28B1DE" + } + } + ] +} +Class.icetriTrapper = { + PARENT: "genericTank", + LABEL: "Winter", + DANGER: 7, + STAT_NAMES: statnames.trap, + GUNS: weaponArray([ + { + POSITION: [15, 7, 1, 0, 0, 0, 0], + }, + { + POSITION: [3, 7, 1.7, 15, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, g.flankGuard]), + TYPE: "icetrap", + STAT_CALCULATOR: "trap" + } + }, { + POSITION: [13.95, 5.15, 1, 0, 0, 0, 0], + PROPERTIES: { + COLOR: "#28B1DE" + } + } + ], 3) +} +Class.icetrapGuard = makeGuard({ + PARENT: "genericTank", + LABEL: "Trap", + STAT_NAMES: statnames.mixed, + GUNS: [ + { + POSITION: [20, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.flankGuard]), + TYPE: "bullet" + } + }, { + POSITION: [13.95, 5.15, 1, 0, 0, 0, 0], + PROPERTIES: { + COLOR: "#28B1DE" + } + } + ] +}, "Ice Guard", "icetrap") + +Class.icewark = { + PARENT: "genericTank", + LABEL: "Ice Wark", + DANGER: 7, + STAT_NAMES: statnames.trap, + GUNS: [{ + POSITION: [13, 8, 1, 0, -5.5, -8, 0] + }, { + POSITION: [4, 8, 1.7, 13, -5.5, -8, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, g.twin, g.halfrange]), + TYPE: "icetrap", + STAT_CALCULATOR: "trap", + } + }, { + POSITION: [13, 8, 1, 0, 5.5, 8, 0.5] + }, { + POSITION: [4, 8, 1.7, 13, 5.5, 8, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, g.twin, g.halfrange]), + TYPE: "icetrap", + STAT_CALCULATOR: "trap", + } + }, { + POSITION: [13.95, 5.15, 1, 0, 0, 0, 0], + PROPERTIES: { + COLOR: "#28B1DE" + } + }] +} + +Class.icecontagion = { + PARENT: "genericTank", + LABEL: 'Hypothermia', + DANGER: 7, + STAT_NAMES: statnames.mixed, + GUNS: [{ + POSITION: [19, 5.5, 1, 0, 0, 0, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.contagi]), + TYPE: "bullet" + } + }, { + POSITION: [13, 8, 1, 0, 0, 0, 0] + }, { + POSITION: [4, 8, 1.7, 13, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap]), + TYPE: "icetrap", + STAT_CALCULATOR: "trap", + } + }, { + POSITION: [13.95, 5.15, 1, 0, 0, 0, 0], + PROPERTIES: { + COLOR: "#28B1DE" + } + }] +}; +Class.miniVulc = { + PARENT: "genericTank", + LABEL: 'Submachine', + DANGER: 6, + GUNS: [{ + POSITION: [30, 1.5, 1, 0, 2.5, 0, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.vulc]), + TYPE: "bullet" + } + }, { + POSITION: [30, 1.5, 1, 0, -2.5, 0, 0.75], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.vulc]), + TYPE: "bullet" + } + }, { + POSITION: [30, 1.5, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.vulc, g.doublereload]), + TYPE: "bullet" + } + }, { + POSITION: [12, 10, 1, 0, 0, 0, 0] + }, { + POSITION: [5, 10, 1, 20, 0, 0, 0] + }] +}; +Class.miniVulcTrap = makeGuard("miniVulc", "Holster") +Class.vulcan = { + PARENT: "genericTank", + LABEL: 'Vulcan', + DANGER: 7, + GUNS: [{ + POSITION: [30, 1.5, 1, 0, -4.5, 0, 1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.vulc, { reload: 1.25, damage: 0.76 }]), + TYPE: "bullet" + } + }, { + POSITION: [30, 1.5, 1, 0, -4.5, 0, 0.9], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.vulc, { reload: 1.25, damage: 0.76 }]), + TYPE: "bullet" + } + }, { + POSITION: [30, 1.5, 1, 0, 4.5, 0, 0.4], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.vulc, { reload: 1.25, damage: 0.76 }]), + TYPE: "bullet" + } + }, { + POSITION: [30, 1.5, 1, 0, 4.5, 0, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.vulc, { reload: 1.25, damage: 0.76 }]), + TYPE: "bullet" + } + }, { + POSITION: [30, 1.5, 1, 0, -2.5, 0, 0.1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.vulc, { reload: 1.25, damage: 0.76 }]), + TYPE: "bullet" + } + }, { + POSITION: [30, 1.5, 1, 0, 2.5, 0, 0.3], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.vulc, { reload: 1.25, damage: 0.76 }]), + TYPE: "bullet" + } + }, { + POSITION: [30, 1.5, 1, 0, 2.5, 0, 0.6], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.vulc, { reload: 1.25, damage: 0.76 }]), + TYPE: "bullet" + } + }, { + POSITION: [30, 1.5, 1, 0, -2.5, 0, 0.8], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.vulc, { reload: 1.25, damage: 0.76 }]), + TYPE: "bullet" + } + }, { + POSITION: [30, 1.5, 1, 0, 0, 0, 0.2], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.vulc, { reload: 1.25, damage: 0.76 }]), + TYPE: "bullet" + } + }, { + POSITION: [30, 1.5, 1, 0, 0, 0, 0.7], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.vulc, { reload: 1.25, damage: 0.76 }]), + TYPE: "bullet" + } + }, { + POSITION: [12, 16, 1, 0, 0, 0, 0] + }, { + POSITION: [5, 16, 1, 20, 0, 0, 0] + }] +}; + +Class.littleArtillery = { + PARENT: "genericTank", + LABEL: "Minishot", + DANGER: 5, + GUNS: [{ + POSITION: [17, 3, 1, 0, -4.5, -7, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [17, 3, 1, 0, 4.5, 7, .75], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [19, 9, 1.05, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic]), + TYPE: "bullet", + } + }] +}; +// minishot upgrades +Class.littleMortar = { + PARENT: "genericTank", + LABEL: "Biggie-Shot", + DANGER: 6, + GUNS: [{ + POSITION: [15, 2.5, 1, 0, -6.5, -8, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [15, 2.5, 1, 0, 6.5, 8, .5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [17, 3, 1, 0, -4.5, -7, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [17, 3, 1, 0, 4.5, 7, .75], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [19, 9, 1.05, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic]), + TYPE: "bullet", + } + }] +}; +Class.littleTwinArtillery = { + PARENT: "genericTank", + LABEL: "Hewn/2", + DANGER: 6, + GUNS: [{ + POSITION: [17, 3, 1, 0, -8, -7, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [17, 3, 1, 0, 8, 7, .75], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [20, 8, 1.05, 0, 5, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin]), + TYPE: "bullet", + } + }, { + POSITION: [20, 8, 1.05, 0, -5, 0, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin]), + TYPE: "bullet", + } + }] +}; +Class.littleSnipeArtillery = { + PARENT: "genericTank", + LABEL: "Shredder", + DANGER: 6, + GUNS: [{ + POSITION: [19, 3, 1, 0, -4.5, -7, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [19, 3, 1, 0, 4.5, 7, .75], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [22, 9, 1.05, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper/*, {damage: 0.75, pen: 0.7, health: 0.9, speed: 0.85, maxSpeed: 0.9}*/]), + TYPE: "bullet", + } + }] +}; +Class.littleMachArtillery = { + PARENT: "genericTank", + LABEL: "Machshot", + DANGER: 6, + GUNS: [{ + POSITION: [17, 3, 1, 0, -5, -7, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [17, 3, 1, 0, 5, 7, .75], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [19, 9, 1.35, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun]), + TYPE: "bullet", + } + }] +}; +Class.littleFlankArtillery = { + PARENT: "genericTank", + LABEL: "Trishot", + DANGER: 6, + GUNS: weaponArray([{ + POSITION: [17, 3, 1, 0, -4.5, -7, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [17, 3, 1, 0, 4.5, 7, .75], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [19, 9, 1.05, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic]), + TYPE: "bullet", + } + }], 3) +}; +Class.littleDirectArtillery = { + PARENT: "genericTank", + LABEL: "CEO", + DANGER: 6, + STAT_NAMES: statnames.drone, + GUNS: [{ + POSITION: [12, 3, 1, 0, -5, -8, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [12, 3, 1, 0, 5, 8, .75], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: { + LENGTH: 6, + WIDTH: 11, + ASPECT: 1.3, + X: 7 + }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone]), + TYPE: "drone", + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "drone", + MAX_CHILDREN: 4, + WAIT_TO_CYCLE: true + } + }] +}; +Class.littleTrapArtillery = { + PARENT: "genericTank", + LABEL: "Executionist", + DANGER: 6, + STAT_NAMES: statnames.trap, + GUNS: [{ + POSITION: [17, 3, 1, 0, -4.5, -7, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [17, 3, 1, 0, 4.5, 7, .75], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: { + LENGTH: 15, + WIDTH: 7 + } + }, { + POSITION: { + LENGTH: 3, + WIDTH: 7, + ASPECT: 1.7, + X: 15 + }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap]), + TYPE: "trap", + STAT_CALCULATOR: "trap" + } + }] +}; +Class.littleSineArtillery = { + PARENT: "genericTank", + LABEL: "CosLock", + DANGER: 6, + STAT_NAMES: statnames.desmos, + GUNS: [{ + POSITION: [17, 3, 1, 0, -4.5, -7, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [17, 3, 1, 0, 4.5, 7, .75], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [20, 8, -4/3, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.desmos]), + TYPE: ["bullet", {CONTROLLERS: ['snake']}] + } + }, { + POSITION: [3.75, 10, 2.125, 1.5, -6.25, 90, 0] + }, { + POSITION: [3.75, 10, 2.125, 1.5, 6.25, -90, 0] + }] +}; +Class.littleSubArtillery = { + PARENT: "genericTank", + LABEL: "Sub-Shot", + DANGER: 6, + GUNS: [{ + POSITION: [17, 3, 1, 0, -4.5, -7, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [17, 3, 1, 0, 4.5, 7, .75], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [23, 5, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.littleHunter, g.hunter, g.hunterSecondary]), + TYPE: "bullet" + } + }, { + POSITION: [20, 8, 1, 0, 0, 0, 0.2], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.littleHunter, g.hunter]), + TYPE: "bullet" + } + }] +}; +Class.littleIncepArtillery = { + PARENT: "genericTank", + LABEL: "Catalyst", + DANGER: 6, + GUNS: [{ + POSITION: [17, 3, 1, 0, -4.5, -7, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [17, 3, 1, 0, 4.5, 7, .75], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [18, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic]), + TYPE: "autobullet", + } + } + ], + TURRETS: [{ + POSITION: [5.5, 18, 0, 0, 0, 0], + TYPE: ["autoTurret", { INDEPENDENT: true, MIRROR_MASTER_ANGLE: true }] + }] +}; +Class.littlePropArtillery = { + PARENT: "genericTank", + LABEL: "Speedrun", + DANGER: 6, + GUNS: [{ + POSITION: [17, 3, 1, 0, -4.5, -7, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [17, 3, 1, 0, 4.5, 7, .75], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [19, 9, 1.05, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic]), + TYPE: "bullet", + } + }, { + POSITION: [16, 8, 1, 0, 0, 180, 0.1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), + TYPE: "bullet", + LABEL: "thruster", + }, + }] +}; +Class.littleLanceArtillery = { + PARENT: "genericTank", + LABEL: "Knife", + STAT_NAMES: statnames.lancer, + DANGER: 6, + GUNS: [{ + POSITION: [17, 3, 1, 0, -4.5, -7, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [17, 3, 1, 0, 4.5, 7, .75], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [20, 15, 0.001, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.lance, { recoil: 0 }]), + TYPE: ["bullet", { ALPHA: 0 }], + AUTOFIRE: true, + STAT_CALCULATOR: "lancer" + } + }, { + POSITION: [25, 15, 0.001, 0, 0, 0, 0] + }] +}; +// biggie shot upgrades +Class.littleSheller = { + PARENT: "genericTank", + LABEL: "Biggier-Shot", + DANGER: 7, + GUNS: [{ + POSITION: [13, 2, 1, 0, -8, -9, 5/6], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [13, 2, 1, 0, 8, 9, 4/6], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [15, 2.5, 1, 0, -6.5, -8, 3/6], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [15, 2.5, 1, 0, 6.5, 8, 2/6], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [17, 3, 1, 0, -4.5, -7, 1/6], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [17, 3, 1, 0, 4.5, 7, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [19, 9, 1.05, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic]), + TYPE: "bullet", + } + }] +} +Class.littleTwinMortar = { + PARENT: "genericTank", + LABEL: "Skewn/2", + DANGER: 7, + GUNS: [{ + POSITION: [15, 2.5, 1, 0, -8.5, -11, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [15, 2.5, 1, 0, 8.5, 11, .5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [17, 3, 1, 0, -8, -7, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [17, 3, 1, 0, 8, 7, .75], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [20, 8, 1.05, 0, 5, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin]), + TYPE: "bullet", + } + }, { + POSITION: [20, 8, 1.05, 0, -5, 0, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin]), + TYPE: "bullet", + } + }] +}; +Class.littleSnipeMortar = { + PARENT: "genericTank", + LABEL: "Chainsaw", + DANGER: 7, + GUNS: [{ + POSITION: [17, 2.5, 1, 0, -6.5, -8, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [17, 2.5, 1, 0, 6.5, 8, .5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [19, 3, 1, 0, -4.5, -7, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [19, 3, 1, 0, 4.5, 7, .75], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [22, 9, 1.05, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.sniper/*, {damage: 0.75, pen: 0.7, health: 0.9, speed: 0.85, maxSpeed: 0.9}*/]), + TYPE: "bullet", + } + }] +}; +Class.littleMachMortar = { + PARENT: "genericTank", + LABEL: "Machtillery", + DANGER: 7, + GUNS: [{ + POSITION: [15, 2.5, 1, 0, -6.5, -8, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [15, 2.5, 1, 0, 6.5, 8, .5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [17, 3, 1, 0, -5, -7, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [17, 3, 1, 0, 5, 7, .75], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [19, 9, 1.35, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, {shudder: 1.3, spray: 0.95}]), + TYPE: "bullet", + } + }] +}; +Class.littleFlankMortar = { + PARENT: "genericTank", + LABEL: "Tri-Tillery", + DANGER: 7, + GUNS: weaponArray([{ + POSITION: [15, 2.5, 1, 0, -6.5, -8, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [15, 2.5, 1, 0, 6.5, 8, .5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [17, 3, 1, 0, -4.5, -7, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [17, 3, 1, 0, 4.5, 7, .75], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [19, 9, 1.05, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard]), + TYPE: "bullet", + } + }], 3) +}; +Class.littleDirectMortar = { + PARENT: "genericTank", + LABEL: "MoneyBags", + DANGER: 7, + STAT_NAMES: statnames.drone, + GUNS: [{ + POSITION: [10.5, 2.5, 1, 0, -6.5, -9, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [10.5, 2.5, 1, 0, 6.5, 9, .5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [12, 3, 1, 0, -5, -8, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [12, 3, 1, 0, 5, 8, .75], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: { + LENGTH: 6, + WIDTH: 11, + ASPECT: 1.3, + X: 7 + }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.drone]), + TYPE: "drone", + AUTOFIRE: true, + SYNCS_SKILLS: true, + STAT_CALCULATOR: "drone", + MAX_CHILDREN: 4, + WAIT_TO_CYCLE: true + } + }] +}; +Class.littleTrapMortar = { + PARENT: "genericTank", + LABEL: "Vile", + DANGER: 7, + STAT_NAMES: statnames.trap, + GUNS: [{ + POSITION: [15, 2.5, 1, 0, -6.5, -8, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [15, 2.5, 1, 0, 6.5, 8, .5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [17, 3, 1, 0, -4.5, -7, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [17, 3, 1, 0, 4.5, 7, .75], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: { + LENGTH: 15, + WIDTH: 7 + } + }, { + POSITION: { + LENGTH: 3, + WIDTH: 7, + ASPECT: 1.7, + X: 15 + }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap]), + TYPE: "trap", + STAT_CALCULATOR: "trap" + } + }] +}; +Class.littleDesmosMortar = { + PARENT: "genericTank", + LABEL: "SineLock", + DANGER: 7, + STAT_NAMES: statnames.desmos, + GUNS: [{ + POSITION: [15, 2.5, 1, 0, -6.5, -8, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [15, 2.5, 1, 0, 6.5, 8, .5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [17, 3, 1, 0, -4.5, -7, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [17, 3, 1, 0, 4.5, 7, .75], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [20, 8, -4/3, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.desmos]), + TYPE: ["bullet", {CONTROLLERS: ['snake']}] + } + }, { + POSITION: [3.75, 10, 2.125, 1.5, -6.25, 90, 0] + }, { + POSITION: [3.75, 10, 2.125, 1.5, 6.25, -90, 0] + }] +}; +Class.littleSubMortar = { + PARENT: "genericTank", + LABEL: "Mega Sub-Shot", + DANGER: 7, + GUNS: [{ + POSITION: [15, 2.5, 1, 0, -6.5, -8, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [15, 2.5, 1, 0, 6.5, 8, .5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [17, 3, 1, 0, -4.5, -7, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [17, 3, 1, 0, 4.5, 7, .75], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [23, 5, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.littleHunter, g.hunter, g.hunterSecondary]), + TYPE: "bullet" + } + }, { + POSITION: [20, 8, 1, 0, 0, 0, 0.2], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.littleHunter, g.hunter]), + TYPE: "bullet" + } + }] +}; +Class.littleIncepMortar = { + PARENT: "genericTank", + LABEL: "Mechanism", + DANGER: 7, + GUNS: [{ + POSITION: [15, 2.5, 1, 0, -6.5, -8, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [15, 2.5, 1, 0, 6.5, 8, .5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [17, 3, 1, 0, -4.5, -7, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [17, 3, 1, 0, 4.5, 7, .75], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [18, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic]), + TYPE: "autobullet", + } + }] +}; +Class.littlePropMortar = { + PARENT: "genericTank", + LABEL: "Nascar", + DANGER: 7, + GUNS: [{ + POSITION: [15, 2.5, 1, 0, -6.5, -8, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [15, 2.5, 1, 0, 6.5, 8, .5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [17, 3, 1, 0, -4.5, -7, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [17, 3, 1, 0, 4.5, 7, .75], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [19, 9, 1.05, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic]), + TYPE: "bullet", + } + }, { + POSITION: [16, 8, 1, 0, 0, 180, 0.1], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.triAngle, g.thruster]), + TYPE: "bullet", + LABEL: "thruster", + }, + }] +}; +Class.littleLanceMortar = { + PARENT: "genericTank", + LABEL: "Exacto", + DANGER: 7, + STAT_NAMES: statnames.lancer, + GUNS: [{ + POSITION: [15, 2.5, 1, 0, -6.5, -8, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [15, 2.5, 1, 0, 6.5, 8, .5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [17, 3, 1, 0, -4.5, -7, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [17, 3, 1, 0, 4.5, 7, .75], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [20, 15, 0.001, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.lance, { recoil: 0 }]), + TYPE: ["bullet", { ALPHA: 0 }], + AUTOFIRE: true, + STAT_CALCULATOR: "lancer" + } + }, { + POSITION: [25, 15, 0.001, 0, 0, 0, 0] + }] +}; +// hewn/2 upgrades +/*Class.littleTwinArtillery = { + PARENT: "genericTank", + LABEL: "Hewn/2", + DANGER: 6, + GUNS: [{ + POSITION: [17, 3, 1, 0, -8, -7, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: [17, 3, 1, 0, 8, 7, .75], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.gunner, g.artillery]), + TYPE: "bullet" + } + }, { + POSITION: { + LENGTH: 19, + WIDTH: 8, + Y: -2, + ANGLE: -17.5, + DELAY: 0.5 + }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.tripleShot]), + TYPE: "bullet" + } + }, + { + POSITION: { + LENGTH: 19, + WIDTH: 8, + Y: 2, + ANGLE: 17.5, + DELAY: 0.5 + }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.tripleShot]), + TYPE: "bullet" + } + }, + { + POSITION: { + LENGTH: 22, + WIDTH: 8 + }, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.tripleShot]), + TYPE: "bullet" + } + } + ] +};*/ +// Auto tanks +Class.autoBasic = makeAuto("basic", "Auto-Basic"); +Class.autoTwin = makeAuto("twin", "Auto-Twin"); +Class.autoMach = makeAuto("machineGun", "Auto-Machine"); +Class.autoSniper = makeAuto("sniper", "Auto-Sniper"); +Class.autoFlank = makeAuto("flankGuard", "Auto-Flank"); +Class.autoDirector = makeAuto("director", "Chairman"); +Class.autoPound = makeAuto("pounder", "Scratcher"); +Class.autoTrap = makeAuto("trapper", "Auto-Trapper"); +Class.autoDesmos = makeAuto("desmos", "Charter"); +Class.autolittleHunter = makeAuto("littleHunter", "Duelist") +Class.autoinception = makeAuto("inception", "Deployer"); +Class.autoauto2 = makeAuto("auto2", "Auto²-2"); +Class.autoPropel = makeAuto("propel", "Grazer"); +Class.autolittleArtillery = makeAuto("littleArtillery", "Quesadilla" /* delta wanted this name lmaoo */) +Class.autoCloner = makeAuto({ + PARENT: "genericTank", + GUNS: [ + { + /*** LENGTH WIDTH ASPECT X Y ANGLE DELAY */ + POSITION: [18, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.cloner]), + TYPE: "bullet" + } + }, + { + POSITION: [0, 20, 1, 0, 0, 180, 3], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.slow]), + TYPE: "autoclonerprobe", + MAX_CHILDREN: 1, + WAIT_TO_CYCLE: true + } + } + ], + TURRETS: [ + { + /* SIZE X Y ANGLE ARC */ + POSITION: [24, 0, 0, 0, 360, 0], + TYPE: "mindindicator" + } + ] +}, "Auto-Cloner"); +Class.autoDouble = makeAuto("doubleTwin", "Mechanism") +Class.autoAssassin = makeAuto("assassin") +Class.autoGunner = makeAuto("gunner") +Class.autoTriAngle = makeAuto("triAngle") +Class.autoOverseer = makeAuto("overseer") +Class.autoRevolutionist = makeAuto("revolutionist", "Audioboard"); +Class.autoCruiser = makeAuto("cruiser") +Class.autoSpawner = makeAuto("spawner") +Class.autoBuilder = makeAuto("builder") +Class.autoBinary = makeAuto("binary", "Computist") +Class.autoinceptionist = makeAuto("autoinceptionistbody", "Poster", {type: 'ceptionistturret'}); +Class.autoGundirector = makeAuto("gundirector", "Virus") +Class.oganesson = makeAuto("noble", "Oganesson") +Class.autoBigSubduer = makeAuto("bigSubduer", "Membrane") +Class.autoFlankdue = makeAuto("flankdue", "Flank-Duelist") +Class.autoBateau = makeAuto("bateau", "Riverboat") +Class.autoTripleShot = makeAuto("tripleShot", "Oppressor"); +Class.autoHunter = makeAuto("hunter", "Twogate"); +Class.autoRifle = makeAuto("rifle", "Sidepoint"); +Class.autoTwinsniper = makeAuto("twinsniper", "Watchlist"); +Class.autoAcid = makeAuto("acid", "Cyanide"); +Class.autoChill = makeAuto("chiller", "Coldpoint"); +Class.autoMini = makeAuto("minigun", "Streamer"); +Class.autoSprayer = makeAuto("sprayer", "Splasher"); +Class.autoHexaTank = makeAuto("hexaTank", "Moat"); +Class.autoAuto3 = makeAuto("auto3", "Auto²-3"); +Class.autoUnderseer = makeAuto("underseer", "Plauge"); +Class.autoDestroy = makeAuto("destroyer", "Executer"); +Class.autoArtillery = makeAuto("artillery", "Bombarder"); +Class.autoLaunch = makeAuto("launcher", "Harbinger"); +Class.autoTrapGuard = makeAuto("trapGuard", "Ducker"); +Class.autoSidewinder = makeAuto("sidewinder", "Auto-Sidewinder"); +Class.autoHelix = makeAuto("helix", "DNA"); +Class.autoUndertow = makeAuto("undertow", "Current"); +Class.autoRepeater = makeAuto("repeater", "Patterner"); +Class.automachinception = makeAuto("machinception", "Mechanist"); +Class.autotailgator = makeAuto("tailgator", "Tailplayer"); +Class.autoflankinception = makeAuto("flankinception", "Flank-Deployer"); +Class.autoBackShield = makeAuto("backShield", "Coverer"); +Class.autoSwivel2 = makeAuto("swivel2", "Scowerer"); +Class.autoJouster = makeAuto("jouster", "Horse"); +Class.autochasseur = makeAuto('chasseur', "Auto-Chasseur"); +Class.autobayonet = makeAuto('bayonet', "Auto-Bayonet"); +Class.autoGatlinggun = makeAuto("gatlinggun", "A-Gatling Gun"); +Class.autowark = makeAuto("wark", "WaWark"); +Class.autoIcetrapper = makeAuto("icetrapper", "Auto Ice Trapper"); +Class.autolittleMortar = makeAuto("littleMortar"); +Class.autolittleTwinArtillery = makeAuto("littleTwinArtillery"); +Class.autolittleSnipeArtillery = makeAuto("littleSnipeArtillery"); +Class.autolittleMachArtillery = makeAuto("littleMachArtillery"); +Class.autolittleFlankArtillery = makeAuto("littleFlankArtillery"); +Class.autolittleDirectArtillery = makeAuto("littleDirectArtillery"); +Class.autolittleTrapArtillery = makeAuto("littleTrapArtillery"); +Class.autolittleSineArtillery = makeAuto("littleSineArtillery"); +Class.autolittleSubArtillery = makeAuto("littleSubArtillery"); +Class.autolittleIncepArtillery = makeAuto("littleIncepArtillery"); +Class.autolittlePropArtillery = makeAuto("littlePropArtillery"); +Class.autolittleLanceArtillery = makeAuto("littleLanceArtillery"); +Class.autominiVulc = makeAuto("miniVulc", "M-61"); +Class.autoSmasher = makeAuto({ + PARENT: "genericSmasher", + DANGER: 6, + TURRETS: [ + { + POSITION: [21.5, 0, 0, 0, 360, 0], + TYPE: "smasherBody" + } + ], + SKILL_CAP: [smshskl, smshskl, smshskl, smshskl, smshskl, smshskl, smshskl, smshskl, smshskl, smshskl] +}, "Auto-Smasher", {type: "autoSmasherTurret", size: 11}) + +//Autodrive Stuff +Class.autoMotor = makeAuto("directdrive", "Auto-Motor", { type: "autoTankGunDrive" }); + +//Hybrid Tanks +Class.bascrid = makeOver('basic', "Basebrid", {count: 1, independent: true, cycle: false}) +Class.twinbrid = makeOver('twin', "Twin-Hybrid", {count: 1, independent: true, cycle: false}) +Class.machbrid = makeOver('machineGun', "Machine-Hybrid", {count: 1, independent: true, cycle: false}) +Class.snipebrid = makeOver('sniper', "Snipebrid", {count: 1, independent: true, cycle: false}) +Class.flankbrid = makeOver('flankGuard', "Flankbrid", {count: 1, independent: true, cycle: false}) +Class.poundbrid = makeOver('pounder', "Poundbrid", {count: 1, independent: true, cycle: false}) +Class.trapbrid = makeOver('trapper', "Trapbrid", {count: 1, independent: true, cycle: false}) +Class.desmosbrid = makeOver('desmos', "Desmosbrid", {count: 1, independent: true, cycle: false}) +Class.littleHunterbrid = makeOver('littleHunter', "Subbrid", {count: 1, independent: true, cycle: false}) +Class.inceptionbrid = makeOver('inception', "Inceptionbrid", {count: 1, independent: true, cycle: false}) +Class.auto2brid = makeOver('auto2', "Auto-2brid", {count: 1, independent: true, cycle: false}) +Class.propelbrid = makeOver('propel', "Racer", {count: 1, independent: true, cycle: false}) +Class.doubletwinbrid = makeOver('doubleTwin', "Double Twinbrid", {count: 1, independent: true, cycle: false}) +Class.hexatankbrid = makeOver('hexaTank', "Hexatankbrid", {count: 1, independent: true, cycle: false}) +Class.auto3brid = makeOver('auto3', "Auto-3brid", {count: 1, independent: true, cycle: false}) +Class.binarybrid = makeOver('binary', "ZerOne", {count: 1, independent: true, cycle: false}) +Class.flankduebrid = makeOver('flankdue', "Partier", {count: 1, independent: true, cycle: false, maxDrones: 1}) +Class.bigsubduerbrid = makeOver('bigSubduer', "Enzyme", {count: 1, independent: true, cycle: false}) +Class.clonebrid = makeOver({ + PARENT: "genericTank", + GUNS: [ + { + POSITION: [18, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.cloner]), + TYPE: "bullet" + } + }, + { + POSITION: [0, 20, 1, 0, 0, 180, 3], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.slow]), + TYPE: "hybridclonerprobe", + MAX_CHILDREN: 1, + WAIT_TO_CYCLE: true + } + } + ], + TURRETS: [ + { + POSITION: [24, 0, 0, 0, 360, 0], + TYPE: "mindindicator" + } + ] +}, "Cloner-Hybrid", {count: 1, independent: true, cycle: false}) +Class.bentHybrid = makeOver('tripleShot', "Bent Hybrid", {count: 1, independent: true, cycle: false}) +Class.revobrid = makeOver('revolutionist', "Revobrid", {count: 1, independent: true, cycle: false}); +Class.contagionbrid = makeOver('contagion', "Contagibrid", {count: 1, independent: true, cycle: false}) +Class.poacher = makeOver('hunter', "Poacher", {count: 1, independent: true, cycle: false}) +Class.armsman = makeOver('rifle', "Armsman", {count: 1, independent: true, cycle: false}) +Class.cropDuster = makeOver('minigun', "Crop Duster", {count: 1, independent: true, cycle: false}) +Class.hybrid = makeOver('destroyer', "Hybrid", {count: 1, independent: true, cycle: false}) +Class.assbrid = makeOver('assassin', "Sharpshooter", {count: 1, independent: true, cycle: false}) +Class.twipebrid = makeOver('twinsniper', "Twiperbrid", {count: 1, independent: true, cycle: false}) +Class.acidbrid = makeOver('acid', "Acidibrid", {count: 1, independent: true, cycle: false}) +Class.chillbrid = makeOver('chiller', "Chillbrid", {count: 1, independent: true, cycle: false}) +Class.artilbrid = makeOver('artillery', "Artillerbrid", {count: 1, independent: true, cycle: false}) +Class.spraybrid = makeOver('sprayer', "Hoser", {count: 1, independent: true, cycle: false}) +Class.trapguardbrid = makeOver('trapGuard', "TG-Hybrid", {count: 1, independent: true, cycle: false}) +Class.builderbrid = makeOver('builder', "Builderbrid", {count: 1, independent: true, cycle: false}) +Class.launchbrid = makeOver('launcher', "Launcherbrid", {count: 1, independent: true, cycle: false}) +Class.tritrapperbrid = makeOver('triTrapper', "T3T-Hybrid", {count: 1, independent: true, cycle: false}) +Class.trianglebrid = makeOver('triAngle', "Trianglebrid", {count: 1, independent: true, cycle: false}) +Class.helixbrid = makeOver('helix', "Gyre", {count: 1, independent: true, cycle: false}) +Class.sidewinderbrid = makeOver('sidewinder', "Sidewinderbrid", {count: 1, independent: true, cycle: false}) +Class.undertowbrid = makeOver('undertow', "Pullist", {count: 1, independent: true, cycle: false}) +Class.repeaterbrid = makeOver('repeater', "Comparator", {count: 1, independent: true, cycle: false}) +Class.inceptionistbrid = makeOver('inceptionist', "Inceptionistbrid", {count: 1, independent: true, cycle: false}) +Class.machinceptionbrid = makeOver('machinception', "MachinceptibriDd", {count: 1, independent: true, cycle: false}) +Class.tailgatorbrid = makeOver('tailgator', "Tailgatorbrid", {count: 1, independent: true, cycle: false}) +Class.flankinceptionbrid = makeOver('flankinception', "Flankinceptibrid", {count: 1, independent: true, cycle: false}) +Class.bateaubrid = makeOver('bateau', "Kayak", {count: 1, independent: true, cycle: false}) +Class.swivel2brid = makeOver('swivel2', "Swivel2brid", {count: 1, independent: true, cycle: false}) +Class.jousterbrid = makeOver('jouster', "Jousterbrid", {count: 1, independent: true, cycle: false}) +Class.bayonetbrid = makeOver('bayonet', "Bayonet-Hybrid", {count: 1, independent: true, cycle: false}); +Class.chasseubrid = makeOver('chasseur', "Chasseubrid", {count: 1, independent: true, cycle: false}); +Class.backshieldbrid = makeOver('backShield', "Fireblanket", {count: 1, independent: true, cycle: false}) +Class.gatlinggunbrid = makeOver('gatlinggun', "H-Gatling Gun", {count: 1, independent: true, cycle: false}) +Class.warkbrid = makeOver('wark', "Waarrk", {count: 1, independent: true, cycle: false}) +Class.icetrapbrid = makeOver('icetrapper', "Ice Trapper Brid", {count: 1, independent: true, cycle: false}) +Class.littleArtillerybrid = makeOver('littleArtillery', "Minishotbrid", {count: 1, independent: true, cycle: false}) +Class.littleMortarbrid = makeOver('littleMortar', "Biggieshotbrid", {count: 1, independent: true, cycle: false}) +Class.littleTwinArtillerybrid = makeOver('littleTwinArtillery', "Hewn/2brid", {count: 1, independent: true, cycle: false}) +Class.littleSnipeArtillerybrid = makeOver('littleSnipeArtillery', "Shredderbrid", {count: 1, independent: true, cycle: false}) +Class.littleMachArtillerybrid = makeOver('littleMachArtillery', "Machshotbrid", {count: 1, independent: true, cycle: false}) +Class.littleFlankArtillerybrid = makeOver('littleFlankArtillery', "Trishotbrid", {count: 1, independent: true, cycle: false}) +Class.littleTrapArtillerybrid = makeOver('littleTrapArtillery', "Executionistbrid", {count: 1, independent: true, cycle: false}) +Class.littleSineArtillerybrid = makeOver('littleSineArtillery', "Coslockbrid", {count: 1, independent: true, cycle: false}) +Class.littleSubArtillerybrid = makeOver('littleSubArtillery', "Sub-shotbrid", {count: 1, independent: true, cycle: false}) +Class.littleIncepArtillerybrid = makeOver('littleIncepArtillery', "Catalystbrid", {count: 1, independent: true, cycle: false}) +Class.littlePropArtillerybrid = makeOver('littlePropArtillery', "Speedrunbrid", {count: 1, independent: true, cycle: false}) +Class.littleLanceArtillerybrid = makeOver('littleLanceArtillery', "Knifebrid", {count: 1, independent: true, cycle: false}) +Class.miniVulcbrid = makeOver('miniVulc', "Crowd Control", {count: 1, independent: true, cycle: false}) + +//auto hybrid tanks +Class.autotwinbrid = makeOver('autoTwin', "Auto-Twinbrid", {count: 1, independent: true, cycle: false}) +Class.autosnipebrid = makeOver('autoSniper', "Auto-Snipebrid", {count: 1, independent: true, cycle: false}) +Class.automachbrid = makeOver('autoMach', "Auto-Machbrid", {count: 1, independent: true, cycle: false}) +Class.autoflankbrid = makeOver('autoFlank', "Auto-Flankbrid", {count: 1, independent: true, cycle: false}) +Class.autopoundbrid = makeOver('autoPound', "Scratcherbrid", {count: 1, independent: true, cycle: false}) +Class.autotrapbrid = makeOver('autoTrap', "Auto-Trapbrid", {count: 1, independent: true, cycle: false}) +Class.autodesmosbrid = makeOver('autoDesmos', "Chartebrid", {count: 1, independent: true, cycle: false}) +Class.autobascrid = makeOver('autoBasic', "Auto-Basebrid", {count: 1, independent: true, cycle: false}) +Class.autoinceptionbrid = makeOver('autoinception', "Deployerbrid", {count: 1, independent: true, cycle: false}) +Class.autolittleHunterbrid = makeOver('autolittleHunter', "Auto-Subbrid", {count: 1, independent: true, cycle: false}) +Class.autopropelbrid = makeOver('autoPropel', "Grazerbrid", {count: 1, independent: true, cycle: false}) +Class.autolittleArtillerybrid = makeOver('autolittleArtillery', "Quessadilabrid", {count: 1, independent: true, cycle: false}) +Class.autoauto2brid = makeOver('autoauto2', "Auto²-2brid", {count: 1, independent: true, cycle: false}) + +//hybrid drive tanks +Class.car = makeOver('basic', "Car", {count: 1, independent: true, cycle: false, type: "turretedDrone"}) +Class.mercedes = makeOver('twin', "Mercedes", {count: 1, independent: true, cycle: false, type: "turretedDrone"}) +Class.tesla = makeOver('sniper', "Tesla", {count: 1, independent: true, cycle: false, type: "turretedDrone"}) +Class.toyota = makeOver('machineGun', "Toyota", {count: 1, independent: true, cycle: false, type: "turretedDrone"}) +Class.ford = makeOver('flankGuard', "Ford", {count: 1, independent: true, cycle: false, type: "turretedDrone"}) +Class.honda = makeOver('pounder', "Honda", {count: 1, independent: true, cycle: false, type: "turretedDrone"}) +Class.gmc = makeOver('trapper', "GMC", {count: 1, independent: true, cycle: false, type: "turretedDrone"}) +Class.porsche = makeOver('autoBasic', "Porsche", {count: 1, independent: true, cycle: false, type: "turretedDrone"}) +Class.mazda = makeOver('desmos', "Mazda", {count: 1, independent: true, cycle: false, type: "turretedDrone"}) +Class.volkswagen = makeOver('littleHunter', "Volkswagen", {count: 1, independent: true, cycle: false, type: "turretedDrone"}) +Class.audi = makeOver('inception', "Audi", {count: 1, independent: true, cycle: false, type: "turretedDrone"}) +Class.mustang = makeOver('propel', "Mustang", {count: 1, independent: true, cycle: false, type: "turretedDrone"}) +Class.ferrari = makeOver('auto2', "Ferrari", {count: 1, independent: true, cycle: false, type: "turretedDrone"}) +Class.ram = makeOver('lancer', "Ram", {count: 1, independent: true, cycle: false, type: "turretedDrone"}) +Class.chrysler = makeOver('littleArtillery', "Chrysler", {count: 1, independent: true, cycle: false, type: "turretedDrone"}) + +//Ceptions +Class.basicCeption = makeCeption('basic', "Basiception"); +Class.twinCeption = makeCeption('twin', "Twinception"); +Class.snipeCeption = makeCeption('sniper', "Snipeception"); +Class.machCeption = makeCeption('machineGun', "Machception"); +Class.flankCeption = makeCeption('flankGuard', "Flankception"); +Class.directCeption = makeCeption('director', "Droneception"); +Class.poundCeption = makeCeption('pounder', "Poundception"); +Class.trapCeption = makeCeption('trapper', "Trapception"); +Class.desmosCeption = makeCeption('desmos', "Desmosception"); +Class.bascridCeption = makeCeption('bascrid', "Baseception"); +Class.littleHunterCeption = makeCeption('littleHunter', "Subception"); +Class.inceptCeption = makeCeption('inception', "Incepticon"); +Class.propelCeption = makeCeption('propel', "Propeleception"); +Class.lancerception = makeAuto('lancer', "Lanceception"); +Class.auto2Ception = makeCeption('auto2', "Auto-2²"); +Class.revoception = makeCeption('revolutionist', "revonception"); +Class.littleArtilleryCeption = makeCeption('littleArtillery', "Shotception") + +//Trackers +Class.trackerSmasher = makeAuto('smasher', "Scanner", {type: 'tracker3gun'}); +Class.trackerSniper = makeAuto('sniper', "Marksman", {type: 'tracker3gun'}); +Class.trackerAssassin = makeAuto('assassin', "Hitman", {type: 'tracker3gun'}); +Class.trackerHunter = makeAuto('hunter', "Pinner", {type: 'tracker3gun'}); +Class.trackerMini = makeAuto('minigun', "Scout", {type: 'tracker3gun'}); +Class.trackerRifle = makeAuto('rifle', "DMR", {type: 'tracker3gun'}); +Class.trackerTwinsniper = makeAuto('twinsniper', "Bolt Action", {type: 'tracker3gun'}); +Class.trackerSniperHybrid = makeAuto('snipebrid', "Camper", {type: 'tracker3gun'}); +Class.trackerAcid = makeAuto('acid', "Arsenic", {type: 'tracker3gun'}); +Class.trackerChill = makeAuto('chiller', "Devils Breath", {type: 'tracker3gun'}); +Class.trackerSnipeArtillery = makeAuto('littleSnipeArtillery', "U.A.V.", {type: 'tracker3gun'}); + +//Homing Auto Tanks +Class.homingautoBasic = makeAuto("basic", "Homing Auto-Basic", {type: 'homingAutoTurret'}); +Class.homingautoTwin = makeAuto("twin", "Homing Auto-Twin", {type: 'homingAutoTurret'}); +Class.homingautoMach = makeAuto("machineGun", "Homing Auto-Machine", {type: 'homingAutoTurret'}); +Class.homingautoSniper = makeAuto("sniper", "Homing Auto-Sniper", {type: 'homingAutoTurret'}); +Class.homingautoFlank = makeAuto("flankGuard", "Homing Auto-Flank", {type: 'homingAutoTurret'}); +Class.homingautoDirector = makeAuto("director", "Homing Chairman", {type: 'homingAutoTurret'}); +Class.homingautoPound = makeAuto("pounder", "Homing Scratcher", {type: 'homingAutoTurret'}); +Class.homingautoTrap = makeAuto("trapper", "Homing Auto-Trapper", {type: 'homingAutoTurret'}); +Class.homingautoDesmos = makeAuto("desmos", "Homing Charter", {type: 'homingAutoTurret'}); +Class.homingautobascrid = makeAuto("bascrid", "Homing Auto-Basebrid", {type: 'homingAutoTurret'}) +Class.homingautolittleHunter = makeAuto("littleHunter", "Homing Duelist", {type: 'homingAutoTurret'}) +Class.homingautoinception = makeAuto("inception", "Homing Deployer", {type: 'homingAutoTurret'}); +Class.homingautopropel = makeAuto("propel", "Homing Grazer", {type: 'homingAutoTurret'}); +Class.homingautoauto2 = makeAuto("auto2", "Homing Auto²-2", {type: 'homingAutoTurret'}); +Class.homingautolancer = makeAuto("lancer", "Homing Lancer", {type: 'homingAutoTurret'}); +Class.homingautolittleArtillery = makeAuto("littleArtillery", "Taco", {type: 'homingAutoTurret'}) + +//Auras +Class.auraBasic = makeAura(Class.basic); +Class.auraTwin = makeAura(Class.twin); +Class.auraSniper = makeAura(Class.sniper); +Class.auraMachineGun = makeAura(Class.machineGun); +Class.auraFlankGuard = makeAura(Class.flankGuard); +Class.auraDirector = makeAura(Class.director); +Class.auraPounder = makeAura(Class.pounder); +Class.auraTrapper = makeAura(Class.trapper); +Class.auraAutoBasic = makeAura(Class.autoBasic); +Class.auraBascrid = makeAura(Class.bascrid); +Class.auraLittleHunter = makeAura(Class.littleHunter); +Class.auraInception = makeAura(Class.inception); +Class.auraPropel = makeAura(Class.propel); +Class.auraDesmos = makeAura(Class.desmos); +Class.auraAuto2 = makeAura(Class.auto2); +Class.auraLittleArtillery = makeAura(Class.littleArtillery); +Class.auraSmasher = makeAura(Class.smasher); + +Class.damageAuraBasic = makeAura(Class.basic, "Omen Basic", {type: 'auraDamageGen'}); +Class.damageAuraTwin = makeAura(Class.twin, "Omen Twin", {type: 'auraDamageGen'}); +Class.damageAuraSniper = makeAura(Class.sniper, "Omen Sniper", {type: 'auraDamageGen'}); +Class.damageAuraMachineGun = makeAura(Class.machineGun, "Omen Machine Gun", {type: 'auraDamageGen'}); +Class.damageAuraFlankGuard = makeAura(Class.flankGuard, "Omen Flank Guard", {type: 'auraDamageGen'}); +Class.damageAuraDirector = makeAura(Class.director, "Omen Director", {type: 'auraDamageGen'}); +Class.damageAuraPounder = makeAura(Class.pounder, "Omen Pounder", {type: 'auraDamageGen'}); +Class.damageAuraTrapper = makeAura(Class.trapper, "Omen Trapper", {type: 'auraDamageGen'}); +Class.damageAuraAutoBasic = makeAura(Class.autoBasic, "Omen Auto-Basic", {type: 'auraDamageGen'}); +Class.damageAuraBascrid = makeAura(Class.bascrid, "Omen Basebrid", {type: 'auraDamageGen'}); +Class.damageAuraLittleHunter = makeAura(Class.littleHunter, "Omen Subduer", {type: 'auraDamageGen'}); +Class.damageAuraInception = makeAura(Class.inception, "Omen Inception", {type: 'auraDamageGen'}); +Class.damageAuraPropel = makeAura(Class.propel, "Omen Propeller", {type: 'auraDamageGen'}); +Class.damageAuraDesmos = makeAura(Class.desmos, "Omen Desmos", {type: 'auraDamageGen'}); +Class.damageAuraAuto2 = makeAura(Class.auto2, "Omen Auto-2", {type: 'auraDamageGen'}); +Class.damageAuraLancer = makeAura(Class.lancer, "Omen Lancer", {type: 'auraDamageGen'}); +Class.damageAuraLittleArtillery = makeAura(Class.littleArtillery, "Omen Minishot", {type: 'auraDamageGen'}); + +Class.rangeAuraBasic = makeAura(Class.basic, "Mega-Aura Basic", {type: 'auraRangeGen'}); +Class.rangeAuraTwin = makeAura(Class.twin, "Mega-Aura Twin", {type: 'auraRangeGen'}); +Class.rangeAuraSniper = makeAura(Class.sniper, "Mega-Aura Sniper", {type: 'auraRangeGen'}); +Class.rangeAuraMachineGun = makeAura(Class.machineGun, "Mega-Aura Machine Gun", {type: 'auraRangeGen'}); +Class.rangeAuraFlankGuard = makeAura(Class.flankGuard, "Mega-Aura Flank Guard", {type: 'auraRangeGen'}); +Class.rangeAuraDirector = makeAura(Class.director, "Mega-Aura Director", {type: 'auraRangeGen'}); +Class.rangeAuraPounder = makeAura(Class.pounder, "Mega-Aura Pounder", {type: 'auraRangeGen'}); +Class.rangeAuraTrapper = makeAura(Class.trapper, "Mega-Aura Trapper", {type: 'auraRangeGen'}); +Class.rangeAuraAutoBasic = makeAura(Class.autoBasic, "Mega-Aura Auto-Basic", {type: 'auraRangeGen'}); +Class.rangeAuraBascrid = makeAura(Class.bascrid, "Mega-Aura Bascrid", {type: 'auraRangeGen'}); +Class.rangeAuraLittleHunter = makeAura(Class.littleHunter, "Mega-Aura Subduer", {type: 'auraRangeGen'}); +Class.rangeAuraInception = makeAura(Class.inception, "Mega-Aura Inception", {type: 'auraRangeGen'}); +Class.rangeAuraPropel = makeAura(Class.propel, "Mega-Aura Propeller", {type: 'auraRangeGen'}); +Class.rangeAuraDesmos = makeAura(Class.desmos, "Mega-Aura Desmos", {type: 'auraRangeGen'}); +Class.rangeAuraAuto2 = makeAura(Class.auto2, "Mega-Aura Auto-2", {type: 'auraRangeGen'}); +Class.rangeAuraLancer = makeAura(Class.lancer, "Mega-Aura Lancer", {type: 'auraRangeGen'}); +Class.rangeAuraLittleArtillery = makeAura(Class.littleArtillery, "Mega-Aura Minishot", {type: 'auraRangeGen'}); + +Class.damagerangeAuraBasic = makeAura(Class.basic, "Mega-Omen Basic", {type: 'auraDamageRangeGen'}); +Class.moredamageAuraBasic = makeAura(Class.basic, "X-Omen Basic", {type: 'auraMoreDamageGen'}); +Class.morerangeAuraBasic = makeAura(Class.basic, "X-Mega-Aura Basic", {type: 'auraMoreRangeGen'}); + +//Twin +Class.auraDoubleTwin = makeAura(Class.doubleTwin); +Class.auraTripleShot = makeAura(Class.tripleShot); + +//Snipe +Class.auraAssassin = makeAura(Class.assassin); +Class.auraHunter = makeAura(Class.hunter); +Class.auraRifle = makeAura(Class.rifle); +Class.auraTrackerSniper = makeAura(Class.trackerSniper); +Class.auraTwinSniper = makeAura(Class.twinsniper); +Class.auraAcid = makeAura(Class.acid); +Class.auraChiller = makeAura(Class.chiller); + +//Mach +Class.auraMinigun = makeAura(Class.minigun); +Class.auraGunner = makeAura(Class.gunner); +Class.auraSprayer = makeAura(Class.sprayer); +Class.auraGatlinggun = makeAura(Class.gatlinggun); +Class.auraMiniVulc = makeAura(Class.miniVulc); + +//Flank +Class.auraHexaTank = makeAura(Class.hexaTank); +Class.auraTriAngle = makeAura(Class.triAngle); +Class.auraAuto3 = makeAura(Class.auto3); +Class.auraBackShield = makeAura(Class.backShield); + +//drone +Class.auraOverseer = makeAura(Class.overseer); +Class.auraCruiser = makeAura(Class.cruiser); +Class.auraUnderseer = makeAura(Class.underseer); +Class.auraSpawner = makeAura(Class.spawner); +Class.auraDirectdrive = makeAura(Class.directdrive); +Class.auraNoble = makeAura(Class.noble); + +//pound +Class.auraDestroyer = makeAura(Class.destroyer); +Class.auraArtillery = makeAura(Class.artillery); +Class.auraLauncher = makeAura(Class.launcher); + +//trap +Class.auraBuilder = makeAura(Class.builder); +Class.auraTriTrapper = makeAura(Class.triTrapper); +Class.auraTrapGuard = makeAura(Class.trapGuard); +Class.auraWark = makeAura(Class.wark); +Class.auraIceTrapper = makeAura(Class.icetrapper); + +//Auto +Class.auraAutoTwin = makeAura(Class.autoTwin); +Class.auraAutoSniper = makeAura(Class.autoSniper); +Class.auraAutoMach = makeAura(Class.autoMach); +Class.auraAutoFlank = makeAura(Class.autoFlank); +Class.auraAutoDirector = makeAura(Class.autoDirector); +Class.auraAutoPound = makeAura(Class.autoPound); +Class.auraAutoTrap = makeAura(Class.autoTrap); +Class.auraAutoDesmos = makeAura(Class.autoDesmos); +Class.auraRevolutionist = makeAura(Class.revolutionist); +Class.auraAutoLittleHunter = makeAura(Class.autolittleHunter); +Class.auraAutoInception = makeAura(Class.autoinception); +Class.auraAutoAuto2 = makeAura(Class.autoauto2); +Class.auraAutoLancer = makeAura(Class.autolancer); +Class.auraAutoPropel = makeAura(Class.autoPropel); +Class.auraAutoLittleArtillery = makeAura(Class.autolittleArtillery); +Class.auraBasicCeption = makeAura(Class.basicCeption); +Class.auraHomingautoBasic = makeAura(Class.homingautoBasic); + +//Brid +Class.auratwinbrid = makeAura(Class.twinbrid); +Class.aurasnipebrid = makeAura(Class.snipebrid); +Class.auramachbrid = makeAura(Class.machbrid); +Class.auraflankbrid = makeAura(Class.flankbrid); +Class.aurapoundbrid = makeAura(Class.poundbrid); +Class.auratrapbrid = makeAura(Class.trapbrid); +Class.auraautobascrid = makeAura(Class.autobascrid); +Class.auradesmosbrid = makeAura(Class.desmosbrid); +Class.auralittlehunterbrid = makeAura(Class.littleHunterbrid); +Class.aurainceptionbrid = makeAura(Class.inceptionbrid); +Class.aurapropelbrid = makeAura(Class.auto2brid); +Class.auraauto2brid = makeAura(Class.auto2brid); +Class.auralancebrid = makeAura(Class.lancebrid); +Class.auralittleartillerybrid = makeAura(Class.littleArtillerybrid) +Class.jeep = makeAura(Class.car, "Jeep"); + +//Sub +Class.auraBinary = makeAura(Class.binary); +Class.auraContagion = makeAura(Class.contagion); +Class.auraGundirector = makeAura(Class.gundirector); +Class.auraBigSubduer = makeAura(Class.bigSubduer); +Class.auraFlankdue = makeAura(Class.flankdue); + +//Incep +Class.auraInceptionist = makeAura(Class.inceptionist) +Class.auraMachinception = makeAura(Class.machinception); +Class.auraTailgator = makeAura(Class.tailgator); +Class.auraFlankinception = makeAura(Class.flankinception); + +//Desmos +Class.auraSidewinder = makeAura(Class.sidewinder); +Class.auraHelix = makeAura(Class.helix); +Class.auraUndertow = makeAura(Class.undertow); +Class.auraRepeater = makeAura(Class.repeater); + +//Swivel +Class.auraSwivel2 = makeAura(Class.swivel2); + +//Lance +Class.auraLancer = makeAura(Class.lancer); +Class.auraChasseur = makeAura(Class.chasseur); +Class.auraBayonet = makeAura(Class.bayonet); + +//Prop +Class.auraBateau = makeAura(Class.bateau); +Class.auraJouster = makeAura(Class.jouster); + +Class.auraLittleMortar = makeAura(Class.littleMortar); +Class.auraLittleTwinArtillery = makeAura(Class.littleTwinArtillery); +Class.auraLittleSnipeArtillery = makeAura(Class.littleSnipeArtillery); +Class.auraLittleMachArtillery = makeAura(Class.littleMachArtillery); +Class.auraLittleFlankArtillery = makeAura(Class.littleFlankArtillery); +Class.auraLittleDirectArtillery = makeAura(Class.littleDirectArtillery); +Class.auraLittleTrapArtillery = makeAura(Class.littleTrapArtillery); +Class.auraLittleSineArtillery = makeAura(Class.littleSineArtillery); +Class.auraLittleSubArtillery = makeAura(Class.littleSubArtillery); +Class.auraLittleIncepArtillery = makeAura(Class.littleIncepArtillery); +Class.auraLittlePropArtillery = makeAura(Class.littlePropArtillery); +Class.auraLittleLanceArtillery = makeAura(Class.littleLanceArtillery); + +// TANK UPGRADE PATHS +Class.basic.UPGRADES_TIER_1 = ["twin", "sniper", "machineGun", "flankGuard", "director", "pounder", "trapper", /*"autoBasic", */"desmos", /*"bascrid", */"littleHunter", "inception", "propel", "lancer", /*"auto2", "auraBasic", */"whirlwind", "littleArtillery"] + Class.basic.UPGRADES_TIER_2 = ["smasher", "cloner"] + + Class.smasher.UPGRADES_TIER_3 = ["megaSmasher", "spike", "landmine", "pion", "trackerSmasher", "saturn", "skater", "acidsmasher", "flail", "autoSmasher", "auraSmasher", "jumpSmasher"] + Class.healer.UPGRADES_TIER_3 = ["medic", "ambulance", "surgeon", "paramedic"] + Class.cloner.UPGRADES_TIER_3 = ["hivemind", "autoCloner", "clonebrid"] + + Class.twin.UPGRADES_TIER_2 = ["doubleTwin", "tripleShot", "gunner", "hexaTank", "helix", "wark", "binary", "twinsniper", "littleTwinArtillery", "autoTwin", "twinbrid", "auraTwin"] + Class.twin.UPGRADES_TIER_3 = ["attacker"] + Class.doubleTwin.UPGRADES_TIER_3 = ["tripleTwin", "hewnDouble", "bulwark", "autoDouble", "bentDouble", "doubletwinbrid", "auraDoubleTwin"] + Class.tripleShot.UPGRADES_TIER_3 = ["pentaShot", "spreadshot", "bentDouble", "triplet", "autoTripleShot", "triplex", "bentHybrid", "trinary", "auraTripleShot"] + + Class.sniper.UPGRADES_TIER_2 = ["assassin", "hunter", "minigun", "rifle", "twinsniper", "autoSniper", "snipebrid", "trackerSniper", "acid", "chiller", "chasseur", "littleSnipeArtillery", "auraSniper"] + Class.sniper.UPGRADES_TIER_3 = ["bushwhacker", "flashfire"] + Class.assassin.UPGRADES_TIER_3 = ["ranger", "xHunter", "falcon", "stalker", "autoAssassin", "assbrid", "trackerAssassin", "disintegrator", "freezer", "auraAssassin", "single"] + Class.hunter.UPGRADES_TIER_3 = ["predator", "xHunter", "poacher", "ordnance", "railgun", "dual", "wakizashi", "autoHunter", "trackerHunter", 'auraHunter'] + Class.rifle.UPGRADES_TIER_3 = ["musket", "crossbow", "armsman", "autoRifle", "trackerRifle", "auraRifle"] + Class.trackerSniper.UPGRADES_TIER_3 = ["trackerAssassin", "trackerHunter", "trackerMini", "trackerRifle", "trackerTwinsniper", "trackerSniperHybrid", "trackerAcid", "trackerChill", "trackerSnipeArtillery", "auraTrackerSniper"] + Class.twinsniper.UPGRADES_TIER_3 = ["dual", "musket", "autoTwinsniper", "twipebrid", "trackerTwinsniper", "auraTwinSniper"] + Class.acid.UPGRADES_TIER_3 = ["disintegrator", "acidsmasher", "formaldehyde", "frostbite", "autoAcid", "acidbrid", "trackerAcid", "auraAcid"] + Class.chiller.UPGRADES_TIER_3 = ["freezer", "icegun", "frostbite", "autoChill", "chillbrid", "trackerChill", "auraChiller", "surge"] + + Class.machineGun.UPGRADES_TIER_2 = ["artillery", "minigun", "gunner", "sprayer", "gatlinggun", "accelmachinegun", "autoMach", "machbrid", "machinception", "miniVulc", "littleMachArtillery", "auraMachineGun"] + Class.minigun.UPGRADES_TIER_3 = ["streamliner", "nailgun", "cropDuster", "barricade", "vulture", "minilaser", "formaldehyde", "icegun", "autoMini", "trackerMini", "accelminigun", "auraMinigun"] + Class.gunner.UPGRADES_TIER_3 = ["autoGunner", "nailgun", "auto4", "machineGunner", "gunnerTrapper", "cyclone", "overgunner", "waterfall", "helecopter", "auraGunner"] + Class.sprayer.UPGRADES_TIER_3 = ["redistributor", "phoenix", "atomizer", "focal", "Sprayinception", "autoSprayer", "spraybrid", "auraSprayer"] + Class.gatlinggun.UPGRADES_TIER_3 = ["focal", "Gatlinception", "accelgatlinggun", "autoGatlinggun", "gatlinggunbrid", "auraGatlinggun"] + Class.accelmachinegun.UPGRADES_TIER_3 = ["accelArtillery", "accelminigun", "accelgatlinggun"] + Class.miniVulc.UPGRADES_TIER_3 = ["nailgun", "vulcan", "miniVulcTrap", "autominiVulc", "miniVulcbrid", "auraMiniVulc"] + + Class.flankGuard.UPGRADES_TIER_2 = ["hexaTank", "triAngle", "auto3", "trapGuard", "triTrapper", "autoFlank", "flankbrid", "flankdue", /*"flankinception", */"backShield", "littleFlankArtillery", "auraFlankGuard"] + Class.flankGuard.UPGRADES_TIER_3 = ["tripleTwin", "quadruplex"] + Class.hexaTank.UPGRADES_TIER_3 = ["octoTank", "cyclone", "hexaTrapper", "autoHexaTank", "hexatankbrid", "auraHexaTank", "hexaWhirl"] + Class.triAngle.UPGRADES_TIER_3 = ["fighter", "booster", "falcon", "bomber", "autoTriAngle", "trianglebrid", "surfer", "eagle", "phoenix", "vulture", "subway", "helecopter", "trailblazer", "rocker", "cockatiel", "auraTriAngle"] + Class.backShield.UPGRADES_TIER_3 = ["bigBackShield", "brella", "slasher", "attacker", "autoBackShield", "backshieldbrid", "auraBackShield"] + + Class.director.UPGRADES_TIER_2 = ["overseer", "cruiser", "underseer", "gundirector", "spawner", "directdrive", "noble", "autoDirector", "littleDirectArtillery", "auraDirector"] + Class.director.UPGRADES_TIER_3 = ["manager", "bigCheese"] + Class.overseer.UPGRADES_TIER_3 = ["overlord", "overtrapper", "overgunner", "banshee", "autoOverseer", "trojan", "overdrive", "commander", "helium", "auraOverseer"] + Class.cruiser.UPGRADES_TIER_3 = ["carrier", "battleship", "fortress", "surfer", "wyrm", "autoCruiser", "commander", "neon", "auraCruiser"] + Class.underseer.UPGRADES_TIER_3 = ["necromancer", "maleficitor", "infestor", "autoUnderseer", "argon", "auraUnderseer"/* "prophet",*/] + Class.spawner.UPGRADES_TIER_3 = ["factory", "protist", "polygun", "autoSpawner", "xenon", "auraSpawner"] + Class.directdrive.UPGRADES_TIER_3 = ["overdrive", "cruiserdrive", "revodirector", "honda", "dictator", "radon", "autoMotor", "auraDirectdrive"] + Class.noble.UPGRADES_TIER_3 = ["helium", "neon", "argon", "krypton", "xenon", "radon", "oganesson", "auraNoble"] + + Class.pounder.UPGRADES_TIER_2 = ["destroyer", "builder", "artillery", "launcher", "autoPound", "poundbrid", "tailgator", "auraPounder"] + Class.pounder.UPGRADES_TIER_3 = ["shotgun", "eagle"] + Class.destroyer.UPGRADES_TIER_3 = ["conqueror", "annihilator", "hybrid", "construct", "autoDestroy", "waterfall", "interceptor", "auraDestroyer"] + Class.artillery.UPGRADES_TIER_3 = ["mortar", "ordnance", "beekeeper", "fieldGun", "autoArtillery", "artilbrid", "auraArtillery", "munition"] + Class.launcher.UPGRADES_TIER_3 = ["skimmer", "twister", "swarmer", "rocketeer", "fieldGun", "shrapnelgun", "firecracker", "autoLaunch", "launchbrid", "auraLauncher", "vortex"] + + Class.trapper.UPGRADES_TIER_2 = ["builder", "triTrapper", "trapGuard", "wark", "contagion", "icetrapper", "autoTrap", "trapbrid", "littleTrapArtillery", "auraTrapper"] + Class.trapper.UPGRADES_TIER_3 = ["barricade"] + Class.builder.UPGRADES_TIER_3 = ["construct", "engineer", "boomer", "assembler", "architect", "conqueror", "fort", "icebuilder", "ramrod", "autoBuilder", "builderbrid", "auraBuilder"] + Class.triTrapper.UPGRADES_TIER_3 = ["fortress", "hexaTrapper", "septaTrapper", "architect", "triContagion", "icetriTrapper", "tritrapperbrid", "auraTriTrapper"] + Class.trapGuard.UPGRADES_TIER_3 = ["bushwhacker", "gunnerTrapper", "bomber", "conqueror", "bulwark", "icetrapGuard", "miniVulcTrap", "autoTrapGuard", "trapguardbrid", "auraTrapGuard", "whirlGuard"] + Class.wark.UPGRADES_TIER_3 = ["bulwark", "twincontagion", "icewark", "autowark", "warkbrid", "auraWark"] + Class.icetrapper.UPGRADES_TIER_3 = ["icebuilder", "icetriTrapper", "icetrapGuard", "icewark", "icecontagion", "autoIcetrapper", "icetrapbrid", "auraIceTrapper"] + + Class.autoBasic.UPGRADES_TIER_2 = ["autoTwin", "autoSniper", "autoMach", "autoFlank", "autoDirector", "autoPound", "autoTrap", "autoDesmos", "autobascrid", "autolittleHunter", "autoinception", "autoPropel", "autolancer", "autoauto2", "autolittleArtillery", "auraAutoBasic", "homingautoBasic"] + Class.autoBasic.UPGRADES_TIER_3 = ["autoSmasher", "autoCloner"] + Class.autoTwin.UPGRADES_TIER_3 = ["autoDouble", "autoTripleShot", "autoGunner", "autoHexaTank", "autoHelix", "autowark", "equilibrium", "autoBinary", "autoTwinsniper", "autolittleTwinArtillery", "autotwinbrid", "auraAutoTwin", "homingautoTwin"] + Class.autoSniper.UPGRADES_TIER_3 = ["autoAssassin", "autoHunter", "autoMini", "autoRifle", "autoTwinsniper", "autoAcid", "autoChill", "autosnipebrid", "autochasseur", "autolittleSnipeArtillery", "auraAutoSniper", "homingautoSniper"] + Class.autoMach.UPGRADES_TIER_3 = ["autoArtillery", "autoMini", "autoGunner", "autoSprayer", "autoGatlinggun", "automachbrid", "automachinception", "autolittleMachArtillery", "auraAutoMach", "homingautoMach"] + Class.autoFlank.UPGRADES_TIER_3 = ["autoHexaTank", "autoTriAngle", "autoAuto3", "autoTrapGuard", "hexaTrapper", "autoflankbrid", "autoFlankdue", "autoflankinception", "autolittleFlankArtillery", "auraAutoFlank", "homingautoFlank"] + Class.autoDirector.UPGRADES_TIER_3 = ["autoOverseer", "autoCruiser", "autoUnderseer", "autoGundirector", "autoSpawner", "autolittleDirectArtillery", "auraAutoDirector", "homingautoDirector"] + Class.autoPound.UPGRADES_TIER_3 = ["autoDestroy", "autoBuilder", "autoArtillery", "autoLaunch", "autopoundbrid", "autotailgator", "auraAutoPound", "homingautoPound"] + Class.autoTrap.UPGRADES_TIER_3 = ["autoBuilder", "hexaTrapper", "autoTrapGuard", "autoContagion", "autowark", "autoIcetrapper", "autolittleTrapArtillery", "autotrapbrid", "auraAutoTrap", "homingautoTrap", "trapCeption"] + Class.autoDesmos.UPGRADES_TIER_3 = ["autoHelix", "autoUndertow", "autoRepeater", "autodesmosbrid", "autolittleSineArtillery", "auraAutoDesmos", "homingautoDesmos"] + Class.autolittleHunter.UPGRADES_TIER_3 = ["autoMini", "autoBinary", "autoHunter", "autoSprayer", "autoContagion", "autoGundirector", "autoBigSubduer", "autoFlankdue", "autobayonet", "autolittleHunterbrid", "autolittleSubArtillery", "auraAutoLittleHunter", "homingautolittleHunter"] + Class.autoinception.UPGRADES_TIER_3 = ["autoinceptionist", "automachinception", "autotailgator", "autoflankinception", "autoinceptionbrid", "autolittleIncepArtillery", "auraAutoInception", "homingautoinception"] + Class.autoPropel.UPGRADES_TIER_3 = ["autoTriAngle", "autoBateau", "autoJouster", "autopropelbrid", "autolittlePropArtillery", "auraAutoPropel", "homingautopropel"] + Class.autoauto2.UPGRADES_TIER_3 = ["autoAuto3", "autoRevolutionist", "autoSwivel2", "autoauto2brid", "auraAutoAuto2", "homingautoauto2"] + Class.autolancer.UPGRADES_TIER_3 = ["autochasseur", "autoJouster", "autobayonet", "autolancebrid", "autolittleLanceArtillery", "auraAutoLancer", "homingautolancer"] + Class.basicCeption.UPGRADES_TIER_3 = ["twinCeption", "snipeCeption", "machCeption", "flankCeption", "directCeption", "poundCeption", "trapCeption", "desmosCeption", "bascridCeption", "littleHunterCeption", "inceptCeption", "propelCeption", "lancerception", "auto2Ception", "auraBasicCeption"] + Class.homingautoBasic.UPGRADES_TIER_3 = ["homingautoTwin", "homingautoSniper", "homingautoMach", "homingautoFlank", "homingautoDirector", "homingautoPound", "homingautoTrap", "homingautoDesmos", "homingautobascrid", "homingautolittleHunter", "homingautoinception", "homingautopropel", "homingautolancer", "homingautoauto2", "homingautolittleArtillery", "auraHomingautoBasic"] + + Class.bascrid.UPGRADES_TIER_2 = ["twinbrid", "snipebrid", "machbrid", "flankbrid", "overseer", "poundbrid", "trapbrid", "autobascrid", "desmosbrid", "littleHunterbrid", "inceptionbrid", "lancebrid", "auto2brid", "car", "auraBascrid"] + Class.bascrid.UPGRADES_TIER_3 = ["clonebrid"] + Class.twinbrid.UPGRADES_TIER_3 = ["doubletwinbrid", "bentHybrid", "overgunner", "hexatankbrid", "autotwinbrid", "helixbrid", "warkbrid", "binarybrid", "twipebrid", "littleTwinArtillerybrid", "mercedes", "auratwinbrid"] + Class.snipebrid.UPGRADES_TIER_3 = ["assbrid", "poacher", "cropDuster", "armsman", "twipebrid", "autosnipebrid", "trackerSniperHybrid", "acidbrid", "chillbrid", "chasseubrid", "littleSnipeArtillerybrid", "tesla", "aurasnipebrid"] + Class.machbrid.UPGRADES_TIER_3 = ["artilbrid", "cropDuster", "overgunner", "spraybrid", "gatlinggunbrid", "automachbrid", "machinceptionbrid", "littleMachArtillerybrid", "toyota", "auramachbrid"] + Class.flankbrid.UPGRADES_TIER_3 = ["hexatankbrid", "trianglebrid", "auto3brid", "trapguardbrid", "tritrapperbrid", "autoflankbrid", "flankduebrid", "flankinceptionbrid", "littleFlankArtillerybrid", "ford", "auraflankbrid"] + Class.poundbrid.UPGRADES_TIER_3 = ["hybrid", "builderbrid", "artilbrid", "launchbrid", "autopoundbrid", "tailgatorbrid", "honda", "aurapoundbrid"] + Class.trapbrid.UPGRADES_TIER_3 = ["builderbrid", "tritrapperbrid", "trapguardbrid", "contagionbrid", "warkbrid", "icetrapbrid", "autotrapbrid", "overtrapper", "littleTrapArtillerybrid", "gmc", "auratrapbrid"] + Class.autobascrid.UPGRADES_TIER_3 = ["autotwinbrid", "autosnipebrid", "automachbrid", "autoflankbrid", "autopoundbrid", "autotrapbrid", "autodesmosbrid", "autolittleHunterbrid", "autoinceptionbrid", "autopropelbrid", "autolancebrid", "porsche", "auraautobascrid"] + Class.desmosbrid.UPGRADES_TIER_3 = ["helixbrid", "undertowbrid", "repeaterbrid", "autodesmosbrid", "littleSineArtillerybrid", "mazda", "auradesmosbrid"] + Class.littleHunterbrid.UPGRADES_TIER_3 = ["cropDuster", "binarybrid", "poacher", "spraybrid", "contagionbrid", "bigsubduerbrid", "flankduebrid", "bayonetbrid", "autolittleHunterbrid", "littleSubArtillerybrid", "volkswagen", "auralittlehunterbrid"] + Class.inceptionbrid.UPGRADES_TIER_3 = ["trianglebrid", "machinceptionbrid", "tailgatorbrid", "flankinceptionbrid", "overdrive", "autoinceptionbrid", "littleIncepArtillerybrid", "audi", "aurainceptionbrid"] + Class.propelbrid.UPGRADES_TIER_3 = ["trianglebrid", "bateaubrid", "jousterbrid", "autopropelbrid", "littlePropArtillerybrid", "mustang", "aurapropelbrid"] + Class.auto2brid.UPGRADES_TIER_3 = ["auto3brid", "revobrid", "swivel2brid", "autoauto2brid", "ferrari", "auraauto2brid"] + Class.lancebrid.UPGRADES_TIER_3 = ["chasseubrid", "jousterbrid", "bayonetbrid", "autolancebrid", "littleLanceArtillerybrid", "ram", "auralancebrid"] + Class.car.UPGRADES_TIER_3 = ["mercedes", "tesla", "toyota", "ford", "overdrive", "honda", "gmc", "porsche", "mazda", "volkswagen", "audi", "mustang", "ram", "ferrari", "jeep", "chrysler"] + + Class.littleHunter.UPGRADES_TIER_2 = ["minigun", "binary", "hunter", "sprayer", "contagion", "gundirector", "bigSubduer", "flankdue", "bayonet", "autolittleHunter", "littleHunterbrid", "littleSubArtillery", "auraLittleHunter"] + Class.binary.UPGRADES_TIER_3 = ["trinary", "dual", "twincontagion", "autoBinary", "binarybrid", "auraBinary"] + Class.contagion.UPGRADES_TIER_3 = ["fort", "triContagion", "twincontagion", "droneTrapper", "cockatiel", "icecontagion", "autoContagion", "contagionbrid", "auraContagion"] + Class.gundirector.UPGRADES_TIER_3 = ["trojan", "protist", "wyrm", "gundirectorbig", "droneTrapper", "autoGundirector", "krypton", "auraGundirector"] + Class.bigSubduer.UPGRADES_TIER_3 = ["predator", "redistributor", "biggerSubduer", "clubbin", "autoBigSubduer", "bigsubduerbrid", "auraBigSubduer"] + Class.flankdue.UPGRADES_TIER_3 = ["subway", "triContagion", "clubbin", "autoFlankdue", "flankduebrid", "auraFlankdue"] + + Class.inception.UPGRADES_TIER_2 = ["inceptionist", "machinception", "tailgator", "launcher", /*"flankinception", */"directdrive", "spawner", "autoinception", "inceptionbrid", "littleIncepArtillery", "auraInception"] + Class.inceptionist.UPGRADES_TIER_3 = ["twinceptionist", "machceptionist", "poundceptionist", /*"flankceptionist", */"factory", "autoinceptionist", "inceptionistbrid", "auraInceptionist"] + Class.machinception.UPGRADES_TIER_3 = ["machceptionist", "Sprayinception", "Gatlinception", "automachinception", "machinceptionbrid", "auraMachinception"] + Class.tailgator.UPGRADES_TIER_3 = ["poundceptionist", "interceptor", "engineer", "shrapnelgun", "autotailgator", "tailgatorbrid", "auraTailgator"] + Class.flankinception.UPGRADES_TIER_3 = ["flankceptionist", "autoflankinception", "flankinceptionbrid", "auraFlankinception"] + + Class.desmos.UPGRADES_TIER_2 = ["helix", "undertow", "repeater", "homingautoBasic", "autoDesmos", "desmosbrid", "littleSineArtillery", "auraDesmos"] + Class.helix.UPGRADES_TIER_3 = ["triplex", "quadruplex", "duplicator", "autoHelix", "helixbrid", "auraHelix"] + Class.undertow.UPGRADES_TIER_3 = ["riptide", "choker", "autoUndertow", "undertowbrid", "auraUndertow"] + Class.repeater.UPGRADES_TIER_3 = ["iterator", "duplicator", "autoRepeater", "repeaterbrid", "auraRepeater"] + + Class.auraBasic.UPGRADES_TIER_2 = ["auraTwin", "auraSniper", "auraMachineGun", "auraFlankGuard", "auraDirector", "auraPounder", "auraTrapper", "auraAutoBasic", "auraDesmos", "auraBascrid", "auraLittleHunter", "auraInception", "auraLancer", "auraAuto2", "damageAuraBasic", "rangeAuraBasic"] + Class.auraBasic.UPGRADES_TIER_3 = ["auraSmasher"] + Class.auraTwin.UPGRADES_TIER_3 = ["auraDoubleTwin", "auraTripleShot", "auraGunner", "auraHexaTank", "auraAutoTwin", "auraHelix", "auraWark", "auratwinbrid", "auraBinary", "auraTwinSniper", "auraLittleTwinArtillery", "damageAuraTwin", "rangeAuraTwin"] + Class.auraSniper.UPGRADES_TIER_3 = ["auraAssassin", "auraHunter", "auraMinigun", "auraRifle", "auraTwinSniper", "auraAutoSniper", "aurasnipebrid", "auraTrackerSniper", "auraAcid", "auraChiller", "auraChasseur", "auraLittleSnipeArtillery", "damageAuraSniper", "rangeAuraSniper"] + Class.auraMachineGun.UPGRADES_TIER_3 = ["auraArtillery", "auraMinigun", "auraGunner", "auraSprayer", "auraGatlinggun", "auraAutoMach", "auramachbrid", "auraMachinception", "auraLittleMachArtillery", "damageAuraMachineGun", "rangeAuraMachineGun"] + Class.auraFlankGuard.UPGRADES_TIER_3 = ["auraHexaTank", "auraTriAngle", "auraAuto3", "auraTrapGuard", "auraTriTrapper", "auraAutoFlank", "auraflankbrid", "auraFlankdue", "auraFlankinception", "auraBackShield", "auraLittleFlankArtillery", "damageAuraFlankGuard", "rangeAuraFlankGuard"] + Class.auraDirector.UPGRADES_TIER_3 = ["auraOverseer", "auraCruiser", "auraUnderseer", "auraSpawner", "auraDirectdrive", "auraAutoDirector", "auraNoble", "auraLittleDirectArtillery", "damageAuraDirector", "rangeAuraDirector"] + Class.auraPounder.UPGRADES_TIER_3 = ["auraDestroyer", "auraBuilder", "auraArtillery", "auraLauncher", "auraAutoPound", "aurapoundbrid", "auraTailgator", "damageAuraPounder", "rangeAuraPounder"] + Class.auraTrapper.UPGRADES_TIER_3 = ["auraBuilder", "auraTriTrapper", "auraTrapGuard", "auraContagion", "auraWark", "auraIceTrapper", "auraAutoTrap", "auratrapbrid", "auraLittleTrapArtillery", "damageAuraTrapper", "rangeAuraTrapper"] + Class.auraAutoBasic.UPGRADES_TIER_3 = ["auraAutoTwin", "auraAutoSniper", "auraAutoMach", "auraAutoFlank", "auraAutoDirector", "auraAutoPound", "auraAutoTrap", "auraAutoDesmos", "auraautobascrid", "auraAutoLittleHunter", "auraAutoInception", "auraHomingautoBasic", "damageAuraAutoBasic", "rangeAuraAutoBasic"] + Class.auraBascrid.UPGRADES_TIER_3 = ["auratwinbrid", "aurasnipebrid", "auramachbrid", "auraflankbrid", "aurapoundbrid", "auratrapbrid", "auradesmosbrid", "auraautobascrid", "auralittlehunterbrid", "aurainceptionbrid", "jeep", "damageAuraBascrid", "rangeAuraBascrid"] + Class.auraDesmos.UPGRADES_TIER_3 = ["auraHelix", "auraUndertow", "auraRepeater", "auraAutoDesmos", "auradesmosbrid", "auraLittleSineArtillery", "damageAuraDesmos", "rangeAuraDesmos"] + Class.auraLittleHunter.UPGRADES_TIER_3 = ["auraMinigun", "auraBinary", "auraHunter", "auraSprayer", "auraContagion", "auraGundirector", "auraBigSubduer", "auraFlankdue", "auraBayonet", "auraAutoLittleHunter", "auralittlehunterbrid", "auraLittleSubArtillery", "damageAuraLittleHunter", "rangeAuraLittleHunter"] + Class.auraInception.UPGRADES_TIER_3 = ["auraInceptionist", "auraMachinception", "auraTailgator", "auraFlankinception", "auraAutoInception", "aurainceptionbrid", "auraLittleIncepArtillery", "damageAuraInception", "rangeAuraInception"] + Class.auraPropel.UPGRADES_TIER_3 = ["auraTriAngle", "auraBateau", "auraJouster", "auraAutoPropel", "aurapropelbrid", "auraLittlePropArtillery", "damageAuraPropel", "rangeAuraPropel"] + Class.auraAuto2.UPGRADES_TIER_3 = ["auraAuto3", "auraRevolutionist", "auraAutoAuto2", "auraauto2brid", "damageAuraAuto2", "rangeAuraAuto2"] + Class.auraLancer.UPGRADES_TIER_3 = ["auraChasseur", "auraJouster", "auraBayonet", "auraAutoLancer", "auralancebrid", "auraLittleLanceArtillery", "damageAuraLancer", "rangeAuraLancer"] + Class.damageAuraBasic.UPGRADES_TIER_3 = ["damageAuraTwin", "damageAuraSniper", "damageAuraMachineGun", "damageAuraFlankGuard", "damageAuraDirector", "damageAuraPounder", "damageAuraTrapper", "damageAuraAutoBasic", "damageAuraBascrid", "damageAuraDesmos", "damageAuraLittleHunter", "damageAuraInception", "damageAuraPropel", "damageAuraAuto2", "damageAuraLancer", "moredamageAuraBasic", "damagerangeAuraBasic"] + Class.rangeAuraBasic.UPGRADES_TIER_3 = ["rangeAuraTwin", "rangeAuraSniper", "rangeAuraMachineGun", "rangeAuraFlankGuard", "rangeAuraDirector", "rangeAuraPounder", "rangeAuraTrapper", "rangeAuraAutoBasic", "rangeAuraBascrid", "rangeAuraDesmos", "rangeAuraLittleHunter", "rangeAuraInception", "rangeAuraPropel", "rangeAuraAuto2", "rangeAuraLancer", "morerangeAuraBasic", "damagerangeAuraBasic"] + + Class.auto2.UPGRADES_TIER_2 = ["auto3", "revolutionist", "swivel2", "autoauto2", "auto2brid", "auraAuto2"] + Class.auto3.UPGRADES_TIER_3 = ["auto5", "mega3", "auto4", "banshee", "homingautoauto2", "autoAuto3", "auto3brid", "auraAuto3", "whirl3"] + Class.revolutionist.UPGRADES_TIER_3 = ["subverter", "autoRevolutionist", "proton", "pion", "hadron", "equilibrium", "revobrid", "baseThrower", "revodirector", "saturn", "auraRevolutionist"] + Class.swivel2.UPGRADES_TIER_3 = ["swivel3", "axis4", "autoSwivel2", "swivel2brid", "auraSwivel2"] + + Class.lancer.UPGRADES_TIER_2 = ["chasseur", "jouster", "bayonet", "autolancer", "lancebrid", "littleLanceArtillery", "auraLancer"] + Class.lancer.UPGRADES_TIER_3 = ["slasher", "katana"] + Class.chasseur.UPGRADES_TIER_3 = ["flail", "fencer", "wakizashi", "autochasseur", "chasseubrid", "auraChasseur"] + Class.bayonet.UPGRADES_TIER_3 = ["choker", "arisaka", "wakizashi", "autobayonet", "bayonetbrid", "auraBayonet"] + + Class.propel.UPGRADES_TIER_2 = ["triAngle", "bateau", "jouster", "autoPropel", "propelbrid", "littlePropArtillery", "auraPropel"] + Class.propel.UPGRADES_TIER_3 = ["jumpSmasher", "shadow"] + Class.bateau.UPGRADES_TIER_3 = ["assblaster", "rocker", "knight", "autoBateau", "bateaubrid", "auraBateau"] + Class.jouster.UPGRADES_TIER_3 = ["trailblazer", "knight", "fencer", "arisaka", "autoJouster", "jousterbrid", "auraJouster"] + + Class.littleArtillery.UPGRADES_TIER_2 = ["littleMortar", "littleTwinArtillery", "littleSnipeArtillery", "littleMachArtillery", "littleFlankArtillery", "littleDirectArtillery", "artillery", "littleTrapArtillery", "littleSineArtillery", "littleSubArtillery", "littleIncepArtillery", "littlePropArtillery", "littleLanceArtillery", "tripleShot", "autolittleArtillery", "littleArtillerybrid", "auraLittleArtillery"] + Class.littleMortar.UPGRADES_TIER_3 = ["littleSheller", "littleTwinMortar", "littleSnipeMortar", "littleMachMortar", "littleFlankMortar", "littleDirectMortar", "mortar", "littleTrapMortar", "littleDesmosMortar", "littleSubMortar", "littleIncepMortar", "littlePropMortar", "littleLanceMortar", "pentaShot", "machineGunner", "autolittleMortar", "littleMortarbrid", "auraLittleMortar"] + Class.littleTwinArtillery.UPGRADES_TIER_3 = ["littleTwinMortar", "autolittleTwinArtillery", "littleTwinArtillerybrid", "auraLittleTwinArtillery"] + Class.littleSnipeArtillery.UPGRADES_TIER_3 = ["crossbow", "littleSnipeMortar", "autolittleSnipeArtillery", "littleSnipeArtillerybrid", "trackerSnipeArtillery", "auraLittleSnipeArtillery"] + Class.littleMachArtillery.UPGRADES_TIER_3 = ["littleMachMortar", "autolittleMachArtillery", "littleMachArtillerybrid", "auraLittleMachArtillery"] + Class.littleFlankArtillery.UPGRADES_TIER_3 = ["littleFlankMortar", "autolittleFlankArtillery", "littleFlankArtillerybrid", "auraLittleFlankArtillery"] + Class.littleDirectArtillery.UPGRADES_TIER_3 = ["littleDirectMortar", "autolittleDirectArtillery", "auraLittleDirectArtillery"] + Class.littleTrapArtillery.UPGRADES_TIER_3 = ["littleTrapMortar", "autolittleTrapArtillery", "littleTrapArtillerybrid", "auraLittleTrapArtillery"] + Class.littleSineArtillery.UPGRADES_TIER_3 = ["littleDesmosMortar", "autolittleSineArtillery", "littleSineArtillerybrid", "auraLittleSineArtillery"] + Class.littleSubArtillery.UPGRADES_TIER_3 = ["littleSubMortar", "autolittleSubArtillery", "littleSubArtillerybrid", "auraLittleSubArtillery"] + Class.littleIncepArtillery.UPGRADES_TIER_3 = ["littleIncepMortar", "autolittleIncepArtillery", "littleIncepArtillerybrid", "auraLittleIncepArtillery"] + Class.littlePropArtillery.UPGRADES_TIER_3 = ["littlePropMortar", "autolittlePropArtillery", "littlePropArtillerybrid", "auraLittlePropArtillery"] + Class.littleLanceArtillery.UPGRADES_TIER_3 = ["littleLanceMortar", "autolittleLanceArtillery", "littleLanceArtillerybrid", "auraLittleLanceArtillery"] + Class.autolittleArtillery.UPGRADES_TIER_3 = ["autolittleTwinArtillery", "autolittleSnipeArtillery", "autolittleMachArtillery", "autolittleFlankArtillery", "autolittleDirectArtillery", "autoArtillery", "autolittleTrapArtillery", "autolittleSineArtillery", "autolittleSubArtillery", "autolittleIncepArtillery", "autolittlePropArtillery", "autolittleLanceArtillery", "autoTripleShot", "autolittleArtillerybrid", "auraAutoLittleArtillery", /*"littleArtilleryCeption",*/ "homingautolittleArtillery"] + Class.littleArtillerybrid.UPGRADES_TIER_3 = ["littleMortarbrid", "littleTwinArtillerybrid", "littleSnipeArtillerybrid", "littleMachArtillerybrid", "littleFlankArtillerybrid", "artilbrid", "littleTrapArtillerybrid", "littleSineArtillerybrid", "littleSubArtillerybrid", "littleIncepArtillerybrid", "littlePropArtillerybrid", "littleLanceArtillerybrid", "bentHybrid", "autolittleArtillerybrid", "chrysler", "auralittleartillerybrid"] + Class.auraLittleArtillery.UPGRADES_TIER_3 = ["auraLittleMortar", "auraLittleTwinArtillery", "auraLittleSnipeArtillery", "auraLittleMachArtillery", "auraLittleFlankArtillery", "auraLittleDirectArtillery", "auraArtillery", "auraLittleTrapArtillery", "auraLittleSineArtillery", "auraLittleSubArtillery", "auraLittleIncepArtillery", "auraLittlePropArtillery", "auraLittleLanceArtillery", "auraTripleShot", "auraAutoLittleArtillery", "auralittleartillerybrid", "damageAuraLittleArtillery", "rangeAuraLittleArtillery"] \ No newline at end of file diff --git a/server/modules/definitions/groups/turrets.js b/server/modules/definitions/groups/turrets.js index e3d95cfb1..eacfb1df5 100644 --- a/server/modules/definitions/groups/turrets.js +++ b/server/modules/definitions/groups/turrets.js @@ -1,108 +1,85 @@ -const { combineStats, makeDeco } = require('../facilitators.js'); -const { gunCalcNames, base } = require('../constants.js'); +const { combineStats, makeDeco, addAura, weaponArray, makeTurret } = require('../facilitators.js'); +const { base } = require('../constants.js'); const g = require('../gunvals.js'); -// Auto Guns -Class.autoTankGun = { - PARENT: "genericTank", - LABEL: "", - BODY: { - FOV: 3, - }, - CONTROLLERS: ["canRepel", "onlyAcceptInArc", "mapAltToFire", "nearestDifferentMaster"], - COLOR: "grey", +// Radial Auto Guns +Class.autoTankGun = makeTurret({ GUNS: [ { POSITION: [22, 10, 1, 0, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.autoTurret]), + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard]), TYPE: "bullet", }, }, ], -} -Class.bansheegun = { - PARENT: "autoTankGun", - BODY: { - FOV: 2, - }, - INDEPENDENT: true, +}, {canRepel: true, limitFov: true, fov: 3}) +Class.bansheegun = makeTurret({ GUNS: [ { POSITION: [26, 10, 1, 0, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.autoTurret, { reload: 1.5 }]), + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, { reload: 1.5 }]), TYPE: "bullet", }, }, ], -} -Class.auto4gun = { - PARENT: "autoTankGun", - BODY: { - FOV: 2, - }, +}, {limitFov: true, independent: true}) +Class.auto4gun = makeTurret({ GUNS: [ { POSITION: [16, 4, 1, 0, -3.5, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.autoTurret, g.pelleter, g.twin, g.power, { speed: 0.7, maxSpeed: 0.7 }]), + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.twin, g.power, { speed: 0.7, maxSpeed: 0.7 }]), TYPE: "bullet", }, }, { POSITION: [16, 4, 1, 0, 3.5, 0, 0.5], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.autoTurret, g.pelleter, g.twin, g.power, { speed: 0.7, maxSpeed: 0.7 }]), + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.twin, g.power, { speed: 0.7, maxSpeed: 0.7 }]), TYPE: "bullet", }, }, ], -} -Class.bigauto4gun = { - PARENT: "auto4gun", +}, {canRepel: true, limitFov: true}) +Class.bigauto4gun = makeTurret({ GUNS: [ { POSITION: [14, 5, 1, 0, -4.5, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.autoTurret, g.pelleter, g.twin, g.twin, g.power, { reload: 2 }]), + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.twin, g.twin, g.power, { reload: 2 }]), TYPE: "bullet", }, }, { POSITION: [14, 5, 1, 0, 4.5, 0, 0.33], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.autoTurret, g.pelleter, g.twin, g.twin, g.power, { reload: 2 }]), + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.twin, g.twin, g.power, { reload: 2 }]), TYPE: "bullet", }, }, { POSITION: [16, 5, 1, 0, 0, 0, 0.67], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.autoTurret, g.pelleter, g.twin, g.twin, g.power, { reload: 2 }]), + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.twin, g.twin, g.power, { reload: 2 }]), TYPE: "bullet", }, }, ], -} -Class.megaAutoTankGun = { - PARENT: "autoTankGun", - BODY: { - FOV: 2, - }, +}, {canRepel: true, limitFov: true, fov: 3}) +Class.megaAutoTankGun = makeTurret({ GUNS: [ { POSITION: [22, 14, 1, 0, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.autoTurret]), + SHOOT_SETTINGS: combineStats([g.basic, g.pounder]), TYPE: "bullet", }, }, ], -} -Class.architectGun = { - PARENT: "autoTurret", - LABEL: "", +}, {canRepel: true, limitFov: true}) +Class.architectGun = makeTurret({ GUNS: [ { POSITION: [20, 16, 1, 0, 0, 0, 0], @@ -110,28 +87,16 @@ Class.architectGun = { { POSITION: [2, 16, 1.1, 20, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.setTrap, g.autoTurret]), + SHOOT_SETTINGS: combineStats([g.trap, g.setTrap, g.flankGuard]), TYPE: "setTrap", - STAT_CALCULATOR: gunCalcNames.block + STAT_CALCULATOR: "block" }, }, ], -} +}, {canRepel: true, limitFov: true, fov: 3}) -// Boss turrets -Class.trapTurret = { - PARENT: "genericTank", - LABEL: "Turret", - BODY: { - FOV: 0.5, - }, - INDEPENDENT: true, - CONTROLLERS: ["nearestDifferentMaster", 'onlyAcceptInArc'], - COLOR: "grey", - AI: { - SKYNET: true, - FULL_VIEW: true, - }, +// NPC turrets +Class.trapTurret = makeTurret({ GUNS: [ { POSITION: [16, 14, 1, 0, 0, 0, 0], @@ -139,240 +104,130 @@ Class.trapTurret = { { POSITION: [4, 14, 1.8, 16, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.lowPower, { speed: 1.2 }, { reload: 2 }]), + SHOOT_SETTINGS: combineStats([g.trap, g.lowPower, { shudder: 0.4, speed: 0.9, reload: 2 }]), TYPE: "trap", - STAT_CALCULATOR: gunCalcNames.trap, + STAT_CALCULATOR: "trap", }, }, ], -}; -Class.baseTrapTurret = { - PARENT: "genericTank", - LABEL: "Turret", - INDEPENDENT: true, - COLOR: "grey", +}, {limitFov: true, aiSettings: {SKYNET: true, FULL_VIEW: true, independent: true, extraStats: []}}) +Class.baseTrapTurret = makeTurret({ GUNS: [ { POSITION: [16, 14, 1, 0, 0, 0, 0], }, { POSITION: [4, 14, 1.8, 16, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.lowPower, g.pounder, g.destroyer, { reload: 0.5 }, g.hexaTrapper]), + SHOOT_SETTINGS: combineStats([g.trap, g.pounder, g.hexaTrapper, {reload: 1.3, size: 1.2, health: 1.35, damage: 1.4, speed: 0.9, shudder: 0.1}]), TYPE: "trap", - STAT_CALCULATOR: gunCalcNames.trap, + STAT_CALCULATOR: "trap", AUTOFIRE: true, }, }, ], -} -Class.terrestrialTrapTurret = { - PARENT: "genericTank", - LABEL: "Turret", - INDEPENDENT: true, - COLOR: "grey", +}, {independent: true, hasAI: false, extraStats: []}) +Class.terrestrialTrapTurret = makeTurret({ GUNS: [ { POSITION: [13, 14, 1, 0, 0, 0, 0], }, { POSITION: [4, 14, 1.8, 13, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.lowPower, g.pounder, g.destroyer, { reload: 0.5 }, g.hexaTrapper]), + SHOOT_SETTINGS: combineStats([g.trap, g.pounder, g.hexaTrapper, {reload: 1.3, size: 1.2, health: 1.35, damage: 1.4, speed: 0.9, shudder: 0.1}]), TYPE: "trap", - STAT_CALCULATOR: gunCalcNames.trap, + STAT_CALCULATOR: "trap", AUTOFIRE: true, }, }, ], -} -let makeshottrapTurretProps = () => ({ - SHOOT_SETTINGS: combineStats([g.trap, g.setTrap, g.shotgun, g.machineGun, { speed: 0.7, maxSpeed: 0.2, damage: 1.5 }]), +}, {independent: true, hasAI: false, extraStats: []}) +const shottrapTurretProperties = { + SHOOT_SETTINGS: combineStats([g.trap, g.setTrap, g.shotgun, g.machineGun, { reload: 0.65, speed: 0.7, maxSpeed: 0.1, damage: 0.7, range: 0.5 }]), AUTOFIRE: true, TYPE: "shotTrapBox", - STAT_CALCULATOR: gunCalcNames.block, -}); -Class.shottrapTurret = { - PARENT: "genericTank", - LABEL: 'Turret', - BODY: { - FOV: 0, - }, - INDEPENDENT: true, - CONTROLLERS: ['nearestDifferentMaster', 'onlyAcceptInArc'], - COLOR: "grey", - AI: { - SKYNET: true, - FULL_VIEW: true, - }, - GUNS: [ { - POSITION: [ 4, 1.5, 1, 11, -3, 0, 0 ], PROPERTIES: makeshottrapTurretProps(), + STAT_CALCULATOR: "block", +} +Class.shottrapTurret = makeTurret({ + GUNS: [{ + POSITION: [ 4, 1.5, 1, 11, -3, 0, 0 ], PROPERTIES: shottrapTurretProperties, }, { - POSITION: [ 4, 2, 1, 11, 3, 0, 0 ], PROPERTIES: makeshottrapTurretProps(), + POSITION: [ 4, 2, 1, 11, 3, 0, 0 ], PROPERTIES: shottrapTurretProperties, }, { - POSITION: [ 4, 1.5, 1, 13, 0, 0, 0 ], PROPERTIES: makeshottrapTurretProps(), + POSITION: [ 4, 1.5, 1, 13, 0, 0, 0 ], PROPERTIES: shottrapTurretProperties, }, { - POSITION: [ 1, 2, 1, 11, 1, 0, 0 ], PROPERTIES: makeshottrapTurretProps(), + POSITION: [ 1, 2, 1, 11, 1, 0, 0 ], PROPERTIES: shottrapTurretProperties, }, { - POSITION: [ 1, 2, 1, 12, -1, 0, 0 ], PROPERTIES: makeshottrapTurretProps(), + POSITION: [ 1, 2, 1, 12, -1, 0, 0 ], PROPERTIES: shottrapTurretProperties, }, { - POSITION: [ 1, 1.5, 1, 11, 1, 0, 0 ], PROPERTIES: makeshottrapTurretProps(), + POSITION: [ 1, 1.5, 1, 11, 1, 0, 0 ], PROPERTIES: shottrapTurretProperties, }, { - POSITION: [ 1, 2, 1, 13, -1, 0, 0 ], PROPERTIES: makeshottrapTurretProps(), + POSITION: [ 1, 2, 1, 13, -1, 0, 0 ], PROPERTIES: shottrapTurretProperties, }, { - POSITION: [ 1, 2,5, 1, 13, 1, 0, 0 ], PROPERTIES: makeshottrapTurretProps(), + POSITION: [ 1, 2.5, 1, 13, 1, 0, 0 ], PROPERTIES: shottrapTurretProperties, }, { - POSITION: [ 1, 2, 1, 13, 2, 0, 0 ], PROPERTIES: makeshottrapTurretProps(), + POSITION: [ 1, 2, 1, 13, 2, 0, 0 ], PROPERTIES: shottrapTurretProperties, }, { - POSITION: [ 1, 2, 1, 13, -2, 0, 0 ], PROPERTIES: makeshottrapTurretProps(), + POSITION: [ 1, 2, 1, 13, -2, 0, 0 ], PROPERTIES: shottrapTurretProperties, }, { - POSITION: [ 1, 2.5, 1, 13, -2, 0, 0 ], PROPERTIES: makeshottrapTurretProps(), + POSITION: [ 1, 2.5, 1, 13, -2, 0, 0 ], PROPERTIES: shottrapTurretProperties, }, { - POSITION: [ 1, 2.5, 1, 13, 2, 0, 0 ], PROPERTIES: makeshottrapTurretProps(), + POSITION: [ 1, 2.5, 1, 13, 2, 0, 0 ], PROPERTIES: shottrapTurretProperties, }, { - POSITION: [ 1, 2, 1, 13, -2, 0, 0 ], PROPERTIES: makeshottrapTurretProps(), + POSITION: [ 1, 2, 1, 13, -2, 0, 0 ], PROPERTIES: shottrapTurretProperties, }, { - POSITION: [ 16, 14, -1.4, 0, 0, 0, 0 ], + POSITION: [ 16, 14, -1.4, 0, 0, 0, 0 ], }, { - POSITION: [ 6, 14, 1.6, 16, 0, 0, 0 ], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.setTrap, g.shotgun, g.machineGun, g.fake]), - AUTOFIRE: true, - TYPE: "bullet" - } - } ] -} + POSITION: [ 6, 14, 1.6, 16, 0, 0, 0 ], PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.trap, g.setTrap, g.shotgun, g.machineGun, {reload: 0.65}, g.fake]), + AUTOFIRE: true, + TYPE: "bullet" + } + }] +}, {limitFov: true, aiSettings: {SKYNET: true, FULL_VIEW: true, independent: true, extraStats: []}}) Class.machineTripleTurret = { PARENT: "genericTank", - LABEL: "Machine Gun", - BODY: { FOV: 2 }, - CONTROLLERS: [ ["spin", {speed: 0.04}] ], + FACING_TYPE: ["spin", {speed: 0.06}], INDEPENDENT: true, COLOR: -1, - GUNS: [ - { - POSITION: [12, 10, 1.4, 8, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.flankGuard]), - TYPE: "bullet", - AUTOFIRE: true, - }, - }, { - POSITION: [12, 10, 1.4, 8, 0, 120, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.flankGuard]), - TYPE: "bullet", - AUTOFIRE: true, - }, - }, { - POSITION: [12, 10, 1.4, 8, 0, 240, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.flankGuard]), - TYPE: "bullet", - AUTOFIRE: true, - }, - }, - ], -}; -Class.launcherTurret = { - PARENT: "genericTank", - LABEL: "Launcher", - BODY: { FOV: 2 }, - CONTROLLERS: [ "canRepel", "onlyAcceptInArc", "mapAltToFire", "nearestDifferentMaster" ], - COLOR: "grey", - GUNS: [ - { - /*** LENGTH WIDTH ASPECT X Y ANGLE DELAY */ - POSITION: [10, 9, 1, 9, 0, 0, 0], - }, { - POSITION: [17, 13, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.artillery, g.artillery]), - TYPE: "minimissile", - STAT_CALCULATOR: gunCalcNames.sustained, - }, - }, - ], -}; -Class.skimmerTurret = { - PARENT: "genericTank", - LABEL: "Skimmer", - BODY: { FOV: 2 * base.FOV }, - COLOR: -1, - CONTROLLERS: [ "canRepel", "onlyAcceptInArc", "mapAltToFire", "nearestDifferentMaster" ], - GUNS: [ - { - POSITION: [10, 14, -0.5, 9, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.artillery, g.artillery, g.skimmer]), - TYPE: "hypermissile", - STAT_CALCULATOR: gunCalcNames.sustained, - }, - }, { - POSITION: [17, 15, 1, 0, 0, 0, 0], + GUNS: weaponArray({ + POSITION: [12, 10, 1.4, 8, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.machineGun, g.flankGuard]), + TYPE: "bullet", + AUTOFIRE: true, }, - ], -}; -Class.kronosSkimmerTurret = { - PARENT: "genericTank", - LABEL: "Skimmer", - BODY: { FOV: 10 }, - COLOR: "grey", - INDEPENDENT: true, - CONTROLLERS: [ "canRepel", "onlyAcceptInArc", "mapAltToFire", "nearestDifferentMaster" ], + }, 3) +} +Class.launcherTurret = makeTurret('launcher', {canRepel: true, limitFov: true, extraStats: []}) +Class.skimmerTurret = makeTurret('skimmer', {canRepel: true, limitFov: true, extraStats: [], color: 'mirror'}) +Class.kronosSkimmerTurret = makeTurret({ GUNS: [ { POSITION: [8, 20, -0.25, 11, 0, 0, 0], }, { POSITION: [15, 18, -0.8, 0, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.artillery, g.artillery, g.skimmer, { reload: 2 }]), + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.artillery, g.artillery, g.skimmer, { reload: 2, health: 1.7, damage: 1.4, resist: 1.2 }]), TYPE: "kronosMissile", }, }, ], -} -Class.autosmashTurret = { - PARENT: "genericTank", - LABEL: "Launcher", - BODY: { FOV: 10 }, - COLOR: "grey", - CONTROLLERS: [ "canRepel", "onlyAcceptInArc", "mapAltToFire", "nearestDifferentMaster" ], - INDEPENDENT: true, +}, {canRepel: true, limitFov: true, fov: 10, independent: true, extraStats: []}) +Class.autoSmasherLauncherTurret = makeTurret({ GUNS: [ { POSITION: [4, 12, 1.2, 16, 0, 0, 0], }, { POSITION: [18, 20, -0.7, 0, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.artillery, g.artillery, g.skimmer, { reload: 2 }, { speed: 1.3, maxSpeed: 1.3 }, { speed: 1.3, maxSpeed: 1.3 }, {range: 2.5}]), + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.artillery, g.artillery, g.skimmer, { reload: 2, health: 1.9, damage: 1.2, resist: 1.2, speed: 1.3, maxSpeed: 1.3, range: 2.5 }]), TYPE: "autoSmasherMissile", }, }, ], -} -Class.twisterTurret = { - PARENT: "genericTank", - LABEL: "Twister", - BODY: { FOV: 2 }, - COLOR: -1, - CONTROLLERS: [ "canRepel", "onlyAcceptInArc", "mapAltToFire", "nearestDifferentMaster" ], - GUNS: [ - { - POSITION: [10, 13, -0.5, 9, 0, 0, 0], - }, { - POSITION: [17, 14, -1.4, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.artillery, g.artillery, g.skimmer, { speed: 1.3, maxSpeed: 1.3 }, { reload: 4/3 }]), - TYPE: "spinmissile", - STAT_CALCULATOR: gunCalcNames.sustained, - }, - }, - ], -}; -Class.hyperTwisterTurret = { - PARENT: "genericTank", - LABEL: "Twister", - BODY: { FOV: 2 }, - COLOR: -1, - CONTROLLERS: [ "canRepel", "onlyAcceptInArc", "mapAltToFire", "nearestDifferentMaster" ], +}, {canRepel: true, limitFov: true, fov: 10, independent: true, extraStats: []}) +Class.twisterTurret = makeTurret('twister', {canRepel: true, limitFov: true, color: 'mirror', extraStats: [{speed: 1.3, maxSpeed: 1.3}]}) +Class.hyperTwisterTurret = makeTurret({ GUNS: [ { POSITION: [10, 13, -0.5, 9, 0, 0, 0], @@ -381,583 +236,294 @@ Class.hyperTwisterTurret = { PROPERTIES: { SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.artillery, g.artillery, g.skimmer, { speed: 1.3, maxSpeed: 1.3 }, { reload: 4/3 }]), TYPE: "hyperspinmissile", - STAT_CALCULATOR: gunCalcNames.sustained, - }, - }, - ], -}; -Class.rocketeerTurret = { - PARENT: "genericTank", - LABEL: "Rocketeer", - BODY: { FOV: 2 }, - CONTROLLERS: [ "canRepel", "onlyAcceptInArc", "mapAltToFire", "nearestDifferentMaster" ], - COLOR: "grey", - GUNS: [ - { - POSITION: [10, 12.5, -0.7, 10, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.launcher, g.rocketeer]), - TYPE: "rocketeerMissile", - STAT_CALCULATOR: gunCalcNames.sustained, - }, - }, { - POSITION: [17, 18, 0.65, 0, 0, 0, 0], - }, - ], -}; -Class.boomerTurret = { - PARENT: "genericTank", - LABEL: "Boomer", - BODY: { FOV: 2 }, - CONTROLLERS: [ "canRepel", "onlyAcceptInArc", "mapAltToFire", "nearestDifferentMaster" ], - COLOR: -1, - GUNS: [ - { - POSITION: [7.75, 10, 1, 12, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.setTrap, g.boomerang, g.fake]), - TYPE: "bullet", - }, - }, { - POSITION: [6, 10, -1.5, 7, 0, 0, 0], - }, { - POSITION: [2, 10, 1.3, 18, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.setTrap, g.boomerang]), - TYPE: "boomerang", + STAT_CALCULATOR: "sustained", }, }, ], -}; +}, {canRepel: true, limitFov: true, color: 'mirror', extraStats: []}) +Class.rocketeerTurret = makeTurret('rocketeer', {canRepel: true, limitFov: true}) +Class.boomerTurret = makeTurret('boomer', {canRepel: true, limitFov: true, color: 'mirror', extraStats: []}) Class.triTrapGuardTurret = { PARENT: "genericTank", COLOR: -1, - CONTROLLERS: [["spin", { independent: true }]], - GUNS: [], -}; -for(let i = 0; i < 3; i++) { - Class.triTrapGuardTurret.GUNS.push( + FACING_TYPE: ["spin", { independent: true }], + GUNS: weaponArray([ { - POSITION: [17, 8, 1, 0, 0, 120*i, 0], + POSITION: [17, 8, 1, 0, 0, 0, 0], PROPERTIES: { SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.flankGuard]), TYPE: "bullet", }, }, { - POSITION: [13, 8, 1, 0, 0, 120*i+60, 0], + POSITION: [13, 8, 1, 0, 0, 60, 0], }, { - POSITION: [4, 8, 1.7, 13, 0, 120*i+60, 0], + POSITION: [4, 8, 1.7, 13, 0, 60, 0], PROPERTIES: { SHOOT_SETTINGS: combineStats([g.trap]), TYPE: "trap", - STAT_CALCULATOR: gunCalcNames.trap, + STAT_CALCULATOR: "trap", }, }, - ) -}; + ], 3), +} Class.eliteSpinnerCyclone = { PARENT: "genericTank", COLOR: -1, - CONTROLLERS: [["spin", { speed: 0.1, independent: true }]], - GUNS: [], -}; -for (let i = 0; i < 12; i++) { - let delay; - switch (i % 4) { - case 0: - delay = 0; - break; - case 1: - delay = 0.5; - break; - case 2: - delay = 0.25; - break; - case 3: - delay = 0.75; - break; - } - Class.eliteSpinnerCyclone.GUNS.push( - { - POSITION: [15, 3.5, 1, 0, 0, 30 * i, delay], + FACING_TYPE: ["spin", { speed: -0.1, independent: true }], + GUNS: weaponArray([ + { + POSITION: [15, 3.5, 1, 0, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.gunner, { speed: 1.3, maxSpeed: 1.3 }]), - TYPE: "bullet", - }, + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.gunner, g.cyclone]), + TYPE: "bullet" + } }, - ) -}; -Class.barricadeTurret = { - PARENT: "genericTank", - LABEL: "Turret", - BODY: { - FOV: 0.5, - }, - INDEPENDENT: true, - CONTROLLERS: ["nearestDifferentMaster"], - COLOR: "grey", - AI: { - SKYNET: true, - FULL_VIEW: true, - }, - GUNS: [ { - POSITION: [24, 8, 1, 0, 0, 0, 0], + POSITION: [15, 3.5, 1, 0, 0, 30, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.gunner, g.cyclone]), + TYPE: "bullet" + } }, { - POSITION: [4, 8, 1.3, 22, 0, 0, 0], + POSITION: [15, 3.5, 1, 0, 0, 60, 0.25], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.minigun, { range: 0.5 }]), - TYPE: "trap", - STAT_CALCULATOR: gunCalcNames.trap, - }, + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.gunner, g.cyclone]), + TYPE: "bullet" + } }, { - POSITION: [4, 8, 1.3, 18, 0, 0, 0.333], + POSITION: [15, 3.5, 1, 0, 0, 90, 0.75], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.minigun, { range: 0.5 }]), - TYPE: "trap", - STAT_CALCULATOR: gunCalcNames.trap, - }, + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.gunner, g.cyclone]), + TYPE: "bullet" + } + } + ], 3) +} +Class.barricadeTurret = makeTurret('barricade', {aiSettings: {SKYNET: true, FULL_VIEW: true, independent: true, extraStats: []}}) +Class.artilleryTurret = makeTurret('artillery', {canRepel: true, limitFov: true, extraStats: []}) +Class.nailgunTurret = makeTurret('nailgun', {canRepel: true, limitFov: true, extraStats: []}) +Class.crowbarTurret = makeTurret({ + GUNS: [ + { + POSITION: [37, 6.5, 1, 0, 0, 0, 0], + }, { + POSITION: [5, 8.5, -1.5, 8, 0, 0, 0], }, + ], + TURRETS: [ { - POSITION: [4, 8, 1.3, 14, 0, 0, 0.667], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.trap, g.minigun, { range: 0.5 }]), - TYPE: "trap", - STAT_CALCULATOR: gunCalcNames.trap, - }, + POSITION: [6, 38, 0, 0, 360, 1], + TYPE: [ "autoTankGun", { GUN_STAT_SCALE: g.flankGuard, INDEPENDENT: true, HAS_NO_RECOIL: true } ], + }, { + POSITION: [6, 28, 0, 0, 360, 1], + TYPE: [ "autoTankGun", { GUN_STAT_SCALE: g.flankGuard, INDEPENDENT: true, HAS_NO_RECOIL: true } ], + }, { + POSITION: [6, 18, 0, 0, 360, 1], + TYPE: [ "autoTankGun", { GUN_STAT_SCALE: g.flankGuard, INDEPENDENT: true, HAS_NO_RECOIL: true } ], }, ], -}; -Class.artilleryAutoTankgun = { - PARENT: "genericTank", - LABEL: "Artillery", - BODY: { - FOV: 2, - }, - CONTROLLERS: [ - "canRepel", - "onlyAcceptInArc", - "mapAltToFire", - "nearestDifferentMaster", +}, {canRepel: true, limitFov: true, extraStats: []}) +Class.wrenchTurret = makeTurret({ + GUNS: [ + { + POSITION: [67, 6.5, 1, 0, 0, 0, 0], + }, { + POSITION: [5, 8.5, -1.5, 8, 0, 0, 0], + }, ], - COLOR: "grey", - GUNS: [{ - POSITION: [17, 3, 1, 0, -6, -7, 0.25], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery, { reload: 0.5 }]), - TYPE: "bullet", - LABEL: "Secondary", + TURRETS: [ + { + POSITION: [6, 68, 0, 0, 360, 1], + TYPE: [ "autoTankGun", { GUN_STAT_SCALE: g.flankGuard, INDEPENDENT: true, HAS_NO_RECOIL: true } ], + }, { + POSITION: [6, 58, 0, 0, 360, 1], + TYPE: [ "autoTankGun", { GUN_STAT_SCALE: g.flankGuard, INDEPENDENT: true, HAS_NO_RECOIL: true } ], + }, { + POSITION: [6, 48, 0, 0, 360, 1], + TYPE: [ "autoTankGun", { GUN_STAT_SCALE: g.flankGuard, INDEPENDENT: true, HAS_NO_RECOIL: true } ], }, - }, + ], +}, {canRepel: true, limitFov: true, extraStats: []}) +Class.protoSwarmerTurret = makeTurret({ + GUNS: [ { - POSITION: [17, 3, 1, 0, 6, 7, 0.75], + POSITION: [10, 14, -1.2, 5, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery, { reload: 0.5 }]), - TYPE: "bullet", - LABEL: "Secondary", + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.destroyer, g.hive, {speed: 1.3, maxSpeed: 0.5, health: 1.3, range: 1.3}]), + TYPE: "protoHive", }, + }, { + POSITION: [11, 12, 1, 5, 0, 0, 0], }, + ], +}, {canRepel: true, limitFov: true, extraStats: []}) +Class.swarmTurret = makeTurret({ + GUNS: [ { - POSITION: [19, 12, 1, 0, 0, 0, 0], + POSITION: [7, 7.5, 0.6, 7, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.artillery, { reload: 0.5 }]), - TYPE: "bullet", - LABEL: "Heavy", + SHOOT_SETTINGS: combineStats([g.swarm]), + TYPE: 'autoswarm', + STAT_CALCULATOR: "swarm", }, }, ], -} -Class.artilleryTurret = { // This one has half the dps of the one above - PARENT: "genericTank", - LABEL: "Artillery", - BODY: { FOV: 2 }, - CONTROLLERS: [ "canRepel", "onlyAcceptInArc", "mapAltToFire", "nearestDifferentMaster" ], - COLOR: "grey", +}, {canRepel: true, limitFov: true, extraStats: []}) +Class.crasherSpawner = makeTurret({ + MAX_CHILDREN: 4, GUNS: [ { - POSITION: [17, 3, 1, 0, -6, -7, 0.25], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery]), - TYPE: "bullet", - LABEL: "Secondary", - }, - }, { - POSITION: [17, 3, 1, 0, 6, 7, 0.75], + POSITION: [6, 12, 1.2, 8, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.artillery]), - TYPE: "bullet", - LABEL: "Secondary", + SHOOT_SETTINGS: combineStats([g.drone, g.weak, g.weak, {health: 1.1}]), + TYPE: [ + "drone", + { + LABEL: "Crasher", + DRAW_HEALTH: true, + }, + ], + SYNCS_SKILLS: true, + AUTOFIRE: true, + STAT_CALCULATOR: "drone", }, + }, + ], +}, {independent: true, aiSettings: {chase: true}, label: 'Spawned', color: 'pink'}) +Class.genghisLowerTurret = makeTurret({ + MAX_CHILDREN: 4, + GUNS: [ + { + POSITION: [7, 11, 0.6, 6, 0, 0, 0.5], }, { - POSITION: [19, 12, 1, 0, 0, 0, 0], + POSITION: [2, 12, 1, 13, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.artillery]), - TYPE: "bullet", - LABEL: "Heavy", + SHOOT_SETTINGS: combineStats([g.swarm, g.babyfactory, { reload: 1.5, health: 2, damage: 2, range: 2 }]), + TYPE: ["tinyMinion", {INDEPENDENT: true}], + AUTOFIRE: true, + SYNCS_SKILLS: true, }, }, ], -}; -Class.legionaryTwin = { - PARENT: "auto4gun", - COLOR: "grey", - INDEPENDENT: true, - GUNS: [ - { - POSITION: [17.5, 5, 1, 0, -4.5, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.autoTurret, g.pelleter, g.twin, g.power, { speed: 0.7, maxSpeed: 0.7 }]), - TYPE: "bullet", - }, - }, { - POSITION: [17.5, 5, 1, 0, 4.5, 0, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.autoTurret, g.pelleter, g.twin, g.power, { speed: 0.7, maxSpeed: 0.7 }]), - TYPE: "bullet", - }, - }, - ], -} -Class.nailgunTurret = { - PARENT: "genericTank", - LABEL: "Nailgun", - BODY: { FOV: 2 }, - CONTROLLERS: [ "canRepel", "onlyAcceptInArc", "mapAltToFire", "nearestDifferentMaster" ], - COLOR: "grey", - GUNS: [{ - /*** LENGTH WIDTH ASPECT X Y ANGLE DELAY */ - POSITION: [19, 2, 1, 0, -2.5, 0, 0.25], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.power, g.twin, g.nailgun]), - TYPE: "bullet", - }, - }, { - POSITION: [19, 2, 1, 0, 2.5, 0, 0.75], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.power, g.twin, g.nailgun]), - TYPE: "bullet", - }, - }, { - POSITION: [20, 2, 1, 0, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.power, g.twin, g.nailgun]), - TYPE: "bullet", - }, - }, { - POSITION: [5.5, 7, -1.8, 6.5, 0, 0, 0], - }, - ], -}; -Class.crowbarTurret = { - PARENT: "genericTank", - COLOR: "grey", - LABEL: "Crowbar", - BODY: { FOV: 2 }, - CONTROLLERS: [ "canRepel", "onlyAcceptInArc", "mapAltToFire", "nearestDifferentMaster" ], - GUNS: [ - { - /*** LENGTH WIDTH ASPECT X Y ANGLE DELAY */ - POSITION: [37, 6.5, 1, 0, 0, 0, 0], - }, { - POSITION: [5, 8.5, -1.5, 8, 0, 0, 0], - }, - ], - TURRETS: [ - { - /* SIZE X Y ANGLE ARC */ - POSITION: [6, 38, 0, 0, 360, 1], - TYPE: [ "autoTankGun", { INDEPENDENT: true, HAS_NO_RECOIL: true } ], - }, { - POSITION: [6, 28, 0, 0, 360, 1], - TYPE: [ "autoTankGun", { INDEPENDENT: true, HAS_NO_RECOIL: true } ], - }, { - POSITION: [6, 18, 0, 0, 360, 1], - TYPE: [ "autoTankGun", { INDEPENDENT: true, HAS_NO_RECOIL: true } ], - }, - ], -}; -Class.wrenchTurret = { - PARENT: "genericTank", - COLOR: "grey", - LABEL: "Wrench", - BODY: { FOV: 2 }, - CONTROLLERS: [ "canRepel", "onlyAcceptInArc", "mapAltToFire", "nearestDifferentMaster" ], - GUNS: [{ - /*** LENGTH WIDTH ASPECT X Y ANGLE DELAY */ - POSITION: [67, 6.5, 1, 0, 0, 0, 0], - }, { - POSITION: [5, 8.5, -1.5, 8, 0, 0, 0], - }, - ], - TURRETS: [ - { - /* SIZE X Y ANGLE ARC */ - POSITION: [6, 68, 0, 0, 360, 1], - TYPE: [ "autoTankGun", { INDEPENDENT: true, HAS_NO_RECOIL: true } ], - }, { - POSITION: [6, 58, 0, 0, 360, 1], - TYPE: [ "autoTankGun", { INDEPENDENT: true, HAS_NO_RECOIL: true } ], - }, { - POSITION: [6, 48, 0, 0, 360, 1], - TYPE: [ "autoTankGun", { INDEPENDENT: true, HAS_NO_RECOIL: true } ], - }, - ], -}; -Class.protoSwarmerTurret = { - PARENT: "genericTank", - LABEL: "Swarmer", - BODY: { FOV: 2 }, - CONTROLLERS: [ "canRepel", "onlyAcceptInArc", "mapAltToFire", "nearestDifferentMaster" ], - COLOR: "grey", - GUNS: [ - { - POSITION: [10, 14, -1.2, 5, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.destroyer, g.hive]), - TYPE: "protoHive", - }, - }, { - POSITION: [11, 12, 1, 5, 0, 0, 0], - }, - ], -} -Class.swarmTurret = { - PARENT: "genericTank", - LABEL: "Swarm", - BODY: { FOV: 2 }, - CONTROLLERS: [ "canRepel", "onlyAcceptInArc", "mapAltToFire", "nearestDifferentMaster" ], - COLOR: "grey", - GUNS: [ - { - POSITION: [7, 7.5, 0.6, 7, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm]), - TYPE: ["swarm", {INDEPENDENT: true}], - STAT_CALCULATOR: gunCalcNames.swarm, - }, - }, - ], -}; -Class.napoleonLowerTurret = { - PARENT: "genericTank", - LABEL: "", - BODY: { FOV: 2 }, - CONTROLLERS: [ "canRepel", "onlyAcceptInArc", "mapAltToFire", "nearestDifferentMaster" ], - COLOR: "grey", +}, {canRepel: true, limitFov: true, extraStats: []}) +Class.cruiserTurret = makeTurret('cruiser', {canRepel: true, limitFov: true}) +Class.carrierTurret = makeTurret('carrier', {canRepel: true, limitFov: true}) +Class.napoleonLowerTurret = makeTurret({ GUNS: [ { POSITION: [8, 8, 0.6, 6, 0, 30, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm, g.bee, g.pounder, { speed: 1.3, maxSpeed: 1.3 }]), + SHOOT_SETTINGS: combineStats([g.swarm, g.bee, g.pounder]), TYPE: ["bee", { INDEPENDENT: true }], - STAT_CALCULATOR: gunCalcNames.swarm, + STAT_CALCULATOR: "swarm", }, }, { POSITION: [8, 8, 0.6, 6, 0, -30, 0.5], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm, g.bee, g.pounder, { speed: 1.3, maxSpeed: 1.3 }]), + SHOOT_SETTINGS: combineStats([g.swarm, g.bee, g.pounder]), TYPE: ["bee", { INDEPENDENT: true }], - STAT_CALCULATOR: gunCalcNames.swarm, - }, - }, - ], -}; -Class.genghisLowerTurret = { - PARENT: "genericTank", - LABEL: "", - MAX_CHILDREN: 4, - BODY: { FOV: 2 }, - CONTROLLERS: [ "canRepel", "onlyAcceptInArc", "mapAltToFire", "nearestDifferentMaster" ], - COLOR: "grey", - GUNS: [ - { - POSITION: [7, 11, 0.6, 6, 0, 0, 0.5], - }, { - POSITION: [2, 12, 1, 13, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm, g.babyfactory, { reload: 1.5 }]), - TYPE: ["tinyMinion", {INDEPENDENT: true}], - AUTOFIRE: true, - SYNCS_SKILLS: true, - }, - }, - ], -}; - -Class.cruiserTurret = { - PARENT: "genericTank", - LABEL: "Cruiser", - BODY: { FOV: 2 }, - CONTROLLERS: [ "canRepel", "onlyAcceptInArc", "mapAltToFire", "nearestDifferentMaster" ], - COLOR: "grey", - GUNS: [ - { - POSITION: [7, 7.5, 0.6, 7, 4, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm]), - TYPE: "swarm", - STAT_CALCULATOR: gunCalcNames.swarm, - }, - }, { - POSITION: [7, 7.5, 0.6, 7, -4, 0, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm]), - TYPE: "swarm", - STAT_CALCULATOR: gunCalcNames.swarm, + STAT_CALCULATOR: "swarm", }, }, ], -}; -Class.carrierTurret = { - PARENT: "genericTank", - LABEL: "Carrier", - BODY: { FOV: 2 }, - CONTROLLERS: [ "canRepel", "onlyAcceptInArc", "mapAltToFire", "nearestDifferentMaster" ], - INDEPENDENT: true, - COLOR: "grey", - GUNS: [ - { - POSITION: [7, 8, 0.6, 7, 0, 0, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm, g.battleship, g.carrier, g.pounder, { speed: 1.3, maxSpeed: 1.3 }]), - TYPE: "swarm", - STAT_CALCULATOR: gunCalcNames.swarm, - }, - }, { - POSITION: [7, 8, 0.6, 7, 2, 30, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm, g.battleship, g.carrier, g.pounder, { speed: 1.3, maxSpeed: 1.3 }]), - TYPE: "swarm", - STAT_CALCULATOR: gunCalcNames.swarm, - }, - }, { - POSITION: [7, 8, 0.6, 7, -2, -30, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm, g.battleship, g.carrier, g.pounder, { speed: 1.3, maxSpeed: 1.3 }]), - TYPE: "swarm", - STAT_CALCULATOR: gunCalcNames.swarm, - }, - }, - ], -} -Class.gunnerCruiserTurret = { - PARENT: "genericTank", - LABEL: "Launcher", - BODY: { FOV: 10 }, - COLOR: "grey", - CONTROLLERS: [ "canRepel", "onlyAcceptInArc", "mapAltToFire", "nearestDifferentMaster" ], - INDEPENDENT: true, +}, {canRepel: true, limitFov: true, extraStats: []}) +Class.gunnerCruiserTurret = makeTurret({ GUNS: [ { POSITION: [4, 7.5, 0.6, 6, 4.5, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm]), + SHOOT_SETTINGS: combineStats([g.swarm, g.battleship, {maxSpeed: 1.1}]), TYPE: "swarm", - STAT_CALCULATOR: gunCalcNames.swarm, + STAT_CALCULATOR: "swarm", }, }, { POSITION: [4, 7.5, 0.6, 6, -4.5, 0, 0.5], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm]), + SHOOT_SETTINGS: combineStats([g.swarm, g.battleship, {maxSpeed: 1.1}]), TYPE: "swarm", - STAT_CALCULATOR: gunCalcNames.swarm, + STAT_CALCULATOR: "swarm", }, }, { POSITION: [16, 3, 1, 0, -3, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.power, g.twin]), + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.power, g.twin, {health: 1.2, damage: 1.2, speed: 1.2, maxSpeed: 0.9}]), TYPE: "bullet", }, }, { POSITION: [16, 3, 1, 0, 3, 0, 0.5], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.power, g.twin]), + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.power, g.twin, {health: 1.2, damage: 1.2, speed: 1.2, maxSpeed: 0.9}]), TYPE: "bullet", }, }, ], -} -Class.juliusLowerTurret = { - PARENT: "genericTank", - LABEL: "", +}, {canRepel: true, limitFov: true, independent: true, fov: 10, extraStats: []}) +Class.juliusLowerTurret = makeTurret({ MAX_CHILDREN: 3, - BODY: { FOV: 2 }, - CONTROLLERS: [ "canRepel", "onlyAcceptInArc", "mapAltToFire", "nearestDifferentMaster" ], - COLOR: "grey", GUNS: [ { POSITION: [8.5, 11, 0.6, 6, 0, 0, 0.5], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.swarm, g.sunchip]), + SHOOT_SETTINGS: combineStats([g.drone, g.sunchip, {size: 0.8, health: 1.5, damage: 1.5, density: 1.2, maxSpeed: 0.8}]), TYPE: "minichip", - STAT_CALCULATOR: gunCalcNames.swarm, + STAT_CALCULATOR: "drone", }, }, ], -}; -Class.swarmerTurret = { - PARENT: "genericTank", - LABEL: "Swarmer", - BODY: { FOV: 2 }, - CONTROLLERS: [ "canRepel", "onlyAcceptInArc", "mapAltToFire", "nearestDifferentMaster" ], - COLOR: "grey", +}, {canRepel: true, limitFov: true, extraStats: []}) +Class.swarmerTurret = makeTurret('swarmer', {canRepel: true, limitFov: true, extraStats: []}) +Class.basicTurret = makeTurret({ GUNS: [ { - POSITION: [14, 14, -1.2, 5, 0, 0, 0], + POSITION: [16, 4, 1, 0, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, g.destroyer, g.hive]), - TYPE: "hive", + SHOOT_SETTINGS: combineStats([g.basic, g.autoTurret, g.pelleter, g.twin, g.power, { speed: 0.7, maxSpeed: 0.7 }]), + TYPE: "bullet", }, - }, { - POSITION: [15, 12, 1, 5, 0, 0, 0], }, ], -}; -Class.basicTurret = { - PARENT: "genericTank", - LABEL: "Turret", - BODY: { FOV: 2 }, - CONTROLLERS: [ "canRepel", "onlyAcceptInArc", "mapAltToFire", "nearestDifferentMaster" ], - COLOR: "grey", +}, {canRepel: true, limitFov: true, extraStats: []}) +Class.tripletTurret = makeTurret({ GUNS: [ { - POSITION: [16, 4, 1, 0, 0, 0, 0], + POSITION: [18, 10, 1, 0, 5, 0, 0.5], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.autoTurret, g.pelleter, g.twin, g.power, { speed: 0.7, maxSpeed: 0.7 }]), + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.triplet]), + TYPE: "bullet", + }, + }, { + POSITION: [18, 10, 1, 0, -5, 0, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.triplet]), + TYPE: "bullet", + }, + }, { + POSITION: [21, 10, 1.2, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.triplet]), TYPE: "bullet", }, }, ], -}; -Class.napoleonUpperTurret = { - PARENT: "genericTank", - LABEL: "", - BODY: { FOV: 2 }, - CONTROLLERS: [ "canRepel", "onlyAcceptInArc", "mapAltToFire", "nearestDifferentMaster" ], - COLOR: "grey", +}, {canRepel: true, limitFov: true, extraStats: []}) +Class.napoleonUpperTurret = makeTurret({ GUNS: [ { POSITION: [12, 17, -0.6, 0, 0, 0, 0], }, { POSITION: [16, 12, 1, 0, 0, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.pounder, { speed: 0.93, maxSpeed: 0.93 }]), + SHOOT_SETTINGS: combineStats([g.basic, g.pounder, { reload: 1.2, health: 1.2, damage: 1.2, speed: 0.93, maxSpeed: 0.93, range: 1.5 }]), TYPE: ["turretedBullet", {COLOR: "veryLightGrey"}], }, }, ], -}; +}, {canRepel: true, limitFov: true, extraStats: []}) // Mounted Turrets -Class.autoTurret = { - PARENT: "genericTank", - LABEL: "Turret", - COLOR: "grey", - BODY: { - FOV: 0.8, - }, +Class.autoTurret = makeTurret({ GUNS: [ { POSITION: [22, 10, 1, 0, 0, 0, 0], @@ -967,16 +533,8 @@ Class.autoTurret = { }, }, ], -} -Class.droneAutoTurret = { - PARENT: "genericTank", - LABEL: "Turret", - COLOR: "grey", - INDEPENDENT: true, - CONTROLLERS: ['nearestDifferentMaster'], - BODY: { - FOV: 0.8, - }, +}, {label: "Turret", fov: 0.8, extraStats: []}) +Class.droneAutoTurret = makeTurret({ GUNS: [ { POSITION: [22, 10, 1, 0, 0, 0, 0], @@ -986,16 +544,26 @@ Class.droneAutoTurret = { }, }, ], -} -Class.autoSmasherTurret = { - PARENT: "autoTurret", +}, {label: "Turret", fov: 0.8, extraStats: []}) +Class.bulletAutoTurret = makeTurret({ + GUNS: [ + { + POSITION: [22, 10, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.power, g.turret, {speed: 0.8, maxSpeed: 0.8, reload: 1.2, health: 1.4}]), + TYPE: "bullet", + }, + }, + ] +}, {label: "Turret", fov: 0.8, extraStats: []}) +Class.autoSmasherTurret = makeTurret({ GUNS: [ { POSITION: [20, 6, 1, 0, 5, 0, 0], PROPERTIES: { SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.power, { recoil: 1.15 }, g.turret, { speed: 1.2 }, g.machineGun, g.pounder, { reload: 0.75 }, { reload: 0.75 }]), TYPE: "bullet", - STAT_CALCULATOR: gunCalcNames.fixedReload, + STAT_CALCULATOR: "fixedReload", }, }, { @@ -1003,17 +571,12 @@ Class.autoSmasherTurret = { PROPERTIES: { SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.power, { recoil: 1.15 }, g.turret, { speed: 1.2 }, g.machineGun, g.pounder, { reload: 0.75 }, { reload: 0.75 }]), TYPE: "bullet", - STAT_CALCULATOR: gunCalcNames.fixedReload, + STAT_CALCULATOR: "fixedReload", }, }, ], -} -Class.pillboxTurret = { - PARENT: "autoTurret", - LABEL: "", - BODY: { - FOV: 2, - }, +}, {label: "Turret", fov: 0.8, extraStats: []}) +Class.pillboxTurret = makeTurret({ HAS_NO_RECOIL: true, GUNS: [ { @@ -1021,39 +584,48 @@ Class.pillboxTurret = { PROPERTIES: { SHOOT_SETTINGS: combineStats([g.basic, g.minionGun, g.turret, g.power, g.autoTurret, { density: 0.1 }]), TYPE: "bullet", + WAIT_TO_CYCLE: true }, }, ], -} -Class.tripletTurret = { - PARENT: "genericTank", - LABEL: "Triplet", - BODY: { FOV: 2 }, - CONTROLLERS: [ "canRepel", "onlyAcceptInArc", "mapAltToFire", "nearestDifferentMaster" ], - INDEPENDENT: true, - COLOR: "grey", +}, {independent: true, extraStats: []}) +Class.autoSmasherMissileTurret = makeTurret({ + HAS_NO_RECOIL: true, GUNS: [ { - POSITION: [18, 10, 1, 0, 5, 0, 0.5], + POSITION: [19, 6, 1, 0, 4.5, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.triplet]), - TYPE: "bullet", - }, - }, { - POSITION: [18, 10, 1, 0, -5, 0, 0.5], + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.pelleter, g.power, g.turret]), + TYPE: "bullet" + } + }, + { + POSITION: [19, 6, 1, 0, -4.5, 0, 0.5], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.triplet]), - TYPE: "bullet", - }, - }, { - POSITION: [21, 10, 1.2, 0, 0, 0, 0], + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.pelleter, g.power, g.turret]), + TYPE: "bullet" + } + } + ], +}, {fov: 5, independent: true, aiSettings: {SKYNET: true, BLIND: true}, extraStats: []}) +Class.legionaryTwin = makeTurret({ + GUNS: [ + { + POSITION: [18, 7, 1, 0, 5, 0, 0], PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.triplet]), - TYPE: "bullet", - }, + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.pelleter, g.power, g.turret, {reload: 0.85}]), + TYPE: "bullet" + } }, + { + POSITION: [18, 7, 1, 0, -5, 0, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.twin, g.pelleter, g.power, g.turret, {reload: 0.85}]), + TYPE: "bullet" + } + } ], -} +}, {fov: 5, independent: true, extraStats: []}) // Healer turrets Class.sanctuaryHealer = { @@ -1063,84 +635,43 @@ Class.sanctuaryHealer = { BODY: { FOV: base.FOV * 1.2, }, - CONTROLLERS: [["spin", { independent: true, speed: -0.05 }]], + FACING_TYPE: ["spin", { speed: -0.05 }], TURRETS: [{ POSITION: { SIZE: 13, LAYER: 1 }, - TYPE: ['healerSymbol', { CONTROLLERS: [["spin", { startAngle: Math.PI / 2, speed: 0, independent: true }]] }] + TYPE: ['healerSymbol', { FACING_TYPE: ["noFacing", { angle: Math.PI / 2 }] }] }], -}; +} Class.surgeonPillboxTurret = { PARENT: "genericTank", LABEL: "", COLOR: "grey", - BODY: { - FOV: 3, - }, HAS_NO_RECOIL: true, - CONTROLLERS: [["spin", { independent: true, speed: 0.08 }]], + FACING_TYPE: ["spin", { speed: 0.08 }], TURRETS: [ { POSITION: [13, 0, 0, 0, 360, 1], TYPE: "healerSymbol", }, ], - GUNS: [ - { - POSITION: [17, 11, 1, 0, 0, 90, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.healer, g.minionGun, g.turret, g.power, g.autoTurret, { density: 0.1 }]), - TYPE: "healerBullet", - AUTOFIRE: true, - }, - }, - { - POSITION: [14, 11, 1, 0, 0, 90, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.healer, g.minionGun, g.turret, g.power, g.autoTurret, { density: 0.1 }]), - TYPE: "healerBullet", - AUTOFIRE: true, - }, - }, - { - POSITION: [17, 11, 1, 0, 0, 270, 0], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.healer, g.minionGun, g.turret, g.power, g.autoTurret, { density: 0.1 }]), - TYPE: "healerBullet", - AUTOFIRE: true, - }, - }, - { - POSITION: [14, 11, 1, 0, 0, 270, 0.5], - PROPERTIES: { - SHOOT_SETTINGS: combineStats([g.basic, g.healer, g.minionGun, g.turret, g.power, g.autoTurret, { density: 0.1 }]), - TYPE: "healerBullet", - AUTOFIRE: true, - }, + GUNS: weaponArray({ + POSITION: [17, 11, 1, 0, 0, 90, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.healer, g.minionGun, g.turret, g.power, g.autoTurret, { density: 0.1 }]), + TYPE: "healerBullet", + AUTOFIRE: true, }, - ], + }, 2, 0.5) } // Miscellaneous -Class.baseSwarmTurret = { - PARENT: "genericTank", - LABEL: "Protector", - COLOR: "grey", - BODY: { - FOV: 2, - }, - CONTROLLERS: ["nearestDifferentMaster"], - AI: { - NO_LEAD: true, - LIKES_SHAPES: true, - }, - INDEPENDENT: true, +Class.baseSwarmTurret = makeTurret({ GUNS: [ { POSITION: [5, 4.5, 0.6, 7, 2, 0, 0.15], PROPERTIES: { SHOOT_SETTINGS: combineStats([g.swarm, g.baseProtector]), TYPE: "swarm", - STAT_CALCULATOR: gunCalcNames.swarm, + STAT_CALCULATOR: "swarm", }, }, { @@ -1148,7 +679,7 @@ Class.baseSwarmTurret = { PROPERTIES: { SHOOT_SETTINGS: combineStats([g.swarm, g.baseProtector]), TYPE: "swarm", - STAT_CALCULATOR: gunCalcNames.swarm, + STAT_CALCULATOR: "swarm", }, }, { @@ -1156,11 +687,11 @@ Class.baseSwarmTurret = { PROPERTIES: { SHOOT_SETTINGS: combineStats([g.swarm, g.baseProtector]), TYPE: ["swarm", { INDEPENDENT: true, AI: { LIKES_SHAPES: true }}], - STAT_CALCULATOR: gunCalcNames.swarm, + STAT_CALCULATOR: "swarm", }, }, ], -} +}, {label: "Protector", independent: true, aiSettings: {NO_LEAD: true, LIKES_SHAPES: true}}) Class.antiTankMachineGunArm = { PARENT: "genericTank", COLOR: "grey", @@ -1194,20 +725,7 @@ Class.antiTankMachineGunArm = { }, ], } -Class.tracker3gun = { - PARENT: "genericTank", - LABEL: "", - COLOR: "timeGem", - BODY: { - FOV: 3 - }, - CONTROLLERS: [ - "canRepel", - "onlyAcceptInArc", - "mapAltToFire", - "nearestDifferentMaster" - ], - COLOR: "grey", +Class.tracker3gun = makeTurret({ GUNS: [ { POSITION: [22, 10, 1, 0, 0, 0, 0] @@ -1216,7 +734,7 @@ Class.tracker3gun = { POSITION: [10, 10, -2, 20, 0, 0, 0] } ] -} +}, {canRepel: true, limitFov: true, fov: 3}) // Decorations Class.overdriveDeco = makeDeco(4) @@ -1241,19 +759,19 @@ Class.healerSymbol = { SHAPE: [[0.3, -0.3],[1,-0.3],[1,0.3],[0.3,0.3],[0.3,1],[-0.3,1],[-0.3,0.3],[-1,0.3],[-1,-0.3],[-0.3,-0.3],[-0.3,-1],[0.3,-1]], SIZE: 13, COLOR: "red", -}; +} // Bodies Class.smasherBody = { LABEL: "", - CONTROLLERS: [["spin", { independent: true, speed: 0.1 }]], + FACING_TYPE: ["spin", { speed: 0.1 }], COLOR: "black", SHAPE: 6, INDEPENDENT: true } Class.landmineBody = { LABEL: "", - CONTROLLERS: [["spin", { independent: true, speed: 0.2 }]], + FACING_TYPE: ["spin", { speed: 0.1 }], COLOR: 9, SHAPE: 6, INDEPENDENT: true @@ -1264,8 +782,492 @@ Class.spikeBody = { } Class.dominationBody = { LABEL: "", - CONTROLLERS: [["spin", { startAngle: Math.PI / 2, speed: 0, independent: true }]], + FACING_TYPE: ["noFacing", { angle: Math.PI / 2 }], COLOR: "black", SHAPE: 6, INDEPENDENT: true } + +//delta turrets +Class.projectileAutoTurret = { + PARENT: "autoTurret", + GUNS: [ + { + POSITION: [22, 10, 1, 0, 0, 0, 0.25], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.power, { recoil: 1.15 }, g.turret, g.overdrive]), + TYPE: "bullet", + }, + }, + ], +} +Class.homingAutoTurret = { + PARENT: "genericTank", + LABEL: "Turret", + COLOR: "orange", + INDEPENDENT: true, + CONTROLLERS: ['nearestDifferentMaster'], + BODY: { + FOV: 0.8, + }, + GUNS: [ + { + POSITION: [22, 10, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.power, { recoil: 1.15 }, g.turret]), + TYPE: "homingBullet", + COLOR: "orange", + }, + }, + ], +} +Class.ceptionistturret = { + PARENT: "genericTank", + LABEL: "Turret", + COLOR: "darkGray", + BODY: { + FOV: 0.8, + }, + GUNS: [ + { + POSITION: [22, 10, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.pelleter, g.power, { recoil: 1.15 }, g.turret]), + TYPE: "ceptionistbullet", + COLOR: "darkGray", + }, + }, + ], +} +Class.fastbigauto4gun = { + PARENT: "auto4gun", + GUNS: [ + { + POSITION: [14, 5, 1, 0, -4.5, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.autoTurret, g.pelleter, g.twin, g.twin, g.power, { reload: 1.2 }]), + TYPE: "bullet", + }, + }, + { + POSITION: [14, 5, 1, 0, 4.5, 0, 0.33], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.autoTurret, g.pelleter, g.twin, g.twin, g.power, { reload: 1.2 }]), + TYPE: "bullet", + }, + }, + { + POSITION: [16, 5, 1, 0, 0, 0, 0.67], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.autoTurret, g.pelleter, g.twin, g.twin, g.power, { reload: 2 }]), + TYPE: "bullet", + }, + }, + ], +} +Class.helecopterblade = { + LABEL: "whatat", + CONTROLLERS: [["spin", { independent: true, speed: 0.16 }]], + COLOR: 16, + // M 0.1 -1.3 C 0.1 -1.4 0.1 -1.5 -0.1 -1.6 L -0.1 -0.3 A 0.5 0.5 -180 0 0 -0.3 -0.1 L -1.3 -0.1 C -1.4 -0.1 -1.5 -0.1 -1.6 0.1 L -0.3 0.1 A 0.5 0.5 -180 0 0 -0.1 0.3 L -0.1 1.3 C -0.1 1.4 -0.1 1.5 0.1 1.6 L 0.1 0.3 A 0.5 0.5 -180 0 0 0.3 0.1 L 1.3 0.1 C 1.4 0.1 1.5 0.1 1.6 -0.1 L 0.3 -0.1 A 0.5 0.5 -180 0 0 0.1 -0.3 Z + SHAPE: "M -1.7 -0.1 C -1.8 -0.1 -1.9 -0.1 -2 0.1 L -0.4 0.1 A 0.5 0.5 90 0 0 -0.1 0.4 L -0.1 1.7 C -0.1 1.8 -0.1 1.9 0.1 2 L 0.1 0.4 A 0.5 0.5 90 0 0 0.4 0.1 L 1.7 0.1 C 1.8 0.1 1.9 0.1 2 -0.1 L 0.4 -0.1 A 0.5 0.5 90 0 0 0.1 -0.4 L 0.1 -1.7 C 0.1 -1.8 0.1 -1.9 -0.1 -2 L -0.1 -0.4 A 0.5 0.5 90 0 0 -0.4 -0.1 Z", + // SHAPE: 'M -1.7 -0.1 C -1.8 -0.1 -1.9 -0.1 -2 0.1 L -0.5 0.1 A 0.5 0.5 90 0 0 -0.1 0.5 L -0.1 1.7 C -0.1 1.8 -0.1 1.9 0.1 2 L 0.1 0.5 A 0.5 0.5 90 0 0 0.5 0.1 L 1.7 0.1 C 1.8 0.1 1.9 0.1 2 -0.1 L 0.5 -0.1 A 0.5 0.5 90 0 0 0.1 -0.5 L 0.1 -1.7 C 0.1 -1.8 0.1 -1.9 -0.1 -2 L -0.1 -0.5 A 0.5 0.5 90 0 0 -0.5 -0.1 Z', + INDEPENDENT: true, +}; +Class.helecoptersblade = { + LABEL: "what", + CONTROLLERS: [["spin", { independent: true, speed: 0.16 }]], + COLOR: 16, + SHAPE: "M -0.1 1 C -0.1 1.1 -0.1 1.2 0.1 1.3 L 0.1 0.3 A 0.5 0.5 0 0 0 0.3 0.1 L 1 0.1 C 1.1 0.1 1.2 0.1 1.3 -0.1 L 0.3 -0.1 A 0.5 0.5 0 0 0 0.1 -0.3 L 0.1 -1 C 0.1 -1.1 0.1 -1.2 -0.1 -1.3 L -0.1 -0.3 A 0.5 0.5 0 0 0 -0.3 -0.1 L -1 -0.1 C -1.1 -0.1 -1.2 -0.1 -1.3 0.1 L -0.3 0.1 A 0.5 0.5 0 0 0 -0.1 0.3 Z", + // M 0.1 -1.3 C 0.1 -1.4 0.1 -1.5 -0.1 -1.6 L -0.1 -0.3 A 0.5 0.5 -180 0 0 -0.3 -0.1 L -1.3 -0.1 C -1.4 -0.1 -1.5 -0.1 -1.6 0.1 L -0.3 0.1 A 0.5 0.5 -180 0 0 -0.1 0.3 L -0.1 1.3 C -0.1 1.4 -0.1 1.5 0.1 1.6 L 0.1 0.3 A 0.5 0.5 -180 0 0 0.3 0.1 L 1.3 0.1 C 1.4 0.1 1.5 0.1 1.6 -0.1 L 0.3 -0.1 A 0.5 0.5 -180 0 0 0.1 -0.3 Z + // SHAPE:'M -1.7 -0.1 C -1.8 -0.1 -1.9 -0.1 -2 0.1 L -0.4 0.1 A 0.5 0.5 90 0 0 -0.1 0.4 L -0.1 1.7 C -0.1 1.8 -0.1 1.9 0.1 2 L 0.1 0.4 A 0.5 0.5 90 0 0 0.4 0.1 L 1.7 0.1 C 1.8 0.1 1.9 0.1 2 -0.1 L 0.4 -0.1 A 0.5 0.5 90 0 0 0.1 -0.4 L 0.1 -1.7 C 0.1 -1.8 0.1 -1.9 -0.1 -2 L -0.1 -0.4 A 0.5 0.5 90 0 0 -0.4 -0.1 Z', + // SHAPE: 'M -1.7 -0.1 C -1.8 -0.1 -1.9 -0.1 -2 0.1 L -0.5 0.1 A 0.5 0.5 90 0 0 -0.1 0.5 L -0.1 1.7 C -0.1 1.8 -0.1 1.9 0.1 2 L 0.1 0.5 A 0.5 0.5 90 0 0 0.5 0.1 L 1.7 0.1 C 1.8 0.1 1.9 0.1 2 -0.1 L 0.5 -0.1 A 0.5 0.5 90 0 0 0.1 -0.5 L 0.1 -1.7 C 0.1 -1.8 0.1 -1.9 -0.1 -2 L -0.1 -0.5 A 0.5 0.5 90 0 0 -0.5 -0.1 Z', + INDEPENDENT: true, +}; +Class.turretBase = { + LABEL: "Base", + SHAPE: 'M 0 -1 A 1 1 0 0 0 0 1 A 1 1 0 0 0 0 -1 Z M 0 -1 A 0.001 0.001 0 0 1 0 1 A 0.001 0.001 0 0 1 0 -1', + COLOR: 9, + CONTROLLERS: [["spin", { independent: true }]], + INDEPENDENT: true, + TURRETS: [{ + POSITION: [4.65, 10.5, 0, 90, 220, 1], + TYPE: "revogun", + }, { + POSITION: [4.65, 10.5, 0, 270, 220, 1], + TYPE: "revogun", + }] +}; +Class.turretBasenoguns = { + LABEL: "Base", + SHAPE: 'M 0 -1 A 1 1 0 0 0 0 1 A 1 1 0 0 0 0 -1 Z M 0 -1 A 0.001 0.001 0 0 1 0 1 A 0.001 0.001 0 0 1 0 -1', + COLOR: 9, + CONTROLLERS: [["spin", { independent: true }]], + INDEPENDENT: true, +}; +Class.grenadeDeco = makeDeco(0); +Class.turretBaseKiva = { + LABEL: "Basethingygygyyasgsdgajskhg", + SHAPE: 'M 0 -1 A 1 1 0 0 0 0 1 A 1 1 0 0 0 0 -1 Z M 0 -1 A 0.001 0.001 0 0 1 0 1 A 0.001 0.001 0 0 1 0 -1', + COLOR: "#FC8208",//iT WonT FUckING SpIN + SYNC_TURRET_SKILLS: true, + CONTROLLERS: [["spin", { independent: true }]], + INDEPENDENT: true, + TURRETS: [{ + POSITION: [4.65, 9.85, 0, 90, 220, 1], + TYPE: ["revogun", { COLOR: "#FC8208" }] + }, { + POSITION: [4.65, 9.85, 0, 270, 220, 1], + TYPE: ["revogun", { COLOR: "#FC8208" }] + }] +}; +Class.hadronturretBase = { + LABEL: "Base", + SHAPE: 'M 0 -1 A 1 1 0 0 0 0 1 A 1 1 0 0 0 0 -1 Z M 0 -1 A 0.001 0.001 0 0 1 0 1 A 0.001 0.001 0 0 1 0 -1', + COLOR: 'red', + CONTROLLERS: ["hadron"], + TURRETS: [{ + POSITION: [4.65, 10.5, 0, 90, 220, 1], + TYPE: "revogun", + }, { + POSITION: [4.65, 10.5, 0, 270, 220, 1], + TYPE: "revogun", + }] +}; +Class.subverterturretBase = { + LABEL: "Base", + SHAPE: 'M 0 -1.1 A 1 1 0 0 0 0 1.1 A 1 1 0 0 0 0 -1.1 Z M 0 -1 A 0.001 0.001 0 0 1 0 1 A 0.001 0.001 0 0 1 0 -1', + COLOR: 9, + CONTROLLERS: [["spin", { independent: true }]], + INDEPENDENT: true, + TURRETS: [{ + POSITION: [4.65, 10.5, 0, 90, 220, 1], + TYPE: "revogun", + }, { + POSITION: [4.65, 10.5, 0, 180, 220, 1], + TYPE: "revogun", + }, { + POSITION: [4.65, 10.5, 0, 270, 220, 1], + TYPE: "revogun", + }, { + POSITION: [4.65, 10.5, 0, 0, 220, 1], + TYPE: "revogun", + }] +}; +Class.protonturretBase = { + LABEL: "Base", + SHAPE: 'M 0 -1 A 1 1 0 0 0 0 1 A 1 1 0 0 0 0 -1 Z M 0 -1 A 0.001 0.001 0 0 1 0 1 A 0.001 0.001 0 0 1 0 -1', + COLOR: 9, + CONTROLLERS: [["spin", { independent: true }]], + INDEPENDENT: true, + TURRETS: [{ + POSITION: [5, 10.5, 0, 0, 220, 1], + TYPE: ["revosheild", { SHAPE: 12 }], + VULNERABLE: true, + + }, { + POSITION: [5, 10.5, 0, 360/3, 220, 1], + TYPE: ["revosheild", { SHAPE: 12 }], + VULNERABLE: true, + + }, { + POSITION: [5, 10.5, 0, 360/3*2, 220, 1], + TYPE: ["revosheild", { SHAPE: 12 }], + VULNERABLE: true, + }] +}; +Class.pionturretBase = { + LABEL: "Base", + SHAPE: 'M 0 -1 A 1 1 0 0 0 0 1 A 1 1 0 0 0 0 -1 Z M 0 -1 A 0.001 0.001 0 0 1 0 1 A 0.001 0.001 0 0 1 0 -1', + COLOR: 'red', + CONTROLLERS: ["hadron"], + TURRETS: [{ + POSITION: [5, 10.5, 0, 90, 220, 1], + TYPE: ["revosheild", { SHAPE: 12 }], + VULNERABLE: true, + }, { + POSITION: [5, 10.5, 0, 270, 220, 1], + TYPE: ["revosheild", { SHAPE: 12 }], + VULNERABLE: true, + }] +}; +Class.saturnturretBase = { + LABEL: "Base", + COLOR: 'mirror', + BORDERLESS: true, + OPACITY: 0.5, + SHAPE: 'M -1.75 1 L -1.75 -1 L -0 -2 L 1.75 -1 L 1.75 1 L 0 2 L -1.75 1 L -1.6625 0.95 L 0 1.9 L 1.6625 0.95 L 1.6625 -0.95 L -0 -1.9 L -1.6625 -0.95 L -1.6625 0.95', + FACING_TYPE: ["spin", { speed: 0.1 }], + INDEPENDENT: true, + TURRETS: [{ + POSITION: [2, 17, 0, 60, 0, 1], + TYPE: "saturnbullet", + }, { + POSITION: [2, 17, 0, 120, 0, 1], + TYPE: "saturnbullet", + }, { + POSITION: [2, 17, 0, 180, 0, 1], + TYPE: "saturnbullet", + }, { + POSITION: [2, 17, 0, 240, 0, 1], + TYPE: "saturnbullet", + }, { + POSITION: [2, 17, 0, 300, 0, 1], + TYPE: "saturnbullet", + }, { + POSITION: [2, 17, 0, 0, 0, 1], + TYPE: "saturnbullet", + }] +} +Class.saturnDeco = { + LABEL: "", + FACING_TYPE: ["spin", { speed: 0.1 }], + COLOR: "black", + SHAPE: "M -1.75 1 L -1.75 -1 L -0 -2 L 1.75 -1 L 1.75 1 L 0 2 L -1.75 1 L -1.6625 0.95 L 0 1.9 L 1.6625 0.95 L 1.6625 -0.95 L -0 -1.9 L -1.6625 -0.95 L -1.6625 0.95", + INDEPENDENT: true +} +Class.saturnbullet = { + PARENT: "genericTank", + COLOR: "mirror", + SHAPE: 0, + INDEPENDENT: true, + BODY: { + HEALTH: 10000, + SHIELD: 10000, + REGEN: 10000, + }, + GUNS: [ + { + POSITION: {WIDTH: 8, LENGTH: 10}, + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, { + range: 0.1, + speed: 0, + maxSpeed: 0, + recoil: 0, + reload: 0.1, + damage: 4, + size: 2, + health: 1, + }]), + TYPE: ["bullet", { + BODY: { + PENETRATION: 1, + SPEED: 3.75, + RANGE: 90, + DENSITY: 1.25, + HEALTH: 0.165, + DAMAGE: 150, + PUSHABILITY: 0.3, + }, + ALPHA: 0, + ON: [{ + event: 'tick', + handler: ({body}) => { + body.DAMAGE -= 1; + body.SIZE -= 0.6; + if (body.SIZE < 1) body.kill(); + } + }], + }], + AUTOFIRE: true, + BORDERLESS: true, + DRAW_FILL: false, + } + } + ] +} +Class.revogun = { + LABEL: 'Auto Turret', + SYNC_TURRET_SKILLS: true, + BODY: { + FOV: 1 + }, + COLOR: 16, + CONTROLLERS: ['onlyAcceptInArc', 'nearestDifferentMaster'], + GUNS: [{ + POSITION: [13.5, 10, 1, 8, 0, 0, 0.5], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.autoTurret]), + TYPE: "bullet" + } + } + ] +} +Class.revosheild = { + PARENT: "genericTank", + DAMAGE_CLASS: 1, + TYPE: "shield", + COLOR: "darkGray", + SHAPE: 0, + INDEPENDENT: true, + BODY: { + PUSHABILITY: 1, + HEALTH: 10000, + SHIELD: 10000, + REGEN: 1000, + DAMAGE: 1, + RESIST: 100, + STEALTH: 1, + DENSITY: 10000, + PENETRATION: 0.01 + }, +} +Class.backshieldturret = { + PARENT: "genericTank", + TYPE: "shield", + DAMAGE_CLASS: 1, + SHAPE: "m -0.702 -0.8099 c 0.2987 0.4922 0.4276 1.0098 0 1.6105 c 0.4606 -0.1615 0.9233 -0.3735 1.3947 -0.8052 C 0.2005 -0.4442 -0.2526 -0.6387 -0.702 -0.8099", + COLOR: "#FF7F00", + INDEPENDENT: true, + BODY: { + HEALTH: 10000, + SHIELD: 10000, + REGEN: 1000, + PENETRATION: 0.01 + }, +} +Class.mirrorDeco = makeDeco("M 0 -1.1 A 1 1 0 0 0 0 1.1 A 1 1 0 0 0 0 -1.1 Z M 0 -0.9 A 0.001 0.001 0 0 1 0 0.9 A 0.001 0.001 0 0 1 0 -0.9") +Class.mirrorbackshieldturret = { + PARENT: "genericTank", + TYPE: "shield", + INDEPENDENT: true, + BODY: { + HEALTH: 10000, + SHIELD: 10000, + REGEN: 1000, + PENETRATION: 0.01 + }, + SHAPE: "m -0.7020 -0.8099 c 0.2987 0.4922 0.4276 1.0098 0 1.6105 c 0.4606 -0.1615 0.9233 -0.3735 1.3947 -0.8052 C 0.2005 -0.4442 -0.2526 -0.6387 -0.702 -0.8099", + COLOR: "#FF7F00", + TURRETS: [{ + POSITION: [5.7, 0, 0, 0, 360, 1], + TYPE: "mirrorDeco" + }] +} +// The sheild uses the hitbox like an aura, but it can hit bullets +Class.autoTurretNerf = { + PARENT: "genericTank", + LABEL: "Turret", + BODY: { + FOV: 0.8, + }, + COLOR: "grey", + GUNS: [ + { + POSITION: [22, 10, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.weak, g.fake, g.basic, g.morerecoil, g.turret, g.autoTurret]), + TYPE: "bullet", + }, + }, + ], +} +Class.mindindicator = { + SHAPE: 'M 0 -1.0 A 1 1 0 0 0 0 1.0 A 1 1 0 0 0 0 -1.0 Z M 0 -1 A 0.001 0.001 0 0 1 0 1 A 0.001 0.001 0 0 1 0 -1', + COLOR: 9, +}; +Class.crosshair1 = { + SHAPE: 'M 0 0 l 1 0 L 0 0 L -1 0 L 0 0 L 0 1 L 0 -1', + COLOR: 9, +}; +Class.greenSmasherBody = { + LABEL: "", + GLOW: { + RADIUS: 2, + COLOR: "green", + ALPHA: 1, + RECURSION: 4, + }, + CONTROLLERS: [["spin", { independent: true, speed: 0.1 }]], + COLOR: "green", + SHAPE: 6, + INDEPENDENT: true, + BORDERLESS: true, +} +Class.droneturretBase = { + LABEL: "Base", + SHAPE: 'M 0 -1 A 1 1 0 0 0 0 1 A 1 1 0 0 0 0 -1 Z M 0 -1 A 0.001 0.001 0 0 1 0 1 A 0.001 0.001 0 0 1 0 -1', + COLOR: 9, + CONTROLLERS: [["spin", { independent: true }]], + SYNC_TURRET_SKILLS: true, + TURRETS: [{ + POSITION: [4.65, 10.5, 0, 90, 220, 1], + TYPE: "droneAutoTurret", + }, { + POSITION: [4.65, 10.5, 0, 270, 220, 1], + TYPE: "droneAutoTurret", + }] +} +Class.dualAutoTankGun = { + TURRETS: [{ + POSITION: [11, 0, 0, 0, 190, 0], + TYPE: "autoTankGun" + }, { + POSITION: [11, 0, 0, 180, 190, 0], + TYPE: "autoTankGun" + }] +} +Class.autoTankGunDrive = { + PARENT: "genericTank", + LABEL: "", + BODY: { + FOV: 3, + }, + SHAPE: 4, + CONTROLLERS: ["canRepel", "onlyAcceptInArc", "mapAltToFire", "nearestDifferentMaster"], + COLOR: "grey", + GUNS: [ + { + POSITION: [22, 10, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.autoTurret]), + TYPE: "bullet", + }, + }, + ], +} +Class.swivelAutoGun = { + PARENT: "genericTank", + LABEL: "", + BODY: { + FOV: 3, + }, + CONTROLLERS: ["canRepel", "onlyAcceptInArc", "mapAltToFire", "nearestDifferentMaster"], + COLOR: "grey", + GUNS: [ + { + POSITION: [22, 10, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.autoTurret, g.lesspower, {speed: 0.9, recoil: 0.8}]), + TYPE: "bullet", + }, + }, + ], +} +Class.jumpsmashBody = { + PARENT: "smasherBody", + SHAPE: 7 +} +Class.autoTurret3 = { + LABEL: 'Auto Turret', + BODY: { + FOV: 0.9 + }, + COLOR: 16, + GUNS: [{ + POSITION: [21.5, 10, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.autoTurret, g.lesspower, g.bitlessreload]), + TYPE: "bullet" + } + }] +}; +Class.skaterDeco = makeDeco("M 0 -1.1 A 1 1 0 0 0 0 1.1 A 1 1 0 0 0 0 -1.1 Z M 0 -1 A 0.001 0.001 0 0 1 0 1 A 0.001 0.001 0 0 1 0 -1"); +Class.skaterDeco.STROKE_WIDTH = 2; +Class.switcherDeco = makeDeco('M 0 0 M 2 -1 L -2 -1 L -2 8 L -1 8 L 1 8 L 2 8') +Class.effectBulletDeco = makeDeco(0) +Class.firecrackerDeco = makeDeco(-6) +Class.surgeDeco = makeDeco(-1, "spaceGem"); +Class.katanaDeco = makeDeco('M 0 2 L 0 -1 L 1 0 L 0 -1 L -1 0 L 0 -1', "#add6f7"); +Class.brellaDeco = makeDeco('M -0 2.2587 L 0.9 0.905 L 0.9 -0.9 L -0 -2.2537 L -0.9 -2.5245 L -0.9 2.5295 L -0 2.2587', "gray") \ No newline at end of file diff --git a/server/modules/definitions/gunvals.js b/server/modules/definitions/gunvals.js index fd4d5850b..225d79c33 100644 --- a/server/modules/definitions/gunvals.js +++ b/server/modules/definitions/gunvals.js @@ -3,12 +3,12 @@ module.exports = { basic: { reload: 10.5, recoil: 1.4, shudder: 0.1, damage: 0.75, speed: 4.5, spray: 15 }, drone: { reload: 36, recoil: 0.25, shudder: 0.1, size: 0.6, speed: 2, spray: 0.1 }, trap: { reload: 23, shudder: 0.25, size: 0.6, damage: 0.75, speed: 5, spray: 15, resist: 3 }, - swarm: { reload: 23, recoil: 0.25, shudder: 0.05, size: 0.4, damage: 0.75, speed: 4, spray: 5 }, + swarm: { reload: 23, recoil: 0.25, shudder: 0.05, size: 0.4, damage: 1.2, speed: 4, spray: 5 }, factory: { reload: 48, shudder: 0.1, size: 0.7, damage: 0.75, speed: 3, spray: 0.1 }, productionist: { reload: 56, recoil: 0.25, shudder: 0.05, size: 0.7, damage: 0.75, speed: 4, range: 1.5, spray: 5 }, // Spammers - desmos: { shudder: 0, spray: 0, size: 0.8 }, + desmos: { shudder: 0, spray: 0, size: 0.8, damage: 0.9, reload: 1.1 }, single: { reload: 1.05, speed: 1.05 }, twin: { recoil: 0.5, shudder: 0.9, health: 0.9, damage: 0.7, spray: 1.2 }, doubleTwin: { damage: 0.9 }, @@ -16,9 +16,10 @@ module.exports = { tripleShot: { reload: 1.1, shudder: 0.8, health: 0.9, pen: 0.8, density: 0.8, spray: 0.5 }, spreadshotMain: { reload: 0.781, recoil: 0.25, shudder: 0.5, health: 0.5, speed: 1.923, maxSpeed: 2.436 }, spreadshot: { reload: 1.5, shudder: 0.25, speed: 0.7, maxSpeed: 0.7, spray: 0.25 }, - triplet: { reload: 1.2, recoil: 0.667, shudder: 0.9, health: 0.85, damage: 0.85, pen: 0.9, density: 1.1, spray: 0.9, resist: 0.95 }, + triplet: { reload: 1.2, recoil: 2/3, shudder: 0.9, health: 0.85, damage: 0.85, pen: 0.9, density: 1.1, spray: 0.9, resist: 0.95 }, turret: { reload: 2, health: 0.8, damage: 0.6, pen: 0.7, density: 0.1 }, autoTurret: { reload: 0.9, recoil: 0.75, shudder: 0.5, size: 0.8, health: 0.9, damage: 0.6, pen: 1.2, speed: 1.1, range: 0.8, density: 1.3, resist: 1.25 }, + littleHunter: { recoil: 0.9, shudder: 0.9, health: 0.9, damage: 0.7, pen: 0.9, reload: 0.9 }, // Snipers sniper: { reload: 1.35, shudder: 0.25, damage: 0.8, pen: 1.1, speed: 1.5, maxSpeed: 1.5, density: 1.5, spray: 0.2, resist: 1.15 }, @@ -29,9 +30,10 @@ module.exports = { predator: { reload: 1.4, size: 0.8, health: 1.5, damage: 0.9, pen: 1.2, speed: 0.9, maxSpeed: 0.9 }, dual: { reload: 2, shudder: 0.8, health: 1.5, speed: 1.3, maxSpeed: 1.1, resist: 1.25 }, rifle: { reload: 0.8, recoil: 0.8, shudder: 1.5, health: 0.8, damage: 0.8, pen: 0.9, spray: 2 }, + railgun: { reload: 2, health: 0.85, damage: 0.5, pen: 0.9 }, // Machine guns - machineGun: { reload: 0.5, recoil: 0.8, shudder: 1.7, health: 0.7, damage: 0.7, maxSpeed: 0.8, spray: 2.5 }, + machineGun: { reload: 0.5, recoil: 0.8, shudder: 1.7, health: 0.7, damage: 0.7, maxSpeed: 0.8, spray: 2.5, size: 0.8 }, minigun: { reload: 1.25, recoil: 0.6, size: 0.8, health: 0.55, damage: 0.45, pen: 1.25, speed: 1.33, density: 1.25, spray: 0.5, resist: 1.1 }, streamliner: { reload: 1.1, recoil: 0.6, damage: 0.65, speed: 1.24 }, nailgun: { reload: 0.85, recoil: 2.5, size: 0.8, damage: 0.7, density: 2 }, @@ -58,25 +60,26 @@ module.exports = { baseProtector: { reload: 2, recoil: 0.000001, health: 100, range: 0.5, density: 5, resist: 10 }, battleship: { health: 1.25, damage: 1.15, maxSpeed: 0.85, resist: 1.1 }, carrier: { reload: 1.5, damage: 0.8, speed: 1.3, maxSpeed: 1.2, range: 1.2 }, - bee: { reload: 1.3, size: 1.4, damage: 1.5, pen: 0.5, speed: 3, maxSpeed: 1.5, density: 0.25 }, - sunchip: { reload: 5, size: 1.4, health: 0.5, damage: 0.4, pen: 0.6, density: 0.8 }, - maleficitor: { reload: 0.5, size: 1.05, health: 1.15, damage: 1.15, pen: 1.15, speed: 0.8, maxSpeed: 0.8, density: 1.15 }, - summoner: { reload: 0.3, size: 1.125, health: 0.4, damage: 0.345, pen: 0.4, density: 0.8 }, + bee: { reload: 1.3, size: 1.4, damage: 1.5, pen: 0.5, speed: 1.5, maxSpeed: 1.5, density: 0.25 }, + sunchip: { reload: 4, size: 1.4, health: 0.5, damage: 0.4, pen: 0.6, density: 0.8 }, + maleficitor: { reload: 0.25, size: 1.05, health: 1.15, damage: 1.15, pen: 1.15, speed: 0.8, maxSpeed: 0.8, density: 1.15 }, + summoner: { reload: 0.3, size: 1.125, health: 0.5, damage: 0.345, pen: 0.4, density: 0.8 }, minionGun: { recoil: 0, shudder: 2, health: 0.4, damage: 0.4, pen: 1.2, range: 0.75, spray: 2 }, - babyfactory: { reload: 1.5, maxSpeed: 1.35 }, + babyfactory: { reload: 1.5, maxSpeed: 1.25 }, bigCheese: { reload: 1.5, size: 1.8, health: 2.5, speed: 1.25 }, mothership: { reload: 1.25, pen: 1.1, speed: 0.775, maxSpeed: 0.8, range: 15, resist: 1.15 }, - satellite: { size: 0.8, reload: 3, damage: 1.875 }, + satellite: { size: 0.8, reload: 3, damage: 4 }, + contagi: { reload: 1, recoil: 0.5, shudder: 1.5, size: 1, health: 0.6, damage: 0.6, pen: 0.75, speed: 1.05, maxSpeed: 1, range: 1, density: 0.9, spray: 0.75, resist: 0.7 }, // Heavy cannons pounder: { reload: 2, recoil: 1.6, damage: 2, speed: 0.85, maxSpeed: 0.8, density: 1.5, resist: 1.15 }, - destroyer: { reload: 2.2, recoil: 1.8, shudder: 0.5, health: 2, damage: 2, pen: 1.2, speed: 0.65, maxSpeed: 0.5, density: 2, resist: 3 }, - annihilator: { reload: 0.8, recoil: 1.25 }, + destroyer: { reload: 2.2, recoil: 1.8, shudder: 0.5, health: 2, damage: 1.4, pen: 1.2, speed: 0.65, maxSpeed: 0.5, density: 2, resist: 3 }, + annihilator: { reload: 0.8, recoil: 1.25, damage: 1.43 }, hive: { reload: 1.5, recoil: 0.8, size: 0.8, health: 0.7, damage: 0.3, maxSpeed: 0.6 }, artillery: { reload: 1.2, recoil: 0.7, size: 0.9, speed: 1.15, maxSpeed: 1.1, density: 1.5 }, mortar: { reload: 1.2, health: 1.1, speed: 0.8, maxSpeed: 0.8 }, shotgun: { reload: 8, recoil: 0.4, size: 1.5, damage: 0.4, pen: 0.8, speed: 1.8, maxSpeed: 0.6, density: 1.2, spray: 1.2 }, - destroyerDominator: { reload: 6.5, recoil: 0, size: 0.975, health: 6, damage: 6, pen: 6, speed: 0.575, maxSpeed: 0.475, spray: 0.5 }, + destroyerDominator: { reload: 6.5, recoil: 0, size: 0.975, health: 5, damage: 5, pen: 5, speed: 0.575, maxSpeed: 0.475, spray: 0.5 }, // Missiles launcher: { reload: 1.5, recoil: 1.5, shudder: 0.1, size: 0.72, health: 1.05, damage: 0.925, speed: 0.9, maxSpeed: 1.2, range: 1.1, resist: 1.5 }, @@ -91,7 +94,7 @@ module.exports = { // Traps and blocks setTrap: { reload: 1.1, recoil: 2, shudder: 0.1, size: 1.5, health: 2, pen: 1.25, speed: 1.5, maxSpeed: 2.5, range: 1.25, resist: 1.25 }, construct: { reload: 1.3, size: 0.9, maxSpeed: 1.1 }, - boomerang: { reload: 0.8, health: 0.5, damage: 0.5, speed: 0.75, maxSpeed: 0.75, range: 1.333 }, + boomerang: { reload: 0.8, health: 0.5, damage: 0.5, speed: 0.75, maxSpeed: 0.75, range: 4/3 }, nestKeeper: { reload: 3, size: 0.75, health: 1.05, damage: 1.05, pen: 1.1, speed: 0.5, maxSpeed: 0.5, range: 0.5, density: 1.1 }, hexaTrapper: { reload: 1.3, shudder: 1.25, speed: 0.8, range: 0.5 }, trapperDominator: { reload: 1.26, recoil: 0, shudder: 0.25, health: 1.25, damage: 1.45, pen: 1.6, speed: 0.5, maxSpeed: 2, range: 0.7, spray: 0.5 }, @@ -105,7 +108,63 @@ module.exports = { arenaCloser: { reload: 1.25, recoil: 0.25, health: 1000, damage: 1000, pen: 1000, speed: 2.5, maxSpeed: 2.25, range: 1.4, density: 4, spray: 0.25 }, healer: { damage: -1, speed: 0.5, maxSpeed: 0.5, recoil: 0.5 }, lowPower: { shudder: 2, health: 0.5, damage: 0.5, pen: 0.7, spray: 0.5, resist: 0.7 }, - halfrange: { range: 0.5 }, aura: { reload: 0.001, recoil: 0.001, shudder: 0.001, size: 6, speed: 0.001, maxSpeed: 0.001, spray: 0.001 }, - noSpread: { shudder: 0, spray: 0 } + noSpread: { shudder: 0, spray: 0 }, + lessspread: { shudder: 0.75, spread: 0.75 }, + + // Range + doublerange: { range: 2 }, + morerange: { range: 1.15 }, + halfrange: { range: 0.5 }, + norange: { range: 0.2 }, + literallynorange: { range: 0 }, + + // Recoil + tonsmorerecoil: { recoil: 4 }, + lotsmorrecoil: { recoil: 1.8 }, + muchmorerecoil: { recoil: 1.35 }, + morerecoil: { recoil: 1.15 }, + lessrecoil: { recoil: 0.65 }, + halfrecoil: { recoil: 0.5 }, + + // Reload + noshoot: { reload: Infinity }, + halfreload: { reload: 2 }, + lessreload: { reload: 1.5 }, + one_third_reload: { reload: 1.333 }, + bitlessreload: { reload: 0.9 }, + morereload: { reload: 0.75 }, + doublereload: { reload: 0.5 }, + triplereload: { reload: 1/3 }, + + // Speed + fast: { speed: 1.2 }, + veryfast: { speed: 2.5 }, + morespeed: { speed: 1.3, maxSpeed: 1.3 }, + bitlessspeed: { speed: 0.93, maxSpeed: 0.93 }, + slow: { speed: 0.7, maxSpeed: 0.7 }, + halfspeed: { speed: 0.5, maxSpeed: 0.5 }, + nomove: { speed: 0, maxSpeed: 0 }, + + // Misc 2 + fakewithrecoil: { recoil: 1, size: 0.00001, health: 0.0001, speed: 0.00001, maxSpeed: 2, range: 0 }, + kiva: { damage: 0.3, pen: 0.2, health: 4, range: 1.5, speed: 1, maxSpeed: 1.4 }, + xxtrahealth: { health: 999 }, + lance: { reload: 0.4, speed: 0.18, maxSpeed: 0.18, range: 0.07, pen: 3, health: 0.8, recoil: 0 }, + chasseur: { reload: 0.4, speed: 0.28, maxSpeed: 0.28, range: 0.07, pen: 3, health: 0.8, recoil: 0 }, + lesspower: { health: 0.9, damage: 0.9, pen: 0.9 }, + grenade_explosion: { reload: 8, recoil: 0, shudder: 4.25, size: 2, health: 2.25, damage: 1.75, pen: 1.5, speed: 1.35, spray: 4 }, + literallyamachinegun: { reload: 0.2, speed: 5, maxSpeed: 5, spray: 0.3, shudder: 0.6 }, + rainmaker: { speed: 0.03, maxSpeed: 0.5, health: 0.98, damage: 0.88, range: 0.25 }, + acceltospeedoflight: { speed: 0.001, maxSpeed: 1000 }, + explosion: { speed: 0.01, maxSpeed: 0.01, health: 5, damage: 3, pen: 4.6, density: 3.6, resist: 3 }, + brella: { reload: 2.5, health: 35, pen: 0, damage: 0.2, maxSpeed: 0.8, spray: 0, range: 2.25, size: 2.4, shudder: 0.1 }, + magnet: { damage: 0, health: 0.8, spray: 45, range: 0.08, recoil: 0, speed: 0.8, pen: 0 }, + solarioblast: { reload: 0.05, health: 5, pen: 100, speed: 14, maxSpeed: 14, spread: 4, size: 2, range: 0.6 }, + emplaser: { reload: 1.25, recoil: 0, size: 1.7 }, + empbullet: { reload: 1.25, recoil: 0, size: 2.5, speed: 1.1, maxSpeed: 1.1, spray: 0.2 }, + cloner: { damage: 0.78, pen: 0.85 }, + sidewinder2: { shudder: 0, spray: 0, size: 0.8, speed: 0.001, damage: 5 }, + repeater: { damage: 0.6 }, + vulc: {reload: 1.25, recoil: 0.1, shudder: 0, size: 0.8, health: 0.6, damage: 0.27, pen: 1, speed: 1.3, maxSpeed: 1.3, range: 1, density: 1.25, spray: 0.001, resist: 1.1}, } \ No newline at end of file diff --git a/server/modules/gamemodes/bossRush.js b/server/modules/gamemodes/bossRush.js index 4ab1e062b..45e94958e 100644 --- a/server/modules/gamemodes/bossRush.js +++ b/server/modules/gamemodes/bossRush.js @@ -7,7 +7,7 @@ let calculatePoints = wave => 5 + wave * 3; let oldGroups = { elites: [ "eliteDestroyer", "eliteGunner", "eliteSprayer", "eliteBattleship", "eliteSpawner" ], - mysticals: [ "summoner", "eliteSkimmer", "nestKeeper", "roguePalisade" ], + strange: [ "summoner", "eliteSkimmer", "nestKeeper", "roguePalisade" ], celestials: [ "paladin", "freyja", "zaphkiel", "nyx", "theia" ], eternals: [ "legionaryCrasher", "kronos", "odin" ], }; @@ -19,42 +19,42 @@ class BossRush { ran.chooseN(oldGroups.elites, 2), ran.chooseN(oldGroups.elites, 3), ran.chooseN(oldGroups.elites, 4), - ran.chooseN(oldGroups.elites, 3).concat(ran.chooseN(oldGroups.mysticals, 1)), - ran.chooseN(oldGroups.elites, 2).concat(ran.chooseN(oldGroups.mysticals, 2)), - ran.chooseN(oldGroups.elites, 1).concat(ran.chooseN(oldGroups.mysticals, 3)), - ran.chooseN(oldGroups.mysticals, 4), - ran.chooseN(oldGroups.elites, 1).concat(ran.chooseN(oldGroups.mysticals, 4)), - ran.chooseN(oldGroups.elites, 2).concat(ran.chooseN(oldGroups.mysticals, 4)), - ran.chooseN(oldGroups.elites, 3).concat(ran.chooseN(oldGroups.mysticals, 4)), - ran.chooseN(oldGroups.elites, 4).concat(ran.chooseN(oldGroups.mysticals, 4)), + ran.chooseN(oldGroups.elites, 3).concat(ran.chooseN(oldGroups.strange, 1)), + ran.chooseN(oldGroups.elites, 2).concat(ran.chooseN(oldGroups.strange, 2)), + ran.chooseN(oldGroups.elites, 1).concat(ran.chooseN(oldGroups.strange, 3)), + ran.chooseN(oldGroups.strange, 4), + ran.chooseN(oldGroups.elites, 1).concat(ran.chooseN(oldGroups.strange, 4)), + ran.chooseN(oldGroups.elites, 2).concat(ran.chooseN(oldGroups.strange, 4)), + ran.chooseN(oldGroups.elites, 3).concat(ran.chooseN(oldGroups.strange, 4)), + ran.chooseN(oldGroups.elites, 4).concat(ran.chooseN(oldGroups.strange, 4)), [ oldGroups.celestials[0] ], [ oldGroups.celestials[1] ], [ oldGroups.celestials[2] ], [ oldGroups.celestials[3] ], [ oldGroups.celestials[4] ], - ran.chooseN(oldGroups.elites, 1).concat(ran.chooseN(oldGroups.mysticals, 1)).concat(ran.chooseN(oldGroups.celestials, 1)), - ran.chooseN(oldGroups.elites, 3).concat(ran.chooseN(oldGroups.mysticals, 1)).concat(ran.chooseN(oldGroups.celestials, 1)), - ran.chooseN(oldGroups.elites, 3).concat(ran.chooseN(oldGroups.mysticals, 3)).concat(ran.chooseN(oldGroups.celestials, 1)), - ran.chooseN(oldGroups.elites, 4).concat(ran.chooseN(oldGroups.mysticals, 4)).concat(ran.chooseN(oldGroups.celestials, 1)), + ran.chooseN(oldGroups.elites, 1).concat(ran.chooseN(oldGroups.strange, 1)).concat(ran.chooseN(oldGroups.celestials, 1)), + ran.chooseN(oldGroups.elites, 3).concat(ran.chooseN(oldGroups.strange, 1)).concat(ran.chooseN(oldGroups.celestials, 1)), + ran.chooseN(oldGroups.elites, 3).concat(ran.chooseN(oldGroups.strange, 3)).concat(ran.chooseN(oldGroups.celestials, 1)), + ran.chooseN(oldGroups.elites, 4).concat(ran.chooseN(oldGroups.strange, 4)).concat(ran.chooseN(oldGroups.celestials, 1)), ran.chooseN(oldGroups.celestials, 2), - ran.chooseN(oldGroups.elites, 1).concat(ran.chooseN(oldGroups.mysticals, 2)).concat(ran.chooseN(oldGroups.celestials, 2)), - ran.chooseN(oldGroups.elites, 3).concat(ran.chooseN(oldGroups.mysticals, 3)).concat(ran.chooseN(oldGroups.celestials, 2)), - ran.chooseN(oldGroups.elites, 4).concat(ran.chooseN(oldGroups.mysticals, 4)).concat(ran.chooseN(oldGroups.celestials, 2)), + ran.chooseN(oldGroups.elites, 1).concat(ran.chooseN(oldGroups.strange, 2)).concat(ran.chooseN(oldGroups.celestials, 2)), + ran.chooseN(oldGroups.elites, 3).concat(ran.chooseN(oldGroups.strange, 3)).concat(ran.chooseN(oldGroups.celestials, 2)), + ran.chooseN(oldGroups.elites, 4).concat(ran.chooseN(oldGroups.strange, 4)).concat(ran.chooseN(oldGroups.celestials, 2)), ran.chooseN(oldGroups.celestials, 3), - ran.chooseN(oldGroups.elites, 3).concat(ran.chooseN(oldGroups.mysticals, 3)).concat(ran.chooseN(oldGroups.celestials, 3)), - ran.chooseN(oldGroups.elites, 4).concat(ran.chooseN(oldGroups.mysticals, 4)).concat(ran.chooseN(oldGroups.celestials, 3)), + ran.chooseN(oldGroups.elites, 3).concat(ran.chooseN(oldGroups.strange, 3)).concat(ran.chooseN(oldGroups.celestials, 3)), + ran.chooseN(oldGroups.elites, 4).concat(ran.chooseN(oldGroups.strange, 4)).concat(ran.chooseN(oldGroups.celestials, 3)), ran.chooseN(oldGroups.celestials, 4), - ran.chooseN(oldGroups.elites, 2).concat(ran.chooseN(oldGroups.mysticals, 2)).concat(ran.chooseN(oldGroups.celestials, 4)), - ran.chooseN(oldGroups.elites, 4).concat(ran.chooseN(oldGroups.mysticals, 4)).concat(ran.chooseN(oldGroups.celestials, 4)), + ran.chooseN(oldGroups.elites, 2).concat(ran.chooseN(oldGroups.strange, 2)).concat(ran.chooseN(oldGroups.celestials, 4)), + ran.chooseN(oldGroups.elites, 4).concat(ran.chooseN(oldGroups.strange, 4)).concat(ran.chooseN(oldGroups.celestials, 4)), ran.chooseN(oldGroups.celestials, 5), - ran.chooseN(oldGroups.elites, 4).concat(ran.chooseN(oldGroups.mysticals, 4)).concat(ran.chooseN(oldGroups.celestials, 5)), + ran.chooseN(oldGroups.elites, 4).concat(ran.chooseN(oldGroups.strange, 4)).concat(ran.chooseN(oldGroups.celestials, 5)), ran.chooseN(oldGroups.eternals, 1), ]; this.bossChoices = [ // [ cost , definition reference ], //mysticals - [ 1, "sorcerer"], + [ 2, "sorcerer"], [ 2, "summoner"], [ 2, "enchantress"], [ 2, "exorcistor"], @@ -90,19 +90,22 @@ class BossRush { [ 35, "theia"], //eternals - [ 99, "legionaryCrasher" /*fucking mid*/], + [100, "legionaryCrasher"], [100, "kronos"], [100, "odin"], ]; - this.friendlyBossChoices = ["roguePalisade", "rogueArmada", "julius", "genghis", "napoleon"]; + this.friendlyBossChoices = [ [9, "roguePalisade"], [8, "rogueArmada"], [1, "julius"], [1, "genghis"], [1, "napoleon"] ]; this.bigFodderChoices = ["sentryGun", "sentrySwarm", "sentryTrap", "shinySentryGun"]; this.smallFodderChoices = ["crasher"]; - this.length = c.CLASSIC_SIEGE ? this.waveCodes.length : c.WAVES; + this.length = Config.CLASSIC_SIEGE ? this.waveCodes.length : Config.WAVES; this.waves = this.generateWaves(); this.waveId = -1; this.gameActive = true; this.timer = 0; this.remainingEnemies = 0; + this.sanctuaryTier = 1; + this.sanctuaries = []; + this.leftSanctuaries = 0; } generateWaves() { @@ -114,57 +117,70 @@ class BossRush { while (points > 0 && choices.length) { choices = choices.filter(([ cost ]) => cost <= points); + if (!choices.length) break; let [ cost, boss ] = ran.choose(choices); points -= cost; wave.push(boss); } - waves.push(c.CLASSIC_SIEGE ? this.waveCodes[i] : wave); + waves.push(Config.CLASSIC_SIEGE ? this.waveCodes[i] : wave); } return waves; } spawnFriendlyBoss() { let o = new Entity(getSpawnableArea(TEAM_BLUE)); - o.define(ran.choose(this.friendlyBossChoices)); + let type = this.friendlyBossChoices[ran.chooseChance(...this.friendlyBossChoices.map((x) => x[0]))][1] + o.define(type); o.define({ DANGER: 10 }); o.team = TEAM_BLUE; o.controllers.push(new ioTypes.nearestDifferentMaster(o), new ioTypes.wanderAroundMap(0, { lookAtGoal: true })); + o.name = ran.chooseBossName('castle'); + o.FOV = 10; + o.settings.broadcastMessage = `${o.name} has fallen!`; sockets.broadcast(o.name + ' has arrived and joined your team!'); } spawnSanctuary(tile, team, type = false) { - type = type ? type : Class.sanctuaryTier3; + type = type ? type : "sanctuaryTier3"; let o = new Entity(tile.loc); - o.define(type); - o.team = team; - o.color.base = getTeamColor(team); - o.skill.score = 111069; - o.name = 'Sanctuary'; - o.SIZE = room.tileWidth / 10; - o.isDominator = true; + this.defineSanctuary(o, team, type); + this.sanctuaries.push(o); + let spawnableTeam = room.spawnable[Object.keys(room.spawnable).find((key) => room.spawnable[key].includes(tile))]; o.on('dead', () => { - /*let isAC; - for (let instance of o.collisionArray) { - if (TEAM_ROOM !== instance.team && instance.type !== 'food' && instance.type !== 'wall') { - isAC = true; - } - } - if (isAC) { - tile.color = 'white'; - } else */if (o.team === TEAM_ENEMIES) { - this.spawnSanctuary(tile, TEAM_BLUE, Class.sanctuaryTier3); + if (o.team === TEAM_ENEMIES) { + this.spawnSanctuary(tile, TEAM_BLUE, `sanctuaryTier${this.sanctuaryTier}`); tile.color.interpret(getTeamColor(TEAM_BLUE)); - sockets.broadcast('A sanctuary has been repaired!'); + this.leftSanctuaries++; + sockets.broadcast('A sanctuary has been repaired! ' + this.leftSanctuaries + ' sanctuaries remain.'); + if (team !== spawnableTeam) { // Allow the player to spawn so we add it to the spawnable locations. + room.spawnable[TEAM_BLUE].push(tile); + } } else { - this.spawnSanctuary(tile, TEAM_ENEMIES, Class.dominator); + this.spawnSanctuary(tile, TEAM_ENEMIES, "dominator"); tile.color.interpret(getTeamColor(TEAM_ENEMIES)); - sockets.broadcast('A sanctuary has been destroyed!'); + this.leftSanctuaries--; + sockets.broadcast('A sanctuary has been destroyed! ' + this.leftSanctuaries + ' sanctuaries remain.'); + if (team !== spawnableTeam) { // Don't allow players to spawn at the destroyed sanctuary so we remove it from spawnable location. + util.remove(spawnableTeam, spawnableTeam.indexOf(tile)); + } } sockets.broadcastRoom(); }); } + defineSanctuary(entity, team, type) { + entity.define(type); + entity.team = team; + entity.color.base = getTeamColor(team); + entity.skill.score = 111069; + entity.name = 'Sanctuary'; + entity.SIZE = room.tileWidth / (Config.CLASSIC_SIEGE ? 10 : 17.5); + entity.isDominator = true; + entity.nameColor = "#ffffff"; + entity.define({ DANGER: 11 }); + } + playerWin() { if (this.gameActive) { this.gameActive = false; @@ -210,7 +226,7 @@ class BossRush { enemy.isBoss = true; } - if (!c.CLASSIC_SIEGE) { + if (!Config.CLASSIC_SIEGE) { //spawn fodder enemies for (let i = 0; i < this.waveId / 5; i++) { this.spawnEnemyWrapper(getSpawnableArea(TEAM_ENEMIES), ran.choose(this.bigFodderChoices)); @@ -224,6 +240,16 @@ class BossRush { setTimeout(() => this.spawnFriendlyBoss(), 5000); } } + + // Update sanctuary tiers + let newSancTier = Math.min(Math.floor(this.waveId / 5) + 1, 6); + if (newSancTier != this.sanctuaryTier) { + for (let sanc of this.sanctuaries) { + this.defineSanctuary(sanc, TEAM_BLUE, `sanctuaryTier${newSancTier}`); + } + sockets.broadcast(`The sanctuaries have upgraded to tier ${newSancTier}.`); + this.sanctuaryTier = newSancTier; + } } //runs once when the server starts @@ -231,7 +257,8 @@ class BossRush { Class.basic.UPGRADES_TIER_2.push("healer"); //TODO: filter out tiles that are not of sanctuary type for (let tile of room.spawnable[TEAM_BLUE]) { - this.spawnSanctuary(tile, TEAM_BLUE); + this.leftSanctuaries += 1; + this.spawnSanctuary(tile, TEAM_BLUE, "sanctuaryTier1"); } } diff --git a/server/modules/gamemodes/gamemodeLoop.js b/server/modules/gamemodes/gamemodeLoop.js index 544c03cff..df4e4e9f3 100644 --- a/server/modules/gamemodes/gamemodeLoop.js +++ b/server/modules/gamemodes/gamemodeLoop.js @@ -1,30 +1,49 @@ let bossRush; -if (c.SPECIAL_BOSS_SPAWNS) bossRush = new BossRush(); +if (Config.SPECIAL_BOSS_SPAWNS) bossRush = new BossRush(); let train; -if (c.TRAIN) train = new Train(); +if (Config.TRAIN) train = new Train(); let moon; -if (c.SPACE_MODE) moon = new Moon(); +if (Config.SPACE_MODE) moon = new Moon(); let hunt; -if (c.HUNT) hunt = new ManHunt(); +if (Config.HUNT) hunt = new ManHunt(); +let risk; +//if (Config.GOVERNMENTAL) risk = new Risk(); -if (c.MOTHERSHIP_LOOP) mothershipLoop.spawn(); -if (c.SPECIAL_BOSS_SPAWNS) bossRush.init(); -if (c.MAZE > 0) generateMaze(c.MAZE); +if (Config.MOTHERSHIP_LOOP) mothershipLoop.spawn(); +if (Config.SPECIAL_BOSS_SPAWNS) bossRush.init(); +if (Config.MAZE > 0) generateMaze(Config.MAZE); -let logger = new LagLogger(); +// Below maze generation because it relies on the maze data +let portalLoop; +if (Config.PORTAL_SPAWNS) { + portalLoop = new PortalLoop(); + portalLoop.init(); +}; + +//if (Config.GOVERNMENTAL) risk.init(); + +let logHistory = []; const gamemodeLoop = function() { - logger.set(); - if (c.HUNT) hunt.loop(); - if (c.TRAIN) train.loop(); - if (c.SPACE_MODE) moon.loop(); - if (c.MOTHERSHIP_LOOP) mothershipLoop.loop(); - if (c.SPECIAL_BOSS_SPAWNS) bossRush.loop(); - logger.mark(); - if (logger.totalTime > 100) { + logs.gamemodeLoop.startTracking(); + if (Config.HUNT) hunt.loop(); + if (Config.TRAIN) train.loop(); + if (Config.SPACE_MODE) moon.loop(); + if (Config.MOTHERSHIP_LOOP) mothershipLoop.loop(); + if (Config.SPECIAL_BOSS_SPAWNS) bossRush.loop(); + logs.gamemodeLoop.endTracking(); + + let logTime = logs.gamemodeLoop.sumLogTimes(); + if (logTime > 100) { console.log("Gamemode loop is taking a long time!"); - console.log(`Gamemode loop took ${logger.totalTime}ms to complete!`); - console.log(`Gamemode loop log history: (Last ${logger.sum.length} entries)`); - console.log(logger.sum.map(entry => `Run at: ${entry.at}. Time: ${entry.time}.`).join("\n")); + console.log(`Gamemode loop took ${logTime}ms to complete!`); + console.log(`Gamemode loop log history: (Last ${logHistory.length} entries)`); + + logHistory.push({at: performance.now(), time: logTime}); + if (logHistory.length > 10) { + logHistory.shift(); + } + + console.log(logHistory.map(entry => `Run at: ${entry.at}. Time: ${entry.time}.`).join("\n")); } }; diff --git a/server/modules/gamemodes/groups.js b/server/modules/gamemodes/groups.js index c76c139d6..1c8f26670 100644 --- a/server/modules/gamemodes/groups.js +++ b/server/modules/gamemodes/groups.js @@ -13,7 +13,6 @@ class Group { this.private = false; this.teamID = getID(); activeGroups.push(this); - console.log("New group created."); } setPrivate() { if (this.private) this.private = false; @@ -33,7 +32,6 @@ class Group { delete() { for (let i = 0; i < this.members.length; i++) removeMember(this.members[i]); activeGroups = activeGroups.filter(entry => entry !== this); - console.log("Group deleted."); } getSpawn() { let validMembers = this.members.map(entry => entry).filter(a => !!a.player).filter(b => !!b.player.body); @@ -46,7 +44,7 @@ class Group { const addMember = (socket, party = -1) => { let group = activeGroups.find(entry => entry.members.length < entry.size); if (party !== -1) group = activeGroups.find(entry => (entry.teamID === party / room.partyHash && entry.members.length < entry.size)); - if (!group) group = new Group(c.GROUPS || 0); + if (!group) group = new Group(Config.GROUPS || 0); group.addMember(socket); }; diff --git a/server/modules/gamemodes/maze.js b/server/modules/gamemodes/maze.js index 5f78d1b7d..a9a3c097a 100644 --- a/server/modules/gamemodes/maze.js +++ b/server/modules/gamemodes/maze.js @@ -107,7 +107,7 @@ let checkMazeForBlocks = (initX, initY, size, maze) => { y: d.y }); o.define("wall"); - o.SIZE = d.s * 0.5 - 2; + o.SIZE = d.s * 0.5 / lazyRealSizes[4] * Math.SQRT2 - 2; o.team = TEAM_ENEMIES; o.protect(); o.life(); @@ -119,4 +119,6 @@ let checkMazeForBlocks = (initX, initY, size, maze) => { } }; -module.exports = { generateMaze }; \ No newline at end of file +if (!global.generateMaze) { + module.exports = { generateMaze }; +} \ No newline at end of file diff --git a/server/modules/gamemodes/moon.js b/server/modules/gamemodes/moon.js index 37d6637b5..f13b27255 100644 --- a/server/modules/gamemodes/moon.js +++ b/server/modules/gamemodes/moon.js @@ -11,7 +11,7 @@ class Moon { loop () { let players = entities.filter(r => r.isPlayer || r.isBot); for (let entity of players) { - if (entity.id != this.moon.id && !entity.ac && entity.alpha) { + if (entity.id != this.moon.id && !entity.isArenaCloser && entity.alpha) { entity.velocity.x += util.clamp(this.moon.x - entity.x, -90, 90) * entity.damp * 0.02; entity.velocity.y += util.clamp(this.moon.y - entity.y, -90, 90) * entity.damp * 0.02; } diff --git a/server/modules/gamemodes/mothership.js b/server/modules/gamemodes/mothership.js index 2e7393fe8..2185b40cd 100644 --- a/server/modules/gamemodes/mothership.js +++ b/server/modules/gamemodes/mothership.js @@ -5,31 +5,31 @@ let choices = ['mothership']; function spawn() { let locs = [{ - x: c.WIDTH * 0.1, - y: c.HEIGHT * 0.1 + x: Config.WIDTH * 0.1, + y: Config.HEIGHT * 0.1 }, { - x: c.WIDTH * 0.9, - y: c.HEIGHT * 0.9 + x: Config.WIDTH * 0.9, + y: Config.HEIGHT * 0.9 }, { - x: c.WIDTH * 0.9, - y: c.HEIGHT * 0.1 + x: Config.WIDTH * 0.9, + y: Config.HEIGHT * 0.1 }, { - x: c.WIDTH * 0.1, - y: c.HEIGHT * 0.9 + x: Config.WIDTH * 0.1, + y: Config.HEIGHT * 0.9 }, { - x: c.WIDTH * 0.9, - y: c.HEIGHT * 0.5 + x: Config.WIDTH * 0.9, + y: Config.HEIGHT * 0.5 }, { - x: c.WIDTH * 0.1, - y: c.HEIGHT * 0.5 + x: Config.WIDTH * 0.1, + y: Config.HEIGHT * 0.5 }, { - x: c.WIDTH * 0.5, - y: c.HEIGHT * 0.9 + x: Config.WIDTH * 0.5, + y: Config.HEIGHT * 0.9 }, { - x: c.WIDTH * 0.5, - y: c.HEIGHT * 0.1 + x: Config.WIDTH * 0.5, + y: Config.HEIGHT * 0.1 }].sort(() => 0.5 - Math.random()); - for (let i = 0; i < c.TEAMS; i++) { + for (let i = 0; i < Config.TEAMS; i++) { let o = new Entity(locs[i]), team = -i - 1; o.define(ran.choose(choices)); diff --git a/server/modules/gamemodes/oldDreadnoughts.js b/server/modules/gamemodes/oldDreadnoughts.js new file mode 100644 index 000000000..4f05734f4 --- /dev/null +++ b/server/modules/gamemodes/oldDreadnoughts.js @@ -0,0 +1,326 @@ +// Labyrinth generation +let validPositions; +let generateLabyrinth = (size) => { + const padding = 1; + + let maze = JSON.parse(JSON.stringify(Array(size).fill(Array(size).fill(true)))); + validPositions = JSON.parse(JSON.stringify(Array(size + padding * 2).fill(Array(size + padding * 2).fill(true)))) + let bfsqx = [1]; + let bfsqy = [1]; + let intermediateQX = [1]; + let intermediateQY = [1]; + const offsets = [0, 1, 0, -1, 0]; + let mazeWallScale = room.height / (size + 2 * padding); + + while (bfsqx.length) { + // Delete walls where the search travels + let currentX = bfsqx.shift(); + let currentY = bfsqy.shift(); + let intermediateX = intermediateQX.shift(); + let intermediateY = intermediateQY.shift(); + if (!maze[currentY][currentX]) continue; + maze[currentY][currentX] = false; + if (intermediateX && intermediateY) maze[intermediateX][intermediateY] = false; + + let options = []; + for (let i = 0; i < 4; i++) { + // Move between grid cells + let newX = currentX + offsets[i] * 2; + let newY = currentY + offsets[i+1] * 2; + + // Punch holes in the walls to reach the outer edge + if (newX < 0 || newX >= size || newY < 0 || newY >= size) { + if (ran.random(1) < 0.25) { + maze[currentY + offsets[i+1]][currentX + offsets[i]] = false; + } + continue; + } + if (!maze[newY][newX]) continue; + options.push([newX, newY]); + } + + if (!options.length) continue; + + // Pick where to go + shuffledOptions = []; + while (options.length) { + let index = Math.floor(ran.random(options.length)); + shuffledOptions.push([...options[index]]); + options.splice(index, 1); + } + + // Save all options on where to go so we can come back to them later + bfsqx.unshift(...shuffledOptions.map((x) => x[0])); + bfsqy.unshift(...shuffledOptions.map((x) => x[1])); + intermediateQX.unshift(...shuffledOptions.map((x) => (x[0] + currentX) / 2)); + intermediateQY.unshift(...shuffledOptions.map((x) => (x[1] + currentY) / 2)); + } + + // Make the maze more interconnected by randomly removing walls + for (let x = 1; x < size; x += 2) { + for (let y = 1; y < size; y += 2) { + for (let i = 0; i < 4; i++) { + let nextX = x + offsets[i]; + let nextY = y + offsets[i + 1]; + if (ran.random(1) < 0.9) continue; + maze[nextY][nextX] = false; + } + } + } + + // Punch holes in the maze + const holeCenters = [ + [5, 5], + [5, 25], + [25, 5], + [25, 25], + [15, 15], + ]; + const holeRadius = 2; + for (let [centerX, centerY] of holeCenters) { + for (let x = centerX - holeRadius; x <= centerX + holeRadius; x++) { + for (let y = centerY - holeRadius; y <= centerY + holeRadius; y++) { + maze[y][x] = false; + } + } + } + + // Open permanant corridors + const corridors = [7, 23]; + for (let y of corridors) { + for (let x = corridors[0]; x <= corridors[1]; x++) { + maze[y][x] = false; + maze[x][y] = false; + } + } + + // Spawn the maze + for (let x = padding; x < size + padding; x++) { + for (let y = padding; y < size + padding; y++) { + // Find spawn location and size + if (!maze[y - 1][x - 1]) continue; + + let d = { + x: x * mazeWallScale + mazeWallScale / 2, + y: y * mazeWallScale + mazeWallScale / 2, + }; + + if (!room.getAt(d).data.allowMazeWallSpawn) continue; + + let o = new Entity({ + x: d.x, + y: d.y + }); + o.define("wall"); + o.SIZE = mazeWallScale * 0.5 / lazyRealSizes[4] * Math.SQRT2 - 2; + o.team = TEAM_ENEMIES; + o.protect(); + o.life(); + makeHitbox(o); + walls.push(o); + validPositions[y][x] = false; + } + } + + // Convert valid positions + let truePositions = []; + for (let y = 0; y < size + 2 * padding; y++) { + for (let x = 0; x < size + 2 * padding; x++) { + if (!validPositions[y][x]) continue; + let trueX = x * mazeWallScale + mazeWallScale / 2; + let trueY = y * mazeWallScale + mazeWallScale / 2; + truePositions.push([trueX, trueY]); + } + } + validPositions = truePositions; + + // Big food + // Class.sphere.SIZE = 17; + // Class.cube.SIZE = 22; + // Class.tetrahedron.SIZE = 27; + // Class.octahedron.SIZE = 28; + // Class.dodecahedron.SIZE = 30; + // Class.icosahedron.SIZE = 32; + // Class.tesseract.SIZE = 39; + delete Class.food.LEVEL_CAP; +} + +// Portal loop +class PortalLoop { + constructor() { + this.initialized = false; + this.spawnBuffer = 50; + this.openBounds = { + xMin: 19500, + xMax: 25500, + yMin: 1500, + yMax: 7500, + }; + this.labyrinthBounds = { + xMin: 50, + xMax: 8950, + yMin: 50, + yMax: 8950, + }; + this.forgeBounds = { + xMin: 11500, + xMax: 15500, + yMin: 2500, + yMax: 6500, + }; + this.locationArrayVariance = 80; + this.readyToSpawn = true; + this.spawnBatches = [ + { + bounds: this.labyrinthBounds, + types: [ + { + type: "spikyPortalOfficialV1", + destination: this.openBounds, + buffer: 1500, + spawnArray: validPositions, + handler: (entity) => { + // Spawn in default spawnable area if on a tank team + if (entity.team == TEAM_DREADNOUGHTS) return; + let {x, y} = getSpawnableArea(entity.team); + entity.x = x; + entity.y = y; + } + }, + { + type: "bluePortalOfficialV1", + destination: this.forgeBounds, + buffer: 0, + spawnArray: validPositions, + handler: (entity) => { + if (entity.team == TEAM_DREADNOUGHTS) return; + + entity.reset(); // Remove non-player controllers + entity.skill.set(Array(10).fill(0)); // Purge skill upgrades + entity.define({ // Purge all unwanted entity config + STAT_NAMES: {}, + IS_SMASHER: false, + ALPHA: [0, 1], + INVISIBLE: [0, 0], + }); + entity.upgrades = []; + entity.define('dreadOfficialV1'); + entity.team = TEAM_DREADNOUGHTS; + + // Fix minimap + if (entity.socket) { + entity.socket.player.team = entity.team; + } + }, + entryBarrier: (entity) => { + return entity.skill.level >= 150; + } + } + ] + }, + { + bounds: this.openBounds, + types: [ + { + type: "spikyPortalOfficialV1", + destination: this.labyrinthBounds, + buffer: 50, + destinationArray: validPositions, + } + ] + }, + { + bounds: this.forgeBounds, + types: [ + { + type: "spikyPortalOfficialV1", + destination: this.labyrinthBounds, + buffer: 50, + destinationArray: validPositions, + }, + { + type: "greenPortalOfficialV1", + destination: this.openBounds, + buffer: 1500, + } + ] + }, + ] + } + spawnCycle() { + this.readyToSpawn = true; + for (let batch of this.spawnBatches) { + for (let portal of batch.types) { + let spawnX, spawnY; + if (portal.spawnArray) { + let [x, y] = ran.choose(portal.spawnArray); + spawnX = x + ran.irandomRange(-this.locationArrayVariance, this.locationArrayVariance); + spawnY = y + ran.irandomRange(-this.locationArrayVariance, this.locationArrayVariance); + } else { + spawnX = ran.irandomRange(batch.bounds.xMin, batch.bounds.xMax); + spawnY = ran.irandomRange(batch.bounds.yMin, batch.bounds.yMax); + } + let entity = new Entity({x: spawnX, y: spawnY}); + entity.define(portal.type); + entity.on('collide', ({instance, other}) => { + // Swap order if the portal is the 'other' in the pair + if (other.type == 'portal') other = instance; + + // Validity checking + if (other.type != 'tank') { + if ( + other.type != "miniboss" && other.type != "food" && other.type != "crasher" && other.type != "aura" && other.type != "wall" && other.type != "unknown" && + (other.x - entity.x) ** 2 + (other.y - entity.y) ** 2 <= (other.size + entity.size) ** 2 + ) { + other.kill(); + } + return; + } + if (other.invuln) return; + if ((other.x - entity.x) ** 2 + (other.y - entity.y) ** 2 > (other.size ** 2)) return; + if (portal.entryBarrier && !portal.entryBarrier(other)) return; + + // Spawn in target region + if (portal.destinationArray) { + let [x, y] = ran.choose(portal.destinationArray); + other.x = x + ran.irandomRange(-this.locationArrayVariance, this.locationArrayVariance); + other.y = y + ran.irandomRange(-this.locationArrayVariance, this.locationArrayVariance); + } else { + other.x = ran.irandomRange(portal.destination.xMin, portal.destination.xMax); + other.y = ran.irandomRange(portal.destination.yMin, portal.destination.yMax); + } + other.invuln = true; + other.destroyAllChildren(); + + // Set new confinement + other.confinement.xMin = portal.destination.xMin - portal.buffer; + other.confinement.xMax = portal.destination.xMax + portal.buffer; + other.confinement.yMin = portal.destination.yMin - portal.buffer; + other.confinement.yMax = portal.destination.yMax + portal.buffer; + + // Special portal properties + if (portal.handler) { + portal.handler(other); + } + }); + entity.on('death', ({body}) => { + if (arenaClosed || !this.readyToSpawn) return; + + // Spawn after 20 seconds if a portal dies + this.readyToSpawn = false; + setTimeout(() => { + this.spawnCycle(); + }, 20_000); + }); + } + } + } + init() { + this.spawnCycle(); + } +} + +if (Config.GAME_MODES.includes('old_dreadnoughts')) { + global.generateMaze = generateLabyrinth; +} +module.exports = { generateLabyrinth, PortalLoop }; \ No newline at end of file diff --git a/server/modules/gamemodes/risk.js b/server/modules/gamemodes/risk.js new file mode 100644 index 000000000..40347b536 --- /dev/null +++ b/server/modules/gamemodes/risk.js @@ -0,0 +1,80 @@ +let neededToWin = 83, + teamcounts = {}, + gameWon = false; + +class Risk { +spawnSanctuary(tile, team) { + let o = new Entity(tile.loc); + o.define(Class.trapperDominator); + o.team = team; + o.color.base = getTeamColor(team); + o.skill.score = 111069; + o.name = 'Sanctuary'; + o.SIZE = room.tileWidth / 10; + o.isDominator = true; + o.on('dead', () => { + + teamcounts[team]--; + if (!teamcounts[team]) { + delete teamcounts[team]; + } + + let killers = []; + for (let instance of o.collisionArray) { + if (isPlayerTeam(instance.team) && team !== instance.team) { + killers.push(instance); + } + } + + let killer = ran.choose(killers); + killer = killer ? killer.master.master : { team: TEAM_BLUE, color: Config.MODE === "tdm" ? 3 : 12 }; + + let newTeam = killer.team, + newColor = getTeamColor(newTeam); + + for (let player of sockets.players) { + if (player.body && player.body.team === newTeam) { + player.body.sendMessage("Press F to take control of the dominator."); + } + } + + let teamName = newTeam > 0 ? killer.name : getTeamName(newTeam); + sockets.broadcast(`A dominator is now controlled by ${teamName}!`); + if (teamcounts[newTeam] >= neededToWin && !gameWon) { + gameWon = true; + setTimeout(sockets.broadcast, 1500, teamName + " has won the game!"); + setTimeout(closeArena, 4500); + } + + this.spawnSanctuary(tile, newTeam); + sockets.broadcastRoom(); + }); + } + + playerWin() { + if (this.gameActive) { + this.gameActive = false; + sockets.broadcast(getTeamName(TEAM_BLUE) + ' has won the game!'); + setTimeout(closeArena, 1500); + } + } + //runs once when the server starts + init() { + Class.basic.UPGRADES_TIER_2.push("healer"); + //TODO: filter out tiles that are not of sanctuary type + for (let tile of room.spawnable[TEAM_BLUE]) { + this.spawnSanctuary(tile, TEAM_BLUE); + } + for (let tile of room.spawnable[TEAM_GREEN]) { + this.spawnSanctuary(tile, TEAM_GREEN); + } + for (let tile of room.spawnable[TEAM_RED]) { + this.spawnSanctuary(tile, TEAM_RED); + } + for (let tile of room.spawnable[TEAM_PURPLE]) { + this.spawnSanctuary(tile, TEAM_PURPLE); + } + } +} + +module.exports = { Risk }; \ No newline at end of file diff --git a/server/modules/gamemodes/tag.js b/server/modules/gamemodes/tag.js index dce1400bd..1a1b2dc43 100644 --- a/server/modules/gamemodes/tag.js +++ b/server/modules/gamemodes/tag.js @@ -4,7 +4,7 @@ function checkWin() { if (won) return; let all = 0, teams = {}; - for (let i = 1; i <= c.TEAMS; i++) { + for (let i = 1; i <= Config.TEAMS; i++) { teams[-i] = 0; } for (let i = 0; i < entities.length; i++) { @@ -27,24 +27,20 @@ function checkWin() { setTimeout(closeArena, 3000); } -function init(g) { - g.events.on('spawn', entity => { - entity.on('dead', () => { - if (!c.TAG || !entity.isPlayer && !entity.isBot) return; - let killers = []; - for (let entry of entity.collisionArray) { - if (isPlayerTeam(entry.team) && entity.team !== entry.team) { - killers.push(entry); - } +Events.on('spawn', entity => { + entity.on('dead', () => { + if (!Config.TAG || !entity.isPlayer && !entity.isBot) return; + let killers = []; + for (let entry of entity.collisionArray) { + if (isPlayerTeam(entry.team) && entity.team !== entry.team) { + killers.push(entry); } - if (!killers.length) return; - let killer = ran.choose(killers); - if (entity.socket) { - entity.socket.rememberedTeam = killer.team; - } - setTimeout(checkWin, 1000); - }); + } + if (!killers.length) return; + let killer = ran.choose(killers); + if (entity.socket) { + entity.socket.rememberedTeam = killer.team; + } + setTimeout(checkWin, 1000); }); -} - -module.exports = { init }; \ No newline at end of file +}); \ No newline at end of file diff --git a/server/modules/global.js b/server/modules/global.js index bb0c618fc..da4b0f24d 100644 --- a/server/modules/global.js +++ b/server/modules/global.js @@ -1,6 +1,9 @@ +// Prepare constants +Math.TAU = Math.PI * 2; + // Global Utilities Requires let EventEmitter = require('events'); -global.events = new EventEmitter(); +global.Events = new EventEmitter(); global.ran = require(".././lib/random.js"); global.util = require(".././lib/util.js"); global.hshg = require(".././lib/hshg.js"); @@ -27,15 +30,16 @@ global.TEAM_YELLOW = -5; global.TEAM_ORANGE = -6; global.TEAM_BROWN = -7; global.TEAM_CYAN = -8; +global.TEAM_DREADNOUGHTS = -10; global.TEAM_ROOM = -100; global.TEAM_ENEMIES = -101; global.getSpawnableArea = team => ran.choose((team in room.spawnable && room.spawnable[team].length) ? room.spawnable[team] : room.spawnableDefault).randomInside(); -global.getTeamName = team => ["BLUE", "GREEN", "RED", "PURPLE", "YELLOW", "ORANGE", "BROWN", "CYAN"][-team - 1] || "An unknown team"; -global.getTeamColor = team => ([10, 11, 12, 15, 25, 26, 27, 28][-team - 1] || 3); -global.isPlayerTeam = team => /*team < 0 && */team > -9; +global.getTeamName = team => ["BLUE", "GREEN", "RED", "PURPLE", "YELLOW", "ORANGE", "BROWN", "CYAN", , "DREADNOUGHTS"][-team - 1] ?? "An unknown team"; +global.getTeamColor = team => ([10, 11, 12, 15, 25, 26, 27, 28, , 4][-team - 1] ?? 3); +global.isPlayerTeam = team => /*team < 0 && */team > -11; global.getWeakestTeam = () => { let teamcounts = {}; - for (let i = -c.TEAMS; i < 0; i++) { + for (let i = -Config.TEAMS; i < 0; i++) { teamcounts[i] = 0; } for (let o of entities) { @@ -46,10 +50,13 @@ global.getWeakestTeam = () => { teamcounts[o.team]++; } } - teamcounts = Object.entries(teamcounts); + teamcounts = Object.entries(teamcounts).map(([teamId, amount]) => { + let weight = teamId in Config.TEAM_WEIGHTS ? Config.TEAM_WEIGHTS[teamId] : 1; + return [teamId, amount / weight]; + }); let lowestTeamCount = Math.min(...teamcounts.map(x => x[1])), entries = teamcounts.filter(a => a[1] == lowestTeamCount); - return parseInt(!entries.length ? -Math.ceil(Math.random() * c.TEAMS) : ran.choose(entries)[0]); + return parseInt(!entries.length ? -Math.ceil(Math.random() * Config.TEAMS) : ran.choose(entries)[0]); }; global.Tile = class Tile { @@ -80,15 +87,16 @@ global.tickEvents = new EventEmitter(); global.syncedDelaysLoop = () => tickEvents.emit(tickIndex++); global.setSyncedTimeout = (callback, ticks = 0, ...args) => tickEvents.once(tickIndex + Math.round(ticks), () => callback(...args)); +const lowercaseRegex = /[a-z]/, + uppercaseRegexG = /[A-Z]/g; function TO_SCREAMING_SNAKE_CASE(TEXT) { - if (/^[A-Z_]*[A-Z]$/.test(TEXT)) { - return TEXT; - } else if (/[a-zA-Z]+/.test(TEXT)) { - return TEXT.replace(/[A-Z]/g, _ => '_' + _).toUpperCase(); + if (lowercaseRegex.test(TEXT)) { + return TEXT.replace(uppercaseRegexG, _ => '_' + _).toUpperCase(); } + return TEXT; } -global.c = new Proxy(new EventEmitter(), { +global.Config = new Proxy(new EventEmitter(), { get (obj, prop) { return obj[TO_SCREAMING_SNAKE_CASE(prop)]; }, @@ -96,7 +104,7 @@ global.c = new Proxy(new EventEmitter(), { let abort; prop = TO_SCREAMING_SNAKE_CASE(prop); - events.emit('change', { + obj.emit('change', { setting: prop, newValue: value, oldValue: obj[prop], @@ -108,14 +116,13 @@ global.c = new Proxy(new EventEmitter(), { } } }); -global.c.port = process.env.PORT; -global.Config = global.c; +global.Config.port = process.env.PORT; for (let [key, value] of Object.entries(require('./setup/config.js'))) { if (key in EventEmitter.prototype) { util.warn(`Configuration contains "${key}", which is in 'EventEmitter.prototype' and its value is therefore discarded.`); } else { - global.c[key] = value; + global.Config[key] = value; } } @@ -168,13 +175,14 @@ const requires = [ "./live/controllers.js", // The AI of the game. "./live/entity.js", // The actual Entity constructor. "./definitions/combined.js", // Class dictionary. - "./setup/room.js", // These are the basic room functions, set up by config.json "./network/sockets.js", // The networking that helps players interact with the game. "./network/webServer.js", // The networking that actually hosts the server. - "./setup/mockups.js", // This file loads the mockups. "./debug/logs.js", // The logging pattern for the game. Useful for pinpointing lag. "./debug/speedLoop.js", // The speed check loop lmao. + "./setup/room.js", // These are the basic room functions, set up by config.json + "./setup/mockups.js", // This file loads the mockups. "./gamemodes/bossRush.js", // Boss Rush + "./gamemodes/oldDreadnoughts.js", // Old Dreadnoughts "./gamemodes/maze.js", // Maze "./gamemodes/mothership.js", // The mothership mode "./gamemodes/manhunt.js", // The Manhunt mode @@ -188,7 +196,6 @@ const requires = [ for (let file of requires) { const module = require(file); - if (module.init) module.init(global); for (let key in module) { if (module.hasOwnProperty(key)) global[key] = module[key]; } diff --git a/server/modules/live/color.js b/server/modules/live/color.js index c635208c3..969919e80 100644 --- a/server/modules/live/color.js +++ b/server/modules/live/color.js @@ -38,11 +38,11 @@ class Color { this.#base = color; break; case 'object': - this.#base = color.BASE ?? color.base ?? 16; - this.#hueShift = color.HUE_SHIFT ?? color.hueShift ?? 0; - this.#saturationShift = color.SATURATION_SHIFT ?? color.saturationShift ?? 1; - this.#brightnessShift = color.BRIGHTNESS_SHIFT ?? color.brightnessShift ?? 0; - this.#allowBrightnessInvert = color.ALLOW_BRIGHTNESS_INVERT ?? color.allowBrightnessInvert ?? false; + this.#base = color.BASE ?? color.base ?? this.#base ?? 16; + this.#hueShift = color.HUE_SHIFT ?? color.hueShift ?? this.#hueShift ?? 0; + this.#saturationShift = color.SATURATION_SHIFT ?? color.saturationShift ?? this.#saturationShift ?? 1; + this.#brightnessShift = color.BRIGHTNESS_SHIFT ?? color.brightnessShift ?? this.#brightnessShift ?? 0; + this.#allowBrightnessInvert = color.ALLOW_BRIGHTNESS_INVERT ?? color.allowBrightnessInvert ?? this.#allowBrightnessInvert ?? false; break; case 'string': if (!color.includes(" ")) { diff --git a/server/modules/live/controllers.js b/server/modules/live/controllers.js index c35c02960..dc9b464f7 100644 --- a/server/modules/live/controllers.js +++ b/server/modules/live/controllers.js @@ -149,22 +149,26 @@ class io_moveInCircles extends IO { constructor(body) { super(body) this.acceptsFromTop = false - this.timer = ran.irandom(10) + 3 + this.timer = ran.irandom(5) + 3 + this.pathAngle = ran.random(2 * Math.PI); this.goal = { - x: this.body.x + 10 * Math.cos(-this.body.facing), - y: this.body.y + 10 * Math.sin(-this.body.facing) + x: this.body.x + 10 * Math.cos(this.pathAngle), + y: this.body.y + 10 * Math.sin(this.pathAngle) } } think() { - if (!(this.timer--)) { - this.timer = 10 + if (!this.timer--) { + this.timer = 5 this.goal = { - x: this.body.x + 10 * Math.cos(-this.body.facing), - y: this.body.y + 10 * Math.sin(-this.body.facing) + x: this.body.x + 10 * Math.cos(this.pathAngle), + y: this.body.y + 10 * Math.sin(this.pathAngle) } + // turnWithSpeed turn speed (but condensed over 5 ticks) + this.pathAngle -= ((this.body.velocity.length / 90) * Math.PI) / Config.runSpeed * 5; } return { - goal: this.goal + goal: this.goal, + power: this.body.ACCELERATION > 0.1 ? 0.2 : 1 } } } @@ -177,6 +181,7 @@ class io_listenToPlayer extends IO { this.acceptsFromTop = false; this.normalFacingType = null; + this.normalFacingTypeArgs = null; this.wasAutospinning = false; this.isAutospinning = false; } @@ -198,19 +203,21 @@ class io_listenToPlayer extends IO { this.isAutospinning = this.player.command.autospin; if (this.isAutospinning && !this.wasAutospinning) { // Save facing type for later - this.normalFacingType = [...this.body.facingType]; + this.normalFacingType = this.body.facingType; + this.normalFacingTypeArgs = this.body.facingTypeArgs; + this.body.facingType = "spin"; this.wasAutospinning = true; } else if (!this.isAutospinning && this.wasAutospinning) { // Restore facing type from earlier - this.body.facingType = [...this.normalFacingType]; + this.body.facingType = this.normalFacingType; + this.body.facingTypeArgs = this.normalFacingTypeArgs; this.wasAutospinning = false; } // Define autospin facingType if (this.isAutospinning) { let speed = 0.05 * (alt ? -1 : 1) * this.body.autospinBoost; - this.body.facingType = ["spin", {speed}]; + this.body.facingTypeArgs = {speed}; } - this.body.autoOverride = this.player.command.override; if (this.body.invuln && (fire || alt)) this.body.invuln = false; return { @@ -218,8 +225,8 @@ class io_listenToPlayer extends IO { fire, alt, goal: this.static ? null : { - x: this.body.x + this.player.command.right - this.player.command.left, - y: this.body.y + this.player.command.down - this.player.command.up, + x: this.body.x + this.player.command.movement.x, + y: this.body.y + this.player.command.movement.y, }, main: fire, }; @@ -385,31 +392,30 @@ class io_onlyAcceptInArc extends IO { class io_stackGuns extends IO { constructor(body, opts = {}) { super(body); - this.timeUntilFire = opts.timeUntilFire || 0; + this.stackAtTime = opts.stackAtTime || 0.2; } think ({ target }) { - //why even bother? if (!target) { return; } //find gun that is about to shoot - let lowestReadiness = Infinity, + let lowestTimeToFire = Infinity, readiestGun; for (let i = 0; i < this.body.guns.length; i++) { let gun = this.body.guns[i]; if (!gun.canShoot || !gun.stack) continue; - let reloadStat = (gun.calculator == "necro" || gun.calculator == "fixed reload") ? 1 : (gun.bulletStats === "master" ? this.body.skill : gun.bulletStats).rld, - readiness = (1 - gun.cycle) / (gun.settings.reload * reloadStat); - if (lowestReadiness > readiness) { - lowestReadiness = readiness; + + let timeToFire = (1 - gun.cycleTimer) / (gun.shootSettings.reload * gun.reloadRateFactor * Config.runSpeed); + if (lowestTimeToFire > timeToFire) { + lowestTimeToFire = timeToFire; readiestGun = gun; } } //if we aren't ready, don't spin yet - if (!readiestGun || (this.timeUntilFire && this.timeUntilFire > lowestReadiness)) { + if (!readiestGun || (this.stackAtTime && lowestTimeToFire > this.stackAtTime)) { return; } @@ -447,7 +453,9 @@ class io_nearestDifferentMaster extends IO { (this.body.aiSettings.BLIND || ((e.x - m.x) * (e.x - m.x) < sqrRange && (e.y - m.y) * (e.y - m.y) < sqrRange)) && (this.body.aiSettings.SKYNET || ((e.x - mm.x) * (e.x - mm.x) < sqrRangeMaster && (e.y - mm.y) * (e.y - mm.y) < sqrRangeMaster)); } - wouldHitWall = (me, enemy) => wouldHitWall(me, enemy); // Override + wouldHitWall (me, enemy) { + wouldHitWall(me, enemy); // Override + } buildList(range) { // Establish whom we judge in reference to let mostDangerous = 0, @@ -510,7 +518,7 @@ class io_nearestDifferentMaster extends IO { this.tick = 100; } // Think damn hard - if (this.tick++ > 15 * c.runSpeed) { + if (this.tick++ > 15 * Config.runSpeed) { this.tick = 0; this.validTargets = this.buildList(range); // Ditch our old target if it's invalid @@ -673,7 +681,7 @@ class io_hangOutNearMaster extends IO { } think(input) { if (this.body.invisible[1]) return {} - if (this.body.source !== this.body) { + if (this.body.source.id !== this.body.id) { let bound1 = this.orbit * 0.8 + this.body.source.size + this.body.size let bound2 = this.orbit * 1.5 + this.body.source.size + this.body.size let dist = util.getDistance(this.body, this.body.source) + Math.PI / 8; @@ -717,7 +725,7 @@ class io_spin extends IO { this.a = Math.atan2(input.target.y, input.target.x); return input; } - this.a += this.speed / c.runSpeed; + this.a += this.speed / Config.runSpeed; let offset = (this.independent && this.body.bond != null) ? this.body.bound.angle : 0; return { target: { @@ -739,16 +747,18 @@ class io_spin2 extends IO { // On spawn logic let alt = this.body.master.control.alt; let reverse = (this.reverseOnAlt && alt) ? -1 : 1; - this.body.facingType = ["spin", {speed: this.speed * reverse}]; + this.body.facingType = "spin"; + this.body.facingTypeArgs = {speed: this.speed * reverse}; } think(input) { - if (!this.reverseOnTheFly) return; + if (!this.reverseOnTheFly || !this.reverseOnAlt) return; // Live logic let alt = this.body.master.control.alt; if (this.lastAlt != alt) { - let reverse = (this.reverseOnAlt && alt) ? -1 : 1; - this.body.facingType = ["spin", {speed: this.speed * reverse}]; + let reverse = alt ? -1 : 1; + this.body.facingType = "spin"; + this.body.facingTypeArgs = {speed: this.speed * reverse}; this.lastAlt = alt; } } @@ -837,7 +847,7 @@ class io_formulaTarget extends IO { // this.originAngle = this.masterAngle ? b.master.facing : getTheGunThatSpawnedMe("how do i do that????").angle; // } - let angle = this.originAngle + this.formula(this.frame += 1 / c.runSpeed, this.body); + let angle = this.originAngle + this.formula(this.frame += 1 / Config.runSpeed, this.body); return { goal: { x: this.body.x + Math.sin(angle), @@ -902,6 +912,40 @@ class io_orbit extends IO { this.body.facing = angle; } } +class io_snake extends IO { + constructor(body, opts = {}) { + super(body); + this.waveInvert = opts.invert ? -1 : 1; + this.wavePeriod = opts.period ?? 5; + this.waveAmplitude = opts.amplitude ?? 150; + this.yOffset = opts.yOffset ?? 0; + + this.reverseWave = this.body.master.control.alt ? -1 : 1; + this.velocityMagnitude = 0; + this.body.damp = 0; + this.waveAngle = this.body.master.facing + (opts.angle ?? 0); + this.startX = this.body.x; + this.startY = this.body.y; + this.body.x += Math.cos(this.body.velocity.direction) * this.body.size * 20; + this.body.y += Math.sin(this.body.velocity.direction) * this.body.size * 20; + // Clamp scale to [45, 75] + // Attempts to get the bullets to intersect with the cursor + this.waveHorizontalScale = util.clamp(util.getDistance(this.body.master.master.control.target, {x: 0, y: 0}) / Math.PI, 45, 75); + } + think(input) { + // Define a sin wave for the bullet to follow + let waveX = this.waveHorizontalScale * (this.body.RANGE - this.body.range) / this.wavePeriod; + let waveY = this.waveAmplitude * Math.sin(waveX / this.waveHorizontalScale) * this.waveInvert * this.reverseWave + this.yOffset; + // Rotate the sin wave + let trueWaveX = Math.cos(this.waveAngle) * waveX - Math.sin(this.waveAngle) * waveY; + let trueWaveY = Math.sin(this.waveAngle) * waveX + Math.cos(this.waveAngle) * waveY; + // Follow the sin wave + this.body.x = util.lerp(this.body.x, this.startX + trueWaveX, this.velocityMagnitude); + this.body.y = util.lerp(this.body.y, this.startY + trueWaveY, this.velocityMagnitude); + // Accelerate after spawning + this.velocityMagnitude = Math.min(0.1, this.velocityMagnitude + 0.01 / Config.runSpeed) + } +} class io_disableOnOverride extends IO { constructor(body) { @@ -956,6 +1000,105 @@ class io_scaleWithMaster extends IO { } } } +class io_kiva extends IO { + constructor(b) { + super(b) + this.r = 0 + this.b = b + this.m = b.master + this.turnover = false + let len = 10 * util.getDistance({ + x: 0, + y: 0 + }, b.master.control.target) + this.myGoal = { + x: b.master.control.target.x + b.master.x, + y: b.master.control.target.y + b.master.y, + } + } + think(input) { + if (this.b.range > this.r) this.r = this.b.range + let t = 1; //1 - Math.sin(2 * Math.PI * this.b.range / this.r) || 1 + if (!this.turnover) { + if (this.r && this.b.range < this.r * 0.5) { + setTimeout(() => this.turnover = true, 500); + } + return { + goal: this.myGoal, + power: t, + } + } else { + let tomaster = util.getDistance(this.b, this.m); + if (tomaster < this.m.size) { + this.b.kill() + } + return { + goal: { + x: this.m.x, + y: this.m.y, + }, + power: t, + } + } + } +} +class io_hadron extends IO { + constructor(b, opts = {}) { + super(b) + this.a = opts.startAngle || 0; + this.speed = opts.speed ?? 0.04; + this.onlyWhenIdle = opts.onlyWhenIdle; + this.independent = opts.independent; + } + think(input) { + if (input.alt){ + if (this.onlyWhenIdle && input.target) { + this.a = Math.atan2(input.target.y, input.target.x); + return input; + } + this.a -= this.speed / Config.runSpeed; + let offset = (this.independent && this.body.bond != null) ? this.body.bound.angle : 0; + return { + target: { + x: Math.cos(this.a - offset), + y: Math.sin(this.a - offset) + }, + main: true, + }; + } else { + if (this.onlyWhenIdle && input.target) { + this.a = Math.atan2(input.target.y, input.target.x); + return input; + } + this.a += this.speed / Config.runSpeed; + let offset = (this.independent && this.body.bond != null) ? this.body.bound.angle : 0; + return { + target: { + x: Math.cos(this.a + offset), + y: Math.sin(this.a + offset), + }, + main: true, + }; + } + } +} +class io_AimAssist extends IO { + constructor(body) { + super(body); + } + think(input) { + this.body.velocity.x = 0; + this.body.velocity.y = 0; + if (!input.fire && !input.target) { + this.body.x = this.body.master.source.x; + this.body.y = this.body.master.source.y; + } + if (input.fire && input.target) { + this.body.x = this.body.x + input.target.x; + this.body.y = this.body.y + input.target.y; + } + } +} let ioTypes = { //misc @@ -973,6 +1116,8 @@ let ioTypes = { stackGuns: io_stackGuns, nearestDifferentMaster: io_nearestDifferentMaster, targetSelf: io_targetSelf, + hadron: io_hadron, + AimAssist: io_AimAssist, onlyAcceptInArc: io_onlyAcceptInArc, spin: io_spin, spin2: io_spin2, @@ -987,10 +1132,13 @@ let ioTypes = { orbit: io_orbit, goToMasterTarget: io_goToMasterTarget, avoid: io_avoid, + snake: io_snake, + minion: io_minion, hangOutNearMaster: io_hangOutNearMaster, fleeAtLowHealth: io_fleeAtLowHealth, wanderAroundMap: io_wanderAroundMap, + kiva: io_kiva, }; -module.exports = { ioTypes, IO }; +module.exports = { ioTypes, IO }; \ No newline at end of file diff --git a/server/modules/live/entity.js b/server/modules/live/entity.js index 162b5237b..f649430ca 100644 --- a/server/modules/live/entity.js +++ b/server/modules/live/entity.js @@ -1,47 +1,24 @@ +const { combineStats } = require('../definitions/facilitators'); + let EventEmitter = require('events'), events, init = g => events = g.events; -function setNatural(natural, type) { - type = ensureIsClass(type); - if (type.PARENT != null) { - if (typeof type.PARENT == 'string') setNatural(natural, type.PARENT) - else { - for (let i = 0; i < type.PARENT.length; i++) { - setNatural(natural, type.PARENT[i]); - } - } - } - if (type.BODY != null) { - for (let index in type.BODY) { - natural[index] = type.BODY[index]; - } - } -} -let lerp = (a, b, x) => a + x * (b - a); class Gun extends EventEmitter { constructor(body, info) { super(); this.id = entitiesIdLog++; - this.ac = false; this.lastShot = { time: 0, power: 0 }; this.body = body; + this.ignorecanshootchecks = false; this.master = body.source; this.label = ""; this.identifier = ""; - this.controllers = []; this.children = []; // Stored Variables this.globalStore = {} this.store = {} // ---------------- - this.control = { - target: new Vector(0, 0), - goal: new Vector(0, 0), - main: false, - alt: false, - fire: false, - }; this.color = new Color({ BASE: "grey", HUE_SHIFT: 0, @@ -52,52 +29,43 @@ class Gun extends EventEmitter { this.alpha = 1; this.strokeWidth = 1; this.canShoot = false; + this.codeControlOnly = false; this.borderless = false; this.drawFill = true; this.drawAbove = false; if (info.PROPERTIES != null) { - if (info.PROPERTIES.TYPE != null) { - this.canShoot = true; - this.label = info.PROPERTIES.LABEL == null ? "" : info.PROPERTIES.LABEL; - this.bulletTypes = Array.isArray(info.PROPERTIES.TYPE) ? info.PROPERTIES.TYPE : [info.PROPERTIES.TYPE]; - // Pre-load bullet definitions so we don't have to recalculate them every shot - let natural = {}; - for (let type of this.bulletTypes) setNatural(natural, type); - this.natural = natural; - if (info.PROPERTIES.GUN_CONTROLLERS != null) { - let toAdd = []; - for (let i = 0; i < info.PROPERTIES.GUN_CONTROLLERS.length; i++) { - let io = info.PROPERTIES.GUN_CONTROLLERS[i]; - if ("string" == typeof io) io = [io]; - toAdd.push(new ioTypes[io[0]](this, io[1])); - } - this.controllers = toAdd.concat(this.controllers); - } - } - this.onShoot = info.PROPERTIES.ON_SHOOT == null ? null : info.PROPERTIES.ON_SHOOT; - this.autofire = info.PROPERTIES.AUTOFIRE == null ? false : info.PROPERTIES.AUTOFIRE; - this.altFire = info.PROPERTIES.ALT_FIRE == null ? false : info.PROPERTIES.ALT_FIRE; - this.calculator = info.PROPERTIES.STAT_CALCULATOR == null ? "default" : info.PROPERTIES.STAT_CALCULATOR; - this.waitToCycle = info.PROPERTIES.WAIT_TO_CYCLE == null ? false : info.PROPERTIES.WAIT_TO_CYCLE; - this.bulletStats = (info.PROPERTIES.BULLET_STATS == null || info.PROPERTIES.BULLET_STATS == "master") ? "master" : new Skill(info.PROPERTIES.BULLET_STATS); - this.settings = info.PROPERTIES.SHOOT_SETTINGS == null ? [] : JSON.parse(JSON.stringify(info.PROPERTIES.SHOOT_SETTINGS)); - this.countsOwnKids = info.PROPERTIES.MAX_CHILDREN == null ? false : info.PROPERTIES.MAX_CHILDREN; - this.syncsSkills = info.PROPERTIES.SYNCS_SKILLS == null ? false : info.PROPERTIES.SYNCS_SKILLS; - this.negRecoil = info.PROPERTIES.NEGATIVE_RECOIL == null ? false : info.PROPERTIES.NEGATIVE_RECOIL; - this.independentChildren = info.PROPERTIES.INDEPENDENT_CHILDREN == null ? false : info.PROPERTIES.INDEPENDENT_CHILDREN; + this.autofire = info.PROPERTIES.AUTOFIRE ?? false; + this.altFire = info.PROPERTIES.ALT_FIRE ?? false; + this.statCalculator = info.PROPERTIES.STAT_CALCULATOR ?? "default"; + this.waitToCycle = info.PROPERTIES.WAIT_TO_CYCLE ?? false; + this.delaySpawn = info.PROPERTIES.DELAY_SPAWN ?? this.waitToCycle; + this.bulletSkills = (info.PROPERTIES.BULLET_STATS == null || info.PROPERTIES.BULLET_STATS == "master") ? "master" : new Skill(info.PROPERTIES.BULLET_STATS); + this.useMasterSkills = this.bulletSkills === "master"; + this.shootSettings = info.PROPERTIES.SHOOT_SETTINGS == null ? [] : JSON.parse(JSON.stringify(info.PROPERTIES.SHOOT_SETTINGS)); + this.maxChildren = info.PROPERTIES.MAX_CHILDREN ?? false; + this.syncsSkills = info.PROPERTIES.SYNCS_SKILLS ?? false; + this.negativeRecoil = info.PROPERTIES.NEGATIVE_RECOIL ? -1 : 1; + this.independentChildren = info.PROPERTIES.INDEPENDENT_CHILDREN ?? false; + this.codeControlOnly = info.PROPERTIES.CODE_CONTROLLED ?? false; + this.ignorecanshootchecks = info.PROPERTIES.IGNORES_CANSHOOT_CHECKS ?? false; if (info.PROPERTIES.COLOR != null) { this.color.interpret(info.PROPERTIES.COLOR); } - this.alpha = info.PROPERTIES.ALPHA == null ? 1 : info.PROPERTIES.ALPHA - this.strokeWidth = info.PROPERTIES.STROKE_WIDTH == null ? 1 : info.PROPERTIES.STROKE_WIDTH - this.borderless = info.PROPERTIES.BORDERLESS == null ? false : info.PROPERTIES.BORDERLESS; - this.drawFill = info.PROPERTIES.DRAW_FILL == null ? true : info.PROPERTIES.DRAW_FILL; - this.destroyOldestChild = info.PROPERTIES.DESTROY_OLDEST_CHILD == null ? false : info.PROPERTIES.DESTROY_OLDEST_CHILD; - if (this.destroyOldestChild) this.countsOwnKids++; - this.shootOnDeath = (info.PROPERTIES.SHOOT_ON_DEATH == null) ? false : info.PROPERTIES.SHOOT_ON_DEATH; - this.drawAbove = (info.PROPERTIES.DRAW_ABOVE == null) ? false : info.PROPERTIES.DRAW_ABOVE; - this.stack = (info.PROPERTIES.STACK_GUN == null) ? true : info.PROPERTIES.STACK_GUN; - this.identifier = (info.PROPERTIES.IDENTIFIER == null) ? null : info.PROPERTIES.IDENTIFIER + if (info.PROPERTIES.ALPHA != null) this.alpha = info.PROPERTIES.ALPHA; + if (info.PROPERTIES.STROKE_WIDTH != null) this.strokeWidth = info.PROPERTIES.STROKE_WIDTH; + if (info.PROPERTIES.BORDERLESS != null) this.borderless = info.PROPERTIES.BORDERLESS; + if (info.PROPERTIES.DRAW_FILL != null) this.drawFill = info.PROPERTIES.DRAW_FILL; + if (info.PROPERTIES.DRAW_ABOVE) this.drawAbove = info.PROPERTIES.DRAW_ABOVE; + this.destroyOldestChild = info.PROPERTIES.DESTROY_OLDEST_CHILD ?? false; + if (this.destroyOldestChild) this.maxChildren++; + this.shootOnDeath = info.PROPERTIES.SHOOT_ON_DEATH ?? false; + this.stack = info.PROPERTIES.STACK_GUN ?? true ; + this.identifier = info.PROPERTIES.IDENTIFIER ?? null; + if (info.PROPERTIES.TYPE != null) { + this.canShoot = true; + this.label = info.PROPERTIES.LABEL ?? ""; + this.setBulletType(info.PROPERTIES.TYPE); + } } let position = info.POSITION; if (Array.isArray(position)) { @@ -108,7 +76,8 @@ class Gun extends EventEmitter { X: position[3], Y: position[4], ANGLE: position[5], - DELAY: position[6] + DELAY: position[6], + DRAW_ABOVE: position[7], } } position = { @@ -118,521 +87,425 @@ class Gun extends EventEmitter { X: position.X ?? 0, Y: position.Y ?? 0, ANGLE: position.ANGLE ?? 0, - DELAY: position.DELAY ?? 0 + DELAY: position.DELAY ?? 0, + DRAW_ABOVE: position.DRAW_ABOVE ?? this.drawAbove }; this.length = position.LENGTH / 10; this.width = position.WIDTH / 10; this.aspect = position.ASPECT; let _off = new Vector(position.X, position.Y); this.angle = (position.ANGLE * Math.PI) / 180; - this.direction = _off.direction; + this.offsetDirection = _off.direction; this.offset = _off.length / 10; - this.delay = position.DELAY; - this.position = 0; - this.motion = 0; + this.maxCycleTimer = !this.delaySpawn - position.DELAY; + this.drawAbove = position.DRAW_ABOVE; + this.recoilPosition = 0; + this.recoilVelocity = 0; if (this.canShoot) { - this.cycle = !this.waitToCycle - this.delay; - this.trueRecoil = this.settings.recoil; - this.recoilDir = 0; + this.cycleTimer = this.maxCycleTimer; + this.trueRecoil = this.shootSettings.recoil; + this.facing = 0; + this.childrenLimitFactor = 1; } } - recoil() { - if (this.motion || this.position) { - // Simulate recoil - this.motion -= (0.25 * this.position) / c.runSpeed; - this.position += this.motion; - if (this.position < 0) { - // Bouncing off the back - this.position = 0; - this.motion = -this.motion; - } - if (this.motion > 0) { - this.motion *= 0.75; - } + live() { + if (!this.canShoot || this.body.master.invuln) return; + + // Iterate recoil + this.recoil(); + + if (this.codeControlOnly) return; + + // Determine shoot permission based on child counting settings + let shootPermission = this.checkShootPermission(); + + // Cycle up if we should + if ((shootPermission || !this.waitToCycle) && this.cycleTimer < 1) { + this.cycleTimer += 1 / (this.shootSettings.reload * this.reloadRateFactor * Config.runSpeed); } - if (this.canShoot && !this.body.settings.hasNoRecoil) { - // Apply recoil to motion - if (this.motion > 0) { - let recoilForce = (-this.position * this.trueRecoil * this.body.recoilMultiplier * 1.08 / this.body.size) / c.runSpeed; - this.body.accel.x += recoilForce * Math.cos(this.recoilDir); - this.body.accel.y += recoilForce * Math.sin(this.recoilDir); + + // Firing routine + let fireCommand = this.autofire || (this.altFire ? this.body.control.alt : this.body.control.fire); + if (fireCommand) { + // Loop while allowed to shoot and reloaded enough to shoot + while (shootPermission && this.cycleTimer >= 1) { + this.fire(); + this.cycleTimer--; + + // Repeatedly check for shoot permission to prevent ultra low reload guns from exceeding the child limit in 1 tick + shootPermission = this.checkShootPermission(); } + // If we're not shooting, only cycle up to where we'll have the proper firing delay + } else if (this.cycleTimer > this.maxCycleTimer) { + this.cycleTimer = this.maxCycleTimer; } } - getSkillRaw() { - if (this.bulletStats === "master") { - return [ - this.body.skill.raw[0], - this.body.skill.raw[1], - this.body.skill.raw[2], - this.body.skill.raw[3], - this.body.skill.raw[4], - 0, - 0, - 0, - 0, - 0, - ]; - } - return this.bulletStats.raw; - } - getPhotoInfo() { - return { - ...this.lastShot, - color: this.color.compiled, - alpha: this.alpha, - strokeWidth: this.strokeWidth, - borderless: this.borderless, - drawFill: this.drawFill, - drawAbove: this.drawAbove, - length: this.length, - width: this.width, - aspect: this.aspect, - angle: this.angle, - direction: this.direction, - offset: this.offset, - }; - } - spawnBullets(useWhile, shootPermission) { - // Find out some intermediate values - let angle1 = this.direction + this.angle + this.body.facing, - angle2 = this.angle + this.body.facing, - gunlength = this.length - this.width * this.settings.size / 2, - - // Calculate offsets based on lengths and directions - offsetBaseX = this.offset * Math.cos(angle1), - offsetBaseY = this.offset * Math.sin(angle1), - offsetEndX = gunlength * Math.cos(angle2), - offsetEndY = gunlength * Math.sin(angle2), - - // Finally get the final bullet offset - offsetFinalX = offsetBaseX + offsetEndX, - offsetFinalY = offsetBaseY + offsetEndY, - skill = this.bulletStats === "master" ? this.body.skill : this.bulletStats; + checkShootPermission() { + let shootPermission = this.maxChildren + ? this.maxChildren > + this.children.length * this.childrenLimitFactor + : this.body.maxChildren + ? this.body.maxChildren > + this.body.children.length * this.childrenLimitFactor + : true; - // Shoot, multiple times in a tick if needed - do { - this.fire(offsetFinalX, offsetFinalY, skill); - this.cycle--; - shootPermission = - this.countsOwnKids ? this.countsOwnKids > this.children.length - : this.body.maxChildren ? this.body.maxChildren > this.body.children.length - : true; + // Handle destroying oldest child + if (this.destroyOldestChild && !shootPermission) { + shootPermission = true; + this.destroyOldest(); + } - } while (useWhile && shootPermission && this.cycle-1 >= 1); + return shootPermission; } - live() { - this.recoil(); + fire() { + // Recoil + this.lastShot.time = performance.now(); + this.lastShot.power = 3 * Math.log(Math.sqrt(this.bulletSkills.spd) + this.trueRecoil + 1) + 1; + this.recoilVelocity += this.lastShot.power; + this.facing = this.body.facing + this.angle; - if (!this.canShoot) return + // Initialize bullet + let [spawnX, spawnY] = this.findBulletSpawnPosition(); + let bullet = this.createBullet(spawnX, spawnY); - // Find the proper skillset for shooting - let sk = this.bulletStats === "master" ? this.body.skill : this.bulletStats; - // Decides what to do based on child-counting settings - let shootPermission = this.countsOwnKids - ? this.countsOwnKids > - this.children.length * (this.calculator == "necro" ? sk.rld : 1) - : this.body.maxChildren - ? this.body.maxChildren > - this.body.children.length * (this.calculator == "necro" ? sk.rld : 1) - : true; - if (this.destroyOldestChild) { - if (!shootPermission) { - shootPermission = true; - this.destroyOldest(); - } - } - // Override in invuln - if (this.body.master.invuln) { - shootPermission = false; - } - // Cycle up if we should - if (shootPermission || !this.waitToCycle) { - if (this.cycle < 1) { - this.cycle += 1 / (this.settings.reload * c.runSpeed * (this.calculator == "necro" || this.calculator == "fixed reload" ? 1 : sk.rld)); - } - } - // Firing routines - if (shootPermission && - (this.autofire || (this.altFire ? this.body.control.alt : this.body.control.fire)) - ) { - if (this.cycle >= 1) { - this.spawnBullets(true, shootPermission); - } // If we're not shooting, only cycle up to where we'll have the proper firing delay - } else if (this.cycle > !this.waitToCycle - this.delay) { - this.cycle = !this.waitToCycle - this.delay; + // If told to, create an independent entity + if (this.independentChildren) { + this.defineIndependentBullet(bullet); + // Else make a regular bullet + } else { + this.defineBullet(bullet); } - } - destroyOldest() { - let oldestChild, - oldestTime = Infinity; - for (let i = 0; i < this.children.length; i++) { - let child = this.children[i]; - if (child && child.creationTime < oldestTime) { - oldestTime = child.creationTime; - oldestChild = child; - } + // Set confinement + for (let k in this.master.confinement) { + bullet.confinement[k] = this.master.confinement[k]; } - if (oldestChild) oldestChild.kill(); + bullet.life(); + + // Emit fire event + this.master.emit(this.altFire ? 'altFire' : 'fire', { + body: this.master, + gun: this, + child: bullet, + masterStore: this.master.store, + globalMasterStore: this.master.globalStore, + gunStore: this.store, + globalGunStore: this.globalStore + }); } - syncChildren() { - if (this.syncsSkills) { - let self = this; - for (let i = 0; i < this.children.length; i++) { - let child = this.children[i]; - child.define({ - BODY: self.interpret(), - SKILL: self.getSkillRaw(), - }); - child.refreshBodyAttributes(); - } - } + findBulletSpawnPosition() { + // Find out some intermediate values + let offsetAngle = this.offsetDirection + this.angle + this.body.facing, + gunlength = this.length + Config.bulletSpawnOffset * this.width * this.shootSettings.size / 2, + + // Calculate offset of gun base and gun end based + offsetBaseX = this.offset * Math.cos(offsetAngle), + offsetBaseY = this.offset * Math.sin(offsetAngle), + offsetEndX = gunlength * Math.cos(this.facing), + offsetEndY = gunlength * Math.sin(this.facing), + + // Combine offsets to get final values + offsetFinalX = offsetBaseX + offsetEndX, + offsetFinalY = offsetBaseY + offsetEndY; + + return [offsetFinalX, offsetFinalY] } - fire(gx, gy, sk) { - // Recoil - this.lastShot.time = util.time(); - this.lastShot.power = 3 * Math.log(Math.sqrt(sk.spd) + this.trueRecoil + 1) + 1; - this.motion += this.lastShot.power; + createBullet(spawnX, spawnY) { // Find inaccuracy let shudder = 0, spread = 0; - if (this.settings.shudder) { + if (this.shootSettings.shudder) { do { - shudder = ran.gauss(0, Math.sqrt(this.settings.shudder)); - } while (Math.abs(shudder) >= this.settings.shudder * 2); + shudder = ran.gauss(0, Math.sqrt(this.shootSettings.shudder)); + } while (Math.abs(shudder) >= this.shootSettings.shudder * 2); } - if (this.settings.spray) { + if (this.shootSettings.spray) { do { - spread = ran.gauss(0, this.settings.spray * this.settings.shudder); - } while (Math.abs(spread) >= this.settings.spray / 2); + spread = ran.gauss(0, this.shootSettings.spray * this.shootSettings.shudder); + } while (Math.abs(spread) >= this.shootSettings.spray / 2); } spread *= Math.PI / 180; - // Find speed - let vecLength = (this.negRecoil ? -1 : 1) * this.settings.speed * c.runSpeed * sk.spd * (1 + shudder), - vecAngle = this.angle + this.body.facing + spread, - s = new Vector(vecLength * Math.cos(vecAngle), vecLength * Math.sin(vecAngle)); - // Boost it if we should + + // Find velocity + let velocityMagnitude = this.negativeRecoil * this.shootSettings.speed * this.bulletSkills.spd * (shudder + 1) * Config.runSpeed * 1.3, + velocityDirection = this.angle + this.body.facing + spread, + velocity = new Vector(velocityMagnitude * Math.cos(velocityDirection), velocityMagnitude * Math.sin(velocityDirection)); + + // Apply velocity inheritance if (this.body.velocity.length) { let extraBoost = - Math.max(0, s.x * this.body.velocity.x + s.y * this.body.velocity.y) / + Math.max(0, velocity.x * this.body.velocity.x + velocity.y * this.body.velocity.y) / this.body.velocity.length / - s.length; + velocity.length; if (extraBoost) { - let len = s.length; - s.x += (this.body.velocity.length * extraBoost * s.x) / len; - s.y += (this.body.velocity.length * extraBoost * s.y) / len; + let len = velocity.length; + velocity.x += (this.body.velocity.length * extraBoost * velocity.x) / len; + velocity.y += (this.body.velocity.length * extraBoost * velocity.y) / len; } } - //create an independent entity + // Spawn bullet + spawnX = this.body.x + this.body.size * spawnX - velocity.x, + spawnY = this.body.y + this.body.size * spawnY - velocity.y; + + // Independent children if (this.independentChildren) { - var o = new Entity({ - x: this.body.x + this.body.size * gx - s.x, - y: this.body.y + this.body.size * gy - s.y, - }); - for (let type of this.bulletTypes) { - o.define(type); - } - o.coreSize = o.SIZE; - o.team = this.body.team; - o.refreshBodyAttributes(); - o.life(); - this.master.emit(this.altFire ? 'altFire' : 'fire', { - body: this.master, - gun: this, - child: o, - masterStore: this.master.store, - globalMasterStore: this.master.globalStore, - gunStore: this.store, - globalGunStore: this.globalStore - }); - return; + let bullet = new Entity({x: spawnX, y: spawnY}); + return bullet; } - // Create the bullet - var o = new Entity({ - x: this.body.x + this.body.size * gx - s.x, - y: this.body.y + this.body.size * gy - s.y, - }, - this.master.master - ); - /*let jumpAhead = this.cycle - 1; - if (jumpAhead) { - o.x += s.x * this.cycle / jumpAhead; - o.y += s.y * this.cycle / jumpAhead; - }*/ - o.velocity = s; - this.bulletInit(o); - o.coreSize = o.SIZE; - - this.master.emit(this.altFire ? 'altFire' : 'fire', { - body: this.master, - gun: this, - child: o, - masterStore: this.master.store, - globalMasterStore: this.master.globalStore, - gunStore: this.store, - globalGunStore: this.globalStore - }); + // Dependent children + let bullet = new Entity({x: spawnX, y: spawnY}, this.master.master); + bullet.velocity = velocity; + return bullet; } - bulletInit(o) { - // Define it by its natural properties - for (let type of this.bulletTypes) { - o.define(type); - } - if (o.color.base == '-1' || o.color.base == 'mirror') { - o.color.base = this.body.master.color.base - } - // Pass the gun attributes - o.define({ - BODY: this.interpret(), - SKILL: this.getSkillRaw(), - SIZE: (this.body.size * this.width * this.settings.size) / 2, - LABEL: this.master.label + (this.label ? " " + this.label : "") + " " + o.label - }); - // Keep track of it and give it the function it needs to deutil.log itself upon death - if (this.countsOwnKids) { - o.parent = this; - this.children.push(o); + defineIndependentBullet(bullet) { + bullet.define(this.bulletType); + // Keep track of it for child counting + if (this.maxChildren) { + bullet.parent = this; + this.children.push(bullet); } else if (this.body.maxChildren) { - o.parent = this.body; - this.body.children.push(o); - this.children.push(o); - } - o.source = this.body; - o.facing = o.velocity.direction; - // Necromancers. - let oo = o; - o.necro = (host) => { - if (this.countsOwnKids ? - this.countsOwnKids > this.children.length * (this.bulletStats === "master" ? this.body.skill.rld : this.bulletStats.rld) - : this.body.maxChildren ? - this.body.maxChildren > this.body.children.length * (this.bulletStats === "master" ? this.body.skill.rld : this.bulletStats.rld) - : true - ) { - let save = { - facing: host.facing, - size: host.SIZE, - }; - host.define("genericEntity"); - this.bulletInit(host); - host.team = oo.master.master.team; - host.master = oo.master; - host.color.base = oo.color.base; - host.facing = save.facing; - host.SIZE = save.size; - host.health.amount = host.health.max; - return true; - } - return false; - }; - // Otherwise - o.refreshBodyAttributes(); - o.life(); - this.onShootFunction(); - this.recoilDir = this.body.facing + this.angle; + bullet.parent = this.body; + this.body.children.push(bullet); + this.children.push(bullet); + } + bullet.coreSize = bullet.SIZE; + bullet.team = this.body.team; } - onShootHitscan() { - if (this.body.master.health.amount < 0) return; - let save = { - x: this.body.master.x, - y: this.body.master.y, - angle: this.body.master.facing + this.angle, - }; - let s = this.body.size * this.width * this.settings2.size; - let target = { - x: save.x + this.body.master.control.target.x, - y: save.y + this.body.master.control.target.y, - }; - let amount = (util.getDistance(target, save) / s) | 0; - let gun = this; - let explode = (e) => { - e.on('dead', () => { - let o = new Entity(e, gun.body); - o.accel = { - x: 3 * Math.cos(save.angle), - y: 3 * Math.sin(save.angle), - }; - o.color = gun.body.master.master.color; - o.define("hitScanExplosion"); - // Pass the gun attributes - o.define({ - BODY: gun.interpret(gun.settings3), - SKILL: gun.getSkillRaw(), - SIZE: (gun.body.size * gun.width * gun.settings3.size) / 2, - LABEL: gun.master.label + (gun.label ? " " + gun.label + " " : " ") + o.label, - }); - o.refreshBodyAttributes(); - o.life(); - o.source = gun.body; - }); - }; - let branchAlt = 0; - let branchLength = 0; - let branch = (e, a, b = false, g = 0, z = amount) => { - if (!b) branchAlt++; - let total = (z / 5) | 0 || 2; - let dir = (a ? Math.PI / 2 : -Math.PI / 2) + g; - for (let i = 0; i < total; i++) - setTimeout(() => { - let ss = s * 1.5; - let x = e.x + ss * Math.cos(save.angle + dir) * i; - let y = e.y + ss * Math.sin(save.angle + dir) * i; - let o = new Entity( - { - x, - y, - }, - this.body - ); - o.facing = Math.atan2(target.y - y, target.x - x) + dir; - o.color = this.body.master.master.color; - o.define("hitScanBullet"); - // Pass the gun attributes - o.define({ - BODY: this.interpret(this.settings3), - SKILL: this.getSkillRaw(), - SIZE: (this.body.size * this.width * this.settings2.size) / 2, - LABEL: - this.master.label + - (this.label ? " " + this.label : "") + - " " + - o.label, - }); - o.refreshBodyAttributes(); - o.life(); - o.source = this.body; - if (i === total - 1) { - if (branchLength < 3) { - branchLength++; - branch(o, a, true, dir + g, total); - } else branchLength = 0; - } - }, (500 / amount) * i); - }; - const hitScanLevel = +this.onShoot.split("hitScan").pop(); - for (let i = 0; i < amount; i++) { - setTimeout(() => { - if (this.body.master.health.amount < 0) return; - let x = save.x + s * Math.cos(save.angle) * i; - let y = save.y + s * Math.sin(save.angle) * i; - let e = new Entity({ x: x, y: y }, this.body); - e.facing = Math.atan2(target.y - y, target.x - x); - e.color = this.body.master.master.color; - e.define("hitScanBullet"); - // Pass the gun attributes - e.define({ - BODY: this.interpret(this.settings2), - SKILL: this.getSkillRaw(), - SIZE: (this.body.size * this.width * this.settings2.size) / 2, - LABEL: - this.master.label + - (this.label ? " " + this.label : "") + - " " + - e.label, - }); - e.refreshBodyAttributes(); - e.life(); - e.source = this.body; - switch (hitScanLevel) { - case 1: - if (i % 5 === 0) branch(e, branchAlt % 2 === 0); - break; - case 2:// Superlaser - if (i === amount - 1) explode(e); - break; - case 3:// Death Star - if (i % 3 === 0) explode(e); - break; - } - }, 10 * i); + defineBullet(bullet) { + // Set bullet source + bullet.source = this.body; + + // Define bullet based on natural properties and skills + this.bulletType.SIZE = (this.body.size * this.width * this.shootSettings.size) / 2; + bullet.define(this.bulletType); + + // Fix color + if (bullet.color.base == '-1' || bullet.color.base == 'mirror') { + bullet.color.base = this.body.master.color.base + } + bullet.coreSize = bullet.SIZE; + + // Keep track of it for child counting + if (this.maxChildren) { + bullet.parent = this; + this.children.push(bullet); + } else if (this.body.maxChildren) { + bullet.parent = this.body; + this.body.children.push(bullet); + this.children.push(bullet); + } + bullet.facing = bullet.velocity.direction; + + if (!bullet.settings.necroTypes) { + return; + } + + // Set all necroType gun references to parent gun + for (let shape of bullet.settings.necroTypes) { + bullet.settings.necroDefineGuns[shape] = this; } } - onShootFunction() { - switch (this.onShoot) { - case "hitScan": - case "hitScan1": - case "hitScan2": - case "hitScan3": - onShootHitscan(); - break; + recoil() { + if (this.recoilVelocity || this.recoilPosition) { + // Simulate recoil + this.recoilVelocity -= (0.25 * this.recoilPosition) / Config.runSpeed; + this.recoilPosition += this.recoilVelocity; + if (this.recoilPosition < 0) { + // Bouncing off the back + this.recoilPosition = 0; + this.recoilVelocity = -this.recoilVelocity; + } + if (this.recoilVelocity > 0) { + this.recoilVelocity *= 0.75; + } + } + // Apply recoil to motion + if (this.recoilVelocity > 0 && this.body.recoilMultiplier) { + let recoilForce = -this.recoilPosition * this.trueRecoil * this.body.recoilMultiplier * 1.08 / this.body.size / Config.runSpeed; + this.body.accel.x += recoilForce * Math.cos(this.facing); + this.body.accel.y += recoilForce * Math.sin(this.facing); } } - getTracking() { - return { - speed: c.runSpeed * (this.bulletStats == "master" ? this.body.skill.spd : this.bulletStats.spd) * this.settings.maxSpeed * this.natural.SPEED, - range: Math.sqrt(this.bulletStats == "master" ? this.body.skill.spd : this.bulletStats.spd) * this.settings.range * this.natural.RANGE - }; + setBulletType(type, clearChildren = false) { + // Pre-flatten bullet types to save on doing the same define() sequence a million times + this.bulletType = Array.isArray(type) ? type : [type]; + // Preset BODY because not all definitions have BODY defined when flattened + let flattenedType = {BODY: {}}; + for (let type of this.bulletType) { + type = ensureIsClass(type); + util.flattenDefinition(flattenedType, type); + } + this.bulletType = flattenedType; + // Set final label to bullet + if (!this.independentChildren) { + this.bulletType.LABEL = this.master.label + (this.label ? " " + this.label : "") + " " + this.bulletType.LABEL; + } + // Save a copy of the bullet definition for body stat defining + this.bulletBodyStats = JSON.parse(JSON.stringify(this.bulletType.BODY)); + this.calculateBulletStats(); + + if (!clearChildren) return; + for (let child of this.children) { + child.kill(); + } } - interpret(alt = false) { + syncGunStats() { + this.calculateBulletStats(); + // Don't bother updating children if we shouldn't + if (!this.syncsSkills || this.independentChildren) return; + + for (let i = 0; i < this.children.length; i++) { + let child = this.children[i]; + child.define({ + BODY: this.interpretedStats, + SKILL: this.getSkillRaw(), + }); + child.refreshBodyAttributes(); + } + } + calculateBulletStats() { + // Skip if unable to shoot or if we shouldn't care about body stats + if (!this.ignorecanshootchecks && !this.canShoot) return; + let sizeFactor = this.master.size / this.master.SIZE; - let shoot = alt ? alt : this.settings; - let sk = this.bulletStats == "master" ? this.body.skill : this.bulletStats; + let shoot = this.shootSettings; + if (this.useMasterSkills) { + this.bulletSkills = this.body.skill; + } // Defaults let out = { - SPEED: shoot.maxSpeed * sk.spd, - HEALTH: shoot.health * sk.str, - RESIST: shoot.resist + sk.rst, - DAMAGE: shoot.damage * sk.dam, - PENETRATION: Math.max(1, shoot.pen * sk.pen), - RANGE: shoot.range / Math.sqrt(sk.spd), - DENSITY: (shoot.density * sk.pen * sk.pen) / sizeFactor, - PUSHABILITY: 1 / sk.pen, - HETERO: 3 - 2.8 * sk.ghost, + SPEED: shoot.maxSpeed * this.bulletSkills.spd, + HEALTH: shoot.health * this.bulletSkills.str, + RESIST: shoot.resist + this.bulletSkills.rst, + DAMAGE: shoot.damage * this.bulletSkills.dam, + PENETRATION: Math.max(1, shoot.pen * this.bulletSkills.pen), + RANGE: shoot.range / Math.sqrt(this.bulletSkills.spd), + DENSITY: (shoot.density * this.bulletSkills.pen * this.bulletSkills.pen) / sizeFactor, + PUSHABILITY: 1 / this.bulletSkills.pen, + HETERO: Math.max(0, 3 - 1.2 * this.bulletSkills.ghost), }; + this.reloadRateFactor = this.bulletSkills.rld; // Special cases - switch (this.calculator) { + switch (this.statCalculator) { case "thruster": - this.trueRecoil = shoot.recoil * Math.sqrt(sk.rld * sk.spd); + this.trueRecoil = shoot.recoil * Math.sqrt(this.bulletSkills.rld * this.bulletSkills.spd); break; case "sustained": out.RANGE = shoot.range; break; case "swarm": - out.PENETRATION = Math.max(1, shoot.pen * (0.5 * (sk.pen - 1) + 1)); - out.HEALTH /= shoot.pen * sk.pen; + out.PENETRATION = Math.max(1, shoot.pen * (0.5 * (this.bulletSkills.pen - 1) + 1)); + out.HEALTH /= shoot.pen * this.bulletSkills.pen; break; case "trap": case "block": - out.PUSHABILITY = 1 / Math.pow(sk.pen, 0.5); + out.PUSHABILITY = 1 / Math.pow(this.bulletSkills.pen, 0.5); out.RANGE = shoot.range; break; + case "fixedReload": + this.reloadRateFactor = 1; + break; + case "lancer": + out.RANGE = 0.02 * this.bulletSkills.spd; + break; case "necro": + this.childrenLimitFactor = this.bulletSkills.rld; + this.reloadRateFactor = 1; case "drone": out.PUSHABILITY = 1; - out.PENETRATION = Math.max(1, shoot.pen * (0.5 * (sk.pen - 1) + 1)); - out.HEALTH = (shoot.health * sk.str + sizeFactor) / Math.pow(sk.pen, 0.8); - out.DAMAGE = shoot.damage * sk.dam * Math.sqrt(sizeFactor) * shoot.pen * sk.pen; - out.RANGE = shoot.range * Math.sqrt(sizeFactor); + out.PENETRATION = Math.max(1, shoot.pen * (0.5 * (this.bulletSkills.pen - 1) + 1)); + out.HEALTH = (shoot.health * this.bulletSkills.str + sizeFactor) / Math.pow(this.bulletSkills.pen, 0.8); + out.DAMAGE = shoot.damage * this.bulletSkills.dam * Math.sqrt(sizeFactor) * Math.sqrt(shoot.pen * this.bulletSkills.pen); break; } + if (this.independentChildren) return; // Go through and make sure we respect its natural properties for (let property in out) { - if (this.natural[property] == null || !out.hasOwnProperty(property)) + if (this.bulletBodyStats[property] == null) continue; - out[property] *= this.natural[property]; + out[property] *= this.bulletBodyStats[property]; + } + this.interpretedStats = out; + + // Save in this.bulletType to be used for defining dependent bullets + this.bulletType.SKILL = this.getSkillRaw(); + for (let stat in this.interpretedStats) { + // Do body stats one-by-one so all are defined properly and none are replaced with undefined + this.bulletType.BODY[stat] = this.interpretedStats[stat]; } - return out; + } + destroyOldest() { + let oldestChild, + oldestTime = Infinity; + for (let i = 0; i < this.children.length; i++) { + let child = this.children[i]; + if (child && child.creationTime < oldestTime) { + oldestTime = child.creationTime; + oldestChild = child; + } + } + if (oldestChild) oldestChild.kill(); + } + getTracking() { + return { + speed: Config.runSpeed * this.bulletSkills.spd * this.shootSettings.maxSpeed * this.bulletBodyStats.SPEED, + range: Math.sqrt(this.bulletSkills.spd) * this.shootSettings.range * this.bulletBodyStats.RANGE + }; + } + getSkillRaw() { + if (this.useMasterSkills) { + return [ + this.body.skill.raw[0], + this.body.skill.raw[1], + this.body.skill.raw[2], + this.body.skill.raw[3], + this.body.skill.raw[4], + 0, + 0, + 0, + 0, + 0, + ]; + } + return this.bulletSkills.raw; + } + getPhotoInfo() { + return { + ...this.lastShot, + color: this.color.compiled, + alpha: this.alpha, + strokeWidth: this.strokeWidth, + borderless: this.borderless, + drawFill: this.drawFill, + drawAbove: this.drawAbove, + length: this.length, + width: this.width, + aspect: this.aspect, + angle: this.angle, + offsetDirection: this.offsetDirection, + offset: this.offset, + }; } } class antiNaN { - constructor (me) { + constructor(me) { this.me = me; this.nansInARow = 0; this.data = { x: 1, y: 1, vx: 0, vy: 0, ax: 0, ay: 0 }; - this.amNaN = me => [ me.x, me.y, me.velocity.x, me.velocity.y, me.accel.x, me.accel.y ].some(isNaN); + this.amNaN = me => [me.x, me.y, me.velocity.x, me.velocity.y, me.accel.x, me.accel.y].some(isNaN); } update() { if (this.amNaN(this.me)) { this.nansInARow++; if (this.nansInARow > 50) { console.log("NaN instance found. (Repeated)\nDebug:", [ - ["x" , isNaN(this.me.x)], - ["y" , isNaN(this.me.y)], + ["x", isNaN(this.me.x)], + ["y", isNaN(this.me.y)], ["velocity.x", isNaN(this.me.velocity.x)], ["velocity.y", isNaN(this.me.velocity.y)], - ["accel.x" , isNaN(this.me.accel.x)], - ["accel.y" , isNaN(this.me.accel.y)], + ["accel.x", isNaN(this.me.accel.x)], + ["accel.y", isNaN(this.me.accel.y)], ].filter(entry => entry[1]).join(', ')); } this.me.x = this.data.x; @@ -654,6 +527,39 @@ class antiNaN { } } +class Activation { + constructor(body) { + this.body = body; + this.active = true; + this.lastActive = false; + } + update() { + // Force activation conditions + if (this.body.alwaysActive || this.body.isPlayer || this.body.isBot) { + return this.active = true; + } + if (this.body.skipLife || this.body.isDead()) { + return this.active = false; + } + // Update activity and other properties based on views + this.active = views.some((v) => v.check(this.body)); + if (!this.active && this.lastActive) { + this.body.removeFromGrid(); + this.lastActive = false; + // Save range ticking + this.deactivationTime = performance.now(); + } else if (this.active && !this.lastActive) { + this.lastActive = true; + this.body.addToGrid(); + // Retrieve range ticking + if (this.body.diesAtRange) { + // Time since deactivation, converted to number of ticks, factoring in the run speed + this.body.range -= (performance.now() - this.deactivationTime) / room.cycleSpeed / Config.runSpeed; + } + } + } +} + function getValidated(obj, prop, allowedType, from, optional = true) { let type = typeof obj[prop]; if (allowedType === type || (optional && 'undefined' === type)) { @@ -663,9 +569,9 @@ function getValidated(obj, prop, allowedType, from, optional = true) { } let labelThing = "StatusEffect's effects argument"; class StatusEffect extends EventEmitter { - constructor (duration = 0, multipliers = {}, tick = a=>a) { + constructor(duration = 0, multipliers = {}, tick = a => a) { super(); - this.duration = getValidated({duration}, 'duration', 'number', labelThing, false); + this.duration = getValidated({ duration }, 'duration', 'number', labelThing, false); this.acceleration = getValidated(multipliers, 'acceleration', 'number', labelThing); this.topSpeed = getValidated(multipliers, 'topSpeed', 'number', labelThing); this.health = getValidated(multipliers, 'health', 'number', labelThing); @@ -680,7 +586,7 @@ class StatusEffect extends EventEmitter { this.pushability = getValidated(multipliers, 'pushability', 'number', labelThing); this.recoilReceived = getValidated(multipliers, 'recoilReceived', 'number', labelThing); this.size = getValidated(multipliers, 'size', 'number', labelThing); - this.tick = getValidated({tick}, 'tick', 'function', "StatusEffect's argument"); + this.tick = getValidated({ tick }, 'tick', 'function', "StatusEffect's argument"); } } @@ -730,7 +636,7 @@ class Prop { this.turrets = []; this.props = []; } - define(def) { + define(def, keepteam = false) { let set = ensureIsClass(def); if (set.PARENT != null) { @@ -761,6 +667,10 @@ class Prop { } this.guns = newGuns; } + if (keepteam) { + if (set.TEAM != null) this.TEAM = set.TEAM; + if (set.VARIABLES != null) this.variables = set.VARIABLES ? JSON.parse(JSON.stringify(set.VARIABLES)) : {}; + } } camera() { return { @@ -800,7 +710,7 @@ class Entity extends EventEmitter { polygons: 0, killers: [], }; - this.creationTime = new Date().getTime(); + this.creationTime = Date.now(); // Inheritance this.skipLife = false; this.master = master; @@ -829,36 +739,7 @@ class Entity extends EventEmitter { this.isInGrid = true; } }; - this.activation = (() => { - let active = true; - let timer = ran.irandom(15); - return { - update: () => { - if (this.skipLife) { - return active = false; - } - if (this.isDead()) { - return 0; - } - if (!active) { - this.removeFromGrid(); - if (this.settings.diesAtRange) { - this.kill(); - } - if (!timer--) { - active = true; - } - } else { - this.addToGrid(); - timer = 15; - active = this.alwaysActive || this.isPlayer || this.isBot || views.some((v) => v.check(this, 0.6)); - } - }, - check: () => { - return active; - }, - }; - })(); + this.activation = new Activation(this); this.autoOverride = false; this.healer = false; this.controllers = []; @@ -876,14 +757,21 @@ class Entity extends EventEmitter { this.turrets = []; this.props = []; this.upgrades = []; + this.skippedUpgrades = []; this.settings = {}; this.aiSettings = {}; this.children = []; this.statusEffects = []; this.color = new Color(16); - this.glow = {radius: null, color: new Color(-1).compiled, alpha: 1, recursion: 1} + this.glow = { radius: null, color: new Color(-1).compiled, alpha: 1, recursion: 1 } this.invisible = [0, 0]; this.alphaRange = [0, 1]; + this.confinement = { + xMin: 0, + xMax: room.width, + yMin: 0, + yMax: room.height, + }, // Define it this.SIZE = 1; this.sizeMultiplier = 1; @@ -894,7 +782,6 @@ class Entity extends EventEmitter { this.maxSpeed = 0; this.facingLocked = false; this.facing = 0; - this.vfacing = 0; this.range = 0; this.angle = 0; this.damageReceived = 0; @@ -962,7 +849,7 @@ class Entity extends EventEmitter { entities.push(this); for (let v of views) v.add(this); this.activation.update(); - events.emit('spawn', this); + Events.emit('spawn', this); } addStatusEffect(effect) { this.emit('newStatusEffect', effect); @@ -982,7 +869,7 @@ class Entity extends EventEmitter { let lastingEffects = [], needsBodyAttribRefresh = false; for (let i = 0; i < this.statusEffects.length; i++) { let entry = this.statusEffects[i]; - entry.durationLeftover -= 1 / c.runSpeed; + entry.durationLeftover -= 1 / Config.runSpeed; if (entry.durationLeftover > 0) { lastingEffects.push(entry); } else { @@ -997,14 +884,14 @@ class Entity extends EventEmitter { // Think let faucet = this.settings.independent || this.source == null || this.source === this ? {} : this.source.control, - b = { - target: remapTarget(faucet, this.source, this), - goal: undefined, - fire: faucet.fire, - main: faucet.main, - alt: faucet.alt, - power: undefined, - }; + b = { + target: remapTarget(faucet, this.source, this), + goal: undefined, + fire: faucet.fire, + main: faucet.main, + alt: faucet.alt, + power: undefined, + }; // Seek attention if (this.settings.attentionCraver && !faucet.main && this.range) { this.range -= 1; @@ -1015,11 +902,11 @@ class Entity extends EventEmitter { a = AI.think(b); if (a != null) { if (a.target != null && (b.target == null || AI.acceptsFromTop)) b.target = a.target; - if (a.goal != null && (b.goal == null || AI.acceptsFromTop)) b.goal = a.goal ; - if (a.fire != null && (b.fire == null || AI.acceptsFromTop)) b.fire = a.fire ; - if (a.main != null && (b.main == null || AI.acceptsFromTop)) b.main = a.main ; - if (a.alt != null && (b.alt == null || AI.acceptsFromTop)) b.alt = a.alt ; - if (a.power != null && (b.power == null || AI.acceptsFromTop)) b.power = a.power ; + if (a.goal != null && (b.goal == null || AI.acceptsFromTop)) b.goal = a.goal; + if (a.fire != null && (b.fire == null || AI.acceptsFromTop)) b.fire = a.fire; + if (a.main != null && (b.main == null || AI.acceptsFromTop)) b.main = a.main; + if (a.alt != null && (b.alt == null || AI.acceptsFromTop)) b.alt = a.alt; + if (a.power != null && (b.power == null || AI.acceptsFromTop)) b.power = a.power; } } this.control.target = b.target == null ? this.control.target : b.target; @@ -1058,7 +945,8 @@ class Entity extends EventEmitter { this.controllers = this.controllers.concat(newIO); } become(player, dom = false) { - this.addController(new ioTypes.listenToPlayer(this, { player, static: dom })); + this.addController(new ioTypes.listenToPlayer(this, { player, static: dom })); // make it listen. + this.sendMessage = (content, displayTime = Config.MESSAGE_DISPLAY_TIME) => player.socket.talk("m", displayTime, content); // make sure that it sends messages. this.kick = (reason) => player.socket.kick(reason); } giveUp(player, name = "Mothership") { @@ -1084,7 +972,7 @@ class Entity extends EventEmitter { } define(defs, emitEvent = true) { if (!Array.isArray(defs)) defs = [defs]; - + // Define all primary stats let set = ensureIsClass(defs[0]); this.store = {}; @@ -1101,7 +989,10 @@ class Entity extends EventEmitter { } if (set.LAYER != null) this.layerID = set.LAYER; if (set.index != null) this.index = set.index.toString(); - if (set.NAME != null) this.name = set.NAME; + if (set.NAME != null) { + this.name = set.NAME; + if (this.socket) this.socket.talk("updateName", this.name); + }; if (set.LABEL != null) this.label = set.LABEL; if (set.ANGLE != null) this.angle = set.ANGLE; if (set.UPGRADE_LABEL != null) this.upgradeLabel = set.UPGRADE_LABEL; @@ -1119,7 +1010,7 @@ class Entity extends EventEmitter { } this.color.interpret(set.COLOR); } - this.upgradeColor = set.UPGRADE_COLOR == null ? null : new Color(set.UPGRADE_COLOR).compiled; + if (set.UPGRADE_COLOR) this.upgradeColor = new Color(set.UPGRADE_COLOR).compiled; if (set.GLOW != null) { this.glow = { radius: set.GLOW.RADIUS ?? 0, @@ -1128,6 +1019,25 @@ class Entity extends EventEmitter { recursion: set.GLOW.RECURSION ?? 1 }; } + if (set.IGNORED_BY_AI != null) this.ignoredByAi = set.IGNORED_BY_AI; + if (set.MOTION_TYPE != null) { + this.motionType = set.MOTION_TYPE; + if (Array.isArray(this.motionType)) { + this.motionTypeArgs = this.motionType[1]; + this.motionType = this.motionType[0]; + } else { + this.motionTypeArgs = {}; + } + } + if (set.FACING_TYPE != null) { + this.facingType = set.FACING_TYPE; + if (Array.isArray(this.facingType)) { + this.facingTypeArgs = this.facingType[1]; + this.facingType = this.facingType[0]; + } else { + this.facingTypeArgs = {}; + } + } if (set.CONTROLLERS != null) { let toAdd = []; for (let i = 0; i < set.CONTROLLERS.length; i++) { @@ -1137,11 +1047,7 @@ class Entity extends EventEmitter { } this.addController(toAdd); } - if (set.IGNORED_BY_AI != null) this.ignoredByAi = set.IGNORED_BY_AI; - if (set.MOTION_TYPE != null) this.motionType = set.MOTION_TYPE; - if (typeof this.motionType == "string") this.motionType = [this.motionType, {}]; - if (set.FACING_TYPE != null) this.facingType = set.FACING_TYPE; - if (typeof this.facingType == "string") this.facingType = [this.facingType, {}]; + if (set.ALWAYS_ACTIVE != null) this.alwaysActive = set.ALWAYS_ACTIVE; if (set.MIRROR_MASTER_ANGLE != null) this.settings.mirrorMasterAngle = set.MIRROR_MASTER_ANGLE if (set.DRAW_HEALTH != null) this.settings.drawHealth = set.DRAW_HEALTH; if (set.DRAW_SELF != null) this.settings.drawShape = set.DRAW_SELF; @@ -1160,8 +1066,7 @@ class Entity extends EventEmitter { if (set.HEALTH_WITH_LEVEL != null) this.settings.healthWithLevel = set.HEALTH_WITH_LEVEL; if (set.ACCEPTS_SCORE != null) this.settings.acceptsScore = set.ACCEPTS_SCORE; if (set.OBSTACLE != null) this.settings.obstacle = set.OBSTACLE; - if (set.NECRO != null) this.settings.necroTypes = Array.isArray(set.NECRO) ? set.NECRO : set.NECRO ? [this.shape] : []; - if (set.HAS_NO_RECOIL != null) this.settings.hasNoRecoil = set.HAS_NO_RECOIL; + if (set.HAS_NO_RECOIL) this.RECOIL_MULTIPLIER = 0; if (set.CRAVES_ATTENTION != null) this.settings.attentionCraver = set.CRAVES_ATTENTION; if (set.KILL_MESSAGE != null) this.settings.killMessage = set.KILL_MESSAGE === "" ? "Killed" : set.KILL_MESSAGE; if (set.AUTOSPIN_MULTIPLIER != null) this.autospinBoost = set.AUTOSPIN_MULTIPLIER; @@ -1187,6 +1092,10 @@ class Entity extends EventEmitter { }; if (set.AI != null) this.aiSettings = set.AI; if (set.INVISIBLE != null) this.invisible = set.INVISIBLE; + if (set.SYNC_WITH_TANK != null) { + this.settings.syncWithTank = set.SYNC_WITH_TANK; + if (this.socket) this.socket.talk("I", !!set.SYNC_WITH_TANK); + } if (set.ALPHA != null) { this.alpha = ("number" === typeof set.ALPHA) ? set.ALPHA : set.ALPHA[1]; this.alphaRange = [ @@ -1199,40 +1108,38 @@ class Entity extends EventEmitter { if (set.SHOOT_ON_DEATH != null) this.shootOnDeath = set.SHOOT_ON_DEATH; if (set.BORDERLESS != null) this.borderless = set.BORDERLESS; if (set.DRAW_FILL != null) this.drawFill = set.DRAW_FILL; + if (set.IS_IMMUNE_TO_TILES) this.immuneToTiles = set.IS_IMMUNE_TO_TILES; if (set.TEAM != null) { this.team = set.TEAM; - if (!sockets.players.length) { - const _entity = this; + if (sockets.players.length) { for (let i = 0; i < sockets.players.length; i++) { - if (sockets.players[i].body.id == _entity.id) { - sockets.players[i].team = -_entity.team; + const player = sockets.players[i]; + if (player.body && player.body.id == this.id) { + player.team = this.team; } } } - for (let child of this.children) child.team = set.TEAM + for (let child of this.children) child.team = set.TEAM; } if (set.VARIES_IN_SIZE != null) { this.settings.variesInSize = set.VARIES_IN_SIZE; this.squiggle = this.settings.variesInSize ? ran.randomRange(0.8, 1.2) : 1; } if (set.RESET_UPGRADES || set.RESET_STATS) { - let caps = this.skill.caps.map(x=>x); + let caps = this.skill.caps.map(x => x); this.skill.setCaps(Array(10).fill(0)); this.skill.setCaps(caps); this.upgrades = []; this.isArenaCloser = false; - this.ac = false; this.alpha = 1; this.reset(); } + if (set.SYNC_TURRET_SKILLS != null) this.syncTurretSkills = set.SYNC_TURRET_SKILLS; if (set.RESET_UPGRADE_MENU) this.upgrades = [] - if (set.ARENA_CLOSER != null) { - this.isArenaCloser = set.ARENA_CLOSER; - this.ac = set.ARENA_CLOSER; - } + if (set.ARENA_CLOSER != null) this.isArenaCloser = set.ARENA_CLOSER; if (set.BRANCH_LABEL != null) this.branchLabel = set.BRANCH_LABEL; if (set.BATCH_UPGRADES != null) this.batchUpgrades = set.BATCH_UPGRADES; - for (let i = 0; i < c.MAX_UPGRADE_TIER; i++) { + for (let i = 0; i < Config.MAX_UPGRADE_TIER; i++) { let tierProp = 'UPGRADES_TIER_' + i; if (set[tierProp] != null && emitEvent) { for (let j = 0; j < set[tierProp].length; j++) { @@ -1247,8 +1154,8 @@ class Entity extends EventEmitter { } this.upgrades.push({ class: trueUpgrades, - level: c.TIER_MULTIPLIER * i, - index: index.substring(0, index.length-1), + level: Config.TIER_MULTIPLIER * i, + index: index.substring(0, index.length - 1), tier: i, branch: 0, branchLabel: this.branchLabel, @@ -1264,8 +1171,11 @@ class Entity extends EventEmitter { if (set.LEVEL_CAP != null) { this.levelCap = set.LEVEL_CAP; } + if ("function" === typeof set.LEVEL_SKILL_POINT_FUNCTION) { + this.skill.LSPF = set.LEVEL_SKILL_POINT_FUNCTION; + } if (set.LEVEL != null) { - this.skill.reset(); + this.skill.reset(false); while (this.skill.level < set.LEVEL) { this.skill.score += this.skill.levelScore; this.skill.maintain(); @@ -1279,6 +1189,7 @@ class Entity extends EventEmitter { if (set.SKILL != null && set.SKILL != []) { if (set.SKILL.length != 10) throw "Inappropiate skill raws."; this.skill.set(set.SKILL); + this.syncSkillsToGuns(); } if (set.VALUE != null) this.skill.score = Math.max(this.skill.score, set.VALUE * this.squiggle); if (set.ALT_ABILITIES != null) this.abilities = set.ALT_ABILITIES; @@ -1289,16 +1200,45 @@ class Entity extends EventEmitter { } this.guns = newGuns; } + if (set.GUN_STAT_SCALE) { + this.gunStatScale = set.GUN_STAT_SCALE; + } + if (set.NECRO != null) { + this.settings.necroTypes = Array.isArray(set.NECRO) ? set.NECRO : set.NECRO ? [this.shape] : []; + + // Necro function for tanks + this.settings.necroDefineGuns = {}; + for (let shape of this.settings.necroTypes) { + // Pick the first gun with the right necroType to use for stats and use its defineBullet function + this.settings.necroDefineGuns[shape] = this.guns.filter((gun) => gun.bulletType.NECRO && (gun.bulletType.NECRO === shape || (gun.bulletType.NECRO === true && gun.bulletType.SHAPE === this.shape) || gun.bulletType.NECRO.includes(shape)))[0]; + } + + this.necro = (host) => { + let gun = this.settings.necroDefineGuns[host.shape]; + if (!gun || !gun.checkShootPermission()) return false; + + let savedFacing = host.facing; + let savedSize = host.SIZE; + + host.controllers = []; + host.define("genericEntity"); + gun.defineBullet(host); + host.team = this.master.master.team; + host.master = this.master; + host.color.base = this.color.base; + host.facing = savedFacing; + host.SIZE = savedSize; + host.health.amount = host.health.max; + return true; + } + } if (set.MAX_CHILDREN != null) this.maxChildren = set.MAX_CHILDREN; if (set.RESET_CHILDREN) this.destroyAllChildren(); - if ("function" === typeof set.LEVEL_SKILL_POINT_FUNCTION) { - this.skill.LSPF = set.LEVEL_SKILL_POINT_FUNCTION; - } if (set.RECALC_SKILL != null) { let score = this.skill.score; this.skill.reset(); this.skill.score = score; - while (this.skill.maintain()) {} + while (this.skill.maintain()) { } } if (set.EXTRA_SKILL != null) { this.skill.points += set.EXTRA_SKILL; @@ -1329,6 +1269,7 @@ class Entity extends EventEmitter { } this.definitionEvents = []; } + this.variables = set.VARIABLES ? JSON.parse(JSON.stringify(set.VARIABLES)) : {}; if (set.REROOT_UPGRADE_TREE) this.rerootUpgradeTree = set.REROOT_UPGRADE_TREE; if (Array.isArray(this.rerootUpgradeTree)) { let finalRoot = ""; @@ -1437,6 +1378,7 @@ class Entity extends EventEmitter { for (let j = 0; j < type.length; j++) { o.define(type[j]); if (type.TURRET_DANGER) turretDanger = true; + o.isTurret = true; } if (!turretDanger) o.define({ DANGER: 0 }); o.bindToMaster(def.POSITION, this); @@ -1456,8 +1398,17 @@ class Entity extends EventEmitter { this.SIZE *= set.SIZE * this.squiggle; if (this.coreSize == null) this.coreSize = this.SIZE; } + if (set.CONTROLLERS != null) { + let toAdd = []; + for (let i = 0; i < set.CONTROLLERS.length; i++) { + let io = set.CONTROLLERS[i]; + if ("string" == typeof io) io = [io]; + toAdd.push(new ioTypes[io[0]](this, io[1])); + } + this.addController(toAdd); + } if (set.BATCH_UPGRADES != null) this.batchUpgrades = set.BATCH_UPGRADES; - for (let i = 0; i < c.MAX_UPGRADE_TIER; i++) { + for (let i = 0; i < Config.MAX_UPGRADE_TIER; i++) { let tierProp = 'UPGRADES_TIER_' + i; if (set[tierProp] != null && emitEvent) { for (let j = 0; j < set[tierProp].length; j++) { @@ -1472,8 +1423,8 @@ class Entity extends EventEmitter { } this.upgrades.push({ class: trueUpgrades, - level: c.TIER_MULTIPLIER * i, - index: index.substring(0, index.length-1), + level: Config.TIER_MULTIPLIER * i, + index: index.substring(0, index.length - 1), tier: i, branch, branchLabel: this.branchLabel, @@ -1527,8 +1478,8 @@ class Entity extends EventEmitter { } this.upgrades.push({ class: upgradeClass, - level: c.TIER_MULTIPLIER * upgradeTier, - index: upgradeIndex.substring(0, upgradeIndex.length-1), + level: Config.TIER_MULTIPLIER * upgradeTier, + index: upgradeIndex.substring(0, upgradeIndex.length - 1), tier: upgradeTier, branch: 0, branchLabel: "", @@ -1569,10 +1520,11 @@ class Entity extends EventEmitter { if (effect.size != null) sizeMultiplier *= effect.size; } + this.sizeMultiplier = sizeMultiplier; let speedReduce = Math.pow(this.size / (this.coreSize || this.SIZE), 1); - this.acceleration = (accelerationMultiplier * c.runSpeed * this.ACCELERATION) / speedReduce; + this.acceleration = (accelerationMultiplier * Config.runSpeed * this.ACCELERATION) / speedReduce; if (this.settings.reloadToAcceleration) this.acceleration *= this.skill.acl; - this.topSpeed = (topSpeedMultiplier * c.runSpeed * this.SPEED * this.skill.mob) / speedReduce; + this.topSpeed = (topSpeedMultiplier * Config.runSpeed * this.SPEED * this.skill.mob) / speedReduce; if (this.settings.reloadToAcceleration) this.topSpeed /= Math.sqrt(this.skill.acl); this.health.set(((this.settings.healthWithLevel ? 2 * this.level : 0) + this.HEALTH) * this.skill.hlt * healthMultiplier); this.health.resist = 1 - 1 / Math.max(1, this.RESIST + this.skill.brst); @@ -1584,8 +1536,12 @@ class Entity extends EventEmitter { this.density = densityMultiplier * (1 + 0.08 * this.level) * this.DENSITY; this.stealth = stealthMultiplier * this.STEALTH; this.pushability = pushabilityMultiplier * this.PUSHABILITY; - this.sizeMultiplier = sizeMultiplier; this.recoilMultiplier = this.RECOIL_MULTIPLIER * recoilReceivedMultiplier; + if (Config.SPACE_PHYSICS) { + this.maxSpeed = this.topSpeed; + this.damp = 100; + } + this.scaledAcceleration = this.acceleration / Config.runSpeed; } bindToMaster(position, bond, isInvulnerable) { this.bond = bond; @@ -1599,7 +1555,7 @@ class Entity extends EventEmitter { this.skipLife = true; } // TODO: FIX CLIENT MAKING EVERYTHING FLASH WHEN A VULN TURRET DIES, and display health - if (isInvulnerable) this.on('dead', () => {util.remove(this.master.turrets, this.master.turrets.indexOf(this))}) + if (isInvulnerable) this.on('dead', () => { util.remove(this.master.turrets, this.master.turrets.indexOf(this)) }) this.settings.drawShape = false; // Get my position. if (Array.isArray(position)) { @@ -1630,14 +1586,17 @@ class Entity extends EventEmitter { // Initalize. this.activation.update(); this.facing = this.bond.facing + this.bound.angle; - if (this.facingType[0].includes('Target') || this.facingType[0].includes('Speed')) { - this.facingType = ["bound", {}]; + if (this.facingType.includes('Target') || this.facingType.includes('Speed')) { + this.facingType = "bound"; + this.facingTypeArgs = {}; } - this.motionType = ["bound", {}]; + this.motionType = "bound"; + this.motionTypeArgs = {}; + this.syncSkillsToGuns(); this.move(); } get level() { - return Math.min(this.levelCap ?? c.LEVEL_CAP, this.skill.level); + return Math.min(this.levelCap ?? Config.LEVEL_CAP, this.skill.level); } get size() { return this.bond == null ? (this.coreSize || this.SIZE) * this.sizeMultiplier * (1 + this.level / 45) : this.bond.size * this.bound.size; @@ -1649,10 +1608,23 @@ class Entity extends EventEmitter { return this.size * lazyRealSizes[Math.floor(Math.abs(this.shape))]; } get xMotion() { - return (this.velocity.x + this.accel.x) / c.runSpeed; + return (this.velocity.x + this.accel.x) / Config.runSpeed; } get yMotion() { - return (this.velocity.y + this.accel.y) / c.runSpeed; + return (this.velocity.y + this.accel.y) / Config.runSpeed; + } + set gunStatScale(gunStatScale) { + if (!Array.isArray(gunStatScale)) { + gunStatScale = [gunStatScale]; + } + for (let gun of this.guns) { + if (!gun.shootSettings) { + continue + } + gun.shootSettings = combineStats([gun.shootSettings, ...gunStatScale]); + gun.trueRecoil = gun.shootSettings.recoil; + gun.calculateBulletStats(); + } } camera(tur = false) { let turretsAndProps = this.turrets.concat(this.props); @@ -1673,6 +1645,8 @@ class Entity extends EventEmitter { status: 1, health: this.health.display(), shield: this.shield.display(), + healthN: this.health.amount, + maxHealthN: this.health.max, alpha: this.alpha, facing: this.facing, direction: this.bound ? this.bound.direction : 0, @@ -1680,9 +1654,9 @@ class Entity extends EventEmitter { offset: this.bound ? this.bound.offset : 0, sizeFactor: this.bound ? this.bound.size : 1, mirrorMasterAngle: this.settings.mirrorMasterAngle ?? false, - perceptionAngleIndependence: this.perceptionAngleIndependence, //vfacing: this.vfacing, + perceptionAngleIndependence: this.perceptionAngleIndependence, defaultAngle: this.firingArc[0], - twiggle: forceTwiggle.includes(this.facingType[0]) || (this.facingType[0] === "locksFacing" && this.control.alt), + twiggle: forceTwiggle.includes(this.facingType) || (this.facingType === "locksFacing" && this.control.alt), layer: this.layerID ? this.layerID : this.bond != null ? this.bound.layer : this.type === "wall" ? 11 : this.type === "food" ? 10 : this.type === "tank" ? 5 : this.type === "crasher" ? 1 : 0, color: this.color.compiled, strokeWidth: this.strokeWidth, @@ -1696,7 +1670,7 @@ class Entity extends EventEmitter { }; } syncTurrets() { - for (let i = 0; i < this.guns.length; i++) this.guns[i].syncChildren(); + for (let i = 0; i < this.guns.length; i++) this.guns[i].syncGunStats(); for (let i = 0; i < this.turrets.length; i++) { this.turrets[i].skill = this.skill; this.turrets[i].refreshBodyAttributes(); @@ -1707,13 +1681,19 @@ class Entity extends EventEmitter { let suc = this.skill.upgrade(stat); if (suc) { this.refreshBodyAttributes(); - for (let i = 0; i < this.guns.length; i++) this.guns[i].syncChildren(); - for (let i = 0; i < this.turrets.length; i++) this.turrets[i].syncTurrets(); + this.syncSkillsToGuns(); } return suc; } - upgrade(number) { - let old = this; + syncSkillsToGuns() { + for (let i = 0; i < this.guns.length; i++) this.guns[i].syncGunStats(); + for (let i = 0; i < this.turrets.length; i++) this.turrets[i].syncTurrets(); + } + upgrade(number, branchId) { + // Account for upgrades that are too high level for the player to access + for (let i = 0; i < branchId; i++) { + number += this.skippedUpgrades[i] ?? 0; + } if ( number < this.upgrades.length && this.skill.level >= this.upgrades[number].level @@ -1723,7 +1703,7 @@ class Entity extends EventEmitter { upgradeBranch = upgrade.branch, redefineAll = upgrade.redefineAll; if (redefineAll) { - for (let i = 0; i < upgradeClass.length; i++){ + for (let i = 0; i < upgradeClass.length; i++) { upgradeClass[i] = ensureIsClass(...upgradeClass[i]); } this.upgrades = []; @@ -1735,7 +1715,7 @@ class Entity extends EventEmitter { } this.emit("upgrade", { body: this }); if (this.color.base == '-1' || this.color.base == 'mirror') { - if (c.GROUPS || (c.MODE == 'ffa' && !c.TAG)) { + if (Config.GROUPS || (Config.MODE == 'ffa' && !Config.TAG)) { this.color.base = this.isBot ? "darkGrey" : getTeamColor(TEAM_RED); } else { this.color.base = getTeamColor(this.team); @@ -1775,70 +1755,84 @@ class Entity extends EventEmitter { } move() { let g = { - x: this.control.goal.x - this.x, - y: this.control.goal.y - this.y, - }, + x: this.control.goal.x - this.x, + y: this.control.goal.y - this.y, + }, gactive = g.x !== 0 || g.y !== 0, engine = { x: 0, y: 0, - }, - a = this.acceleration / c.runSpeed; - if (c.SPACE_PHYSICS) { - this.maxSpeed = this.topSpeed; - this.damp = 100; - } - let type = this.motionType[0], - args = this.motionType[1]; - switch (type) { + }; + switch (this.motionType) { case "grow": - this.SIZE += args.growSpeed ?? 1; + this.SIZE += this.motionTypeArgs.growSpeed ?? 1; break; case "fastgrow": - this.SIZE += args.growSpeed ?? 5; + this.SIZE += this.motionTypeArgs.growSpeed ?? 5; + break; + case "fuckingnuclearbomb": + this.SIZE += this.motionTypeArgs.growSpeed ?? 10; + break; + case "trappershockwave": + this.SIZE += this.motionTypeArgs.growSpeed ?? 20; + break; + case "shrink": + this.SIZE -= this.motionTypeArgs.growSpeed ?? 1; + break; + case "solarioarena": + if (this.SIZE > 199) break; + this.SIZE += this.motionTypeArgs.growSpeed ?? 2; break; case "glide": this.maxSpeed = this.topSpeed; - this.damp = args.damp ?? 0.05; + this.damp = this.motionTypeArgs.damp ?? 0.05; break; case "motor": this.maxSpeed = 0; if (this.topSpeed) { - this.damp = Math.abs(a) / this.topSpeed; + this.damp = Math.abs(this.scaledAcceleration) / this.topSpeed; } if (gactive) { - let len = Math.sqrt(g.x * g.x + g.y * g.y); + let len = Math.sqrt(g.x ** 2 + g.y ** 2); engine = { - x: (a * g.x) / len, - y: (a * g.y) / len, + x: (this.scaledAcceleration * g.x) / len, + y: (this.scaledAcceleration * g.y) / len, }; } break; case "spgw": - this.SIZE += args.growSpeed ?? 0.75; + this.SIZE += this.motionTypeArgs.growSpeed ?? 0.75; this.maxSpeed = this.topSpeed; - this.damp = args.damp ?? -0.025; + this.damp = this.motionTypeArgs.damp ?? -0.025; break; case "chonk": - this.SIZE += args.growSpeed ?? 50; + this.SIZE += this.motionTypeArgs.growSpeed ?? 50; this.maxSpeed = this.topSpeed; - this.damp = args.damo ?? -0.025; + this.damp = this.motionTypeArgs.damp ?? -0.025; break; + case "accelerate": + this.velocity.x += 4.5 * Math.cos(this.facing) + this.velocity.y += 4.5 * Math.sin(this.facing) + this.topSpeed += 30; + this.maxSpeed += 30; + this.damp = -0.0125; + //this.damage += 0.45 for now... + break; + case "acceleratetothespeedoflight": + this.velocity.x = this.velocity.x + ((1 * this.maxSpeed + 0.5) * Math.cos(this.facing)) + this.velocity.y = this.velocity.y + ((1 * this.maxSpeed + 0.5) * Math.sin(this.facing)) + this.topSpeed += 0.5; + this.maxSpeed += 0.5; + this.damp = -0.0001; + break; case "swarm": this.maxSpeed = this.topSpeed; - let l = - util.getDistance( - { - x: 0, - y: 0, - }, - g - ) + 1; + let l = Math.sqrt(g.x ** 2 + g.y ** 2) + 1; if (gactive && l > this.size) { let XvelDesired = (this.topSpeed * g.x) / l, YvelDesired = (this.topSpeed * g.y) / l, turning = Math.sqrt( - (this.topSpeed * Math.max(1, this.range) + 1) / a + (this.topSpeed * Math.max(1, this.range) + 1) / this.scaledAcceleration ); engine = { x: (XvelDesired - this.velocity.x) / Math.max(5, turning), @@ -1847,35 +1841,46 @@ class Entity extends EventEmitter { } else { if (this.velocity.length < this.topSpeed) { engine = { - x: (this.velocity.x * a) / 20, - y: (this.velocity.y * a) / 20, + x: (this.velocity.x * this.scaledAcceleration) / 20, + y: (this.velocity.y * this.scaledAcceleration) / 20, }; } } break; case "chase": - if (gactive) { - let l = util.getDistance({ x: 0, y: 0, }, g); - if (l > this.size * 2) { - this.maxSpeed = this.topSpeed; - let XvelDesired = (this.topSpeed * g.x) / l, - YvelDesired = (this.topSpeed * g.y) / l; - engine = { - x: (XvelDesired - this.velocity.x) * a, - y: (YvelDesired - this.velocity.y) * a, - }; - } else { - this.maxSpeed = 0; - } + // No DIV/0 protection because it's already protected against + let length = Math.sqrt(g.x ** 2 + g.y ** 2); + if (length > this.size * 2) { + this.maxSpeed = this.topSpeed; + let XvelDesired = (this.topSpeed * g.x) / length, + YvelDesired = (this.topSpeed * g.y) / length; + engine = { + x: (XvelDesired - this.velocity.x) * this.scaledAcceleration, + y: (YvelDesired - this.velocity.y) * this.scaledAcceleration, + }; } else { this.maxSpeed = 0; } break; + case "aimassist": + this.x = this.source.x + this.master.control.target.x; + this.y = this.source.y + this.master.control.target.y; + this.velocity.x = this.source.velocity.x; + this.velocity.y = this.source.velocity.y; + break; + case "aimassistlock": + if (!this.control.alt) { + this.x = this.source.x + this.master.control.target.x; + this.y = this.source.y + this.master.control.target.y; + this.velocity.x = this.source.velocity.x; + this.velocity.y = this.source.velocity.y; + }; + break; case "drift": this.maxSpeed = 0; engine = { - x: g.x * a, - y: g.y * a, + x: g.x * this.scaledAcceleration, + y: g.y * this.scaledAcceleration, }; break; case "bound": @@ -1889,6 +1894,7 @@ class Entity extends EventEmitter { this.firingArc = [ref.facing + bound.angle, bound.arc / 2]; this.accel.null(); this.blend = ref.blend; + if (this.bond.syncTurretSkills) this.skill.set(this.bond.master.skill.raw); break; case "withMaster": this.x = this.source.x; @@ -1908,14 +1914,24 @@ class Entity extends EventEmitter { break; case "desmos": this.damp = 0; + let save = { + x: this.master.x, + y: this.master.y, + }; + let target = { + x: this.master.x + this.master.control.target.x, + y: this.master.y + this.master.control.target.y, + }; + let amount = (util.getDistance(target, save) / 100) | 0; + amount = amount > 6 ? 6 : amount; if (this.waveReversed == null) this.waveReversed = this.master.control.alt ? -1 : 1; if (this.waveAngle == null) { this.waveAngle = this.master.facing; - this.velocity.x = this.velocity.length * Math.cos(this.waveAngle); - this.velocity.y = this.velocity.length * Math.sin(this.waveAngle);; + this.velocity.x = ((5 + this.velocity.length * (amount + 2)) * Math.cos(this.waveAngle)) / 7; + this.velocity.y = ((5 + this.velocity.length * (amount + 2)) * Math.sin(this.waveAngle)) / 7; } - let waveX = this.maxSpeed * 5 * Math.cos((this.RANGE - this.range) / (args.period ?? 4) * 2); - let waveY = (args.amplitude ?? 15) * Math.cos((this.RANGE - this.range) / (args.period ?? 4)) * this.waveReversed * (args.invert ? -1 : 1); + let waveX = this.maxSpeed * 5 * Math.cos((this.RANGE - this.range) / (this.motionTypeArgs.period ?? 4) * 2); + let waveY = (this.motionTypeArgs.amplitude ?? 15) * Math.cos((this.RANGE - this.range) / (this.motionTypeArgs.period ?? 4)) * this.waveReversed * (this.motionTypeArgs.invert ? -1 : 1); this.x += Math.cos(this.waveAngle) * waveX - Math.sin(this.waveAngle) * waveY; this.y += Math.sin(this.waveAngle) * waveX + Math.cos(this.waveAngle) * waveY; break; @@ -1928,33 +1944,29 @@ class Entity extends EventEmitter { } face() { let t = this.control.target, - tactive = t.x !== 0 || t.y !== 0, - oldFacing = this.facing, - oldVFacing = this.vfacing; - let type = this.facingType[0], - args = this.facingType[1]; - switch (type) { - case "autospin": - this.facing += (args.speed ?? 0.02) / c.runSpeed; - break; + oldFacing = this.facing; + switch (this.facingType) { case "turnWithSpeed": - this.facing += ((this.velocity.length / 90) * Math.PI) / c.runSpeed; + this.facing += ((this.velocity.length / 90) * Math.PI) / Config.runSpeed; + break; + case "autospin": + this.facing += (this.facingTypeArgs.speed ?? 0.02) / Config.runSpeed; break; case "spin": - this.facing += (args.speed ?? 0.05) / c.runSpeed; + this.facing += (this.facingTypeArgs.speed ?? 0.05) / Config.runSpeed; break; case "fastspin": - this.facing += (args.speed ?? 0.1) / c.runSpeed; + this.facing += (this.facingTypeArgs.speed ?? 0.1) / Config.runSpeed; break; case "veryfastspin": - this.facing += (args.speed ?? 1) / c.runSpeed; + this.facing += (this.facingTypeArgs.speed ?? 1) / Config.runSpeed; break; case "withMotion": this.facing = this.velocity.direction; break; case "smoothWithMotion": case "looseWithMotion": - this.facing = util.interpolateAngle(this.facing, this.velocity.direction, c.runSpeed / (args.speed ?? 4)); + this.facing = util.interpolateAngle(this.facing, this.velocity.direction, Config.runSpeed / (this.facingTypeArgs.speed ?? 4)); break; case "withTarget": case "toTarget": @@ -1964,18 +1976,21 @@ class Entity extends EventEmitter { case "locksFacing": if (!this.control.alt) this.facing = Math.atan2(t.y, t.x); break; + case "withMaster": + if (this.master.independent) this.facing = this.master.facing + break; case "looseWithTarget": case "looseToTarget": case "smoothToTarget": - this.facing = util.interpolateAngle(this.facing, Math.atan2(t.y, t.x), c.runSpeed / (args.speed ?? 4)); + this.facing = util.interpolateAngle(this.facing, Math.atan2(t.y, t.x), Config.runSpeed / (this.facingTypeArgs.speed ?? 4)); break; case "noFacing": - this.facing = args.angle ?? 0; + this.facing = this.facingTypeArgs.angle ?? 0; break; case "bound": let angleToTarget, angleDiff = 3, reduceIndependence = false, - slowness = this.settings.mirrorMasterAngle ? 1 : (args.slowness ?? 4) / c.runSpeed; + slowness = this.settings.mirrorMasterAngle ? 1 : (this.facingTypeArgs.slowness ?? 4) / Config.runSpeed; if (this.control.main) { angleToTarget = Math.atan2(t.y, t.x); angleDiff = Math.abs(util.angleDifference(angleToTarget, this.firingArc[0])); @@ -1988,12 +2003,12 @@ class Entity extends EventEmitter { reduceIndependence = true; } if (reduceIndependence) { - this.perceptionAngleIndependence -= 0.3 / c.runSpeed; + this.perceptionAngleIndependence -= 0.3 / Config.runSpeed; if (this.perceptionAngleIndependence < 0) { this.perceptionAngleIndependence = 0; } } else { - this.perceptionAngleIndependence += 0.3 / c.runSpeed; + this.perceptionAngleIndependence += 0.3 / Config.runSpeed; if (this.perceptionAngleIndependence > 1) { this.perceptionAngleIndependence = 1; } @@ -2003,13 +2018,11 @@ class Entity extends EventEmitter { } this.facing += this.turnAngle; // Loop - const TAU = 2 * Math.PI; if (this.facingLocked) { this.facing = oldFacing; - this.vfacing = oldVFacing; } else { - this.facing = ((this.facing % TAU) + TAU) % TAU; - this.vfacing = util.angleDifference(oldFacing, this.facing) * c.runSpeed; + // note: double mod is just as expensive as simple add/subtract - it's not that bad + this.facing = ((this.facing % Math.TAU) + Math.TAU) % Math.TAU; } } takeSelfie() { @@ -2032,18 +2045,18 @@ class Entity extends EventEmitter { this.accel.null(); // Apply motion this.stepRemaining = 1; - if (c.SPACE_PHYSICS) this.stepRemaining = 2; - this.x += (this.stepRemaining * this.velocity.x) / c.runSpeed; - this.y += (this.stepRemaining * this.velocity.y) / c.runSpeed; + if (Config.SPACE_PHYSICS) this.stepRemaining = 2; + this.x += (this.stepRemaining * this.velocity.x) / Config.runSpeed; + this.y += (this.stepRemaining * this.velocity.y) / Config.runSpeed; } friction() { var motion = this.velocity.length, excess = motion - this.maxSpeed; if (excess > 0 && this.damp) { - var k = this.damp / c.runSpeed, + var k = this.damp / Config.runSpeed, drag = excess / (k + 1), finalvelocity = this.maxSpeed + drag; - if (c.SPACE_PHYSICS) + if (Config.SPACE_PHYSICS) finalvelocity *= this.type === "bullet" ? 1.005 : 1.1; this.velocity.x = (finalvelocity * this.velocity.x) / motion; this.velocity.y = (finalvelocity * this.velocity.y) / motion; @@ -2060,25 +2073,25 @@ class Entity extends EventEmitter { return 0; } if (!this.settings.canGoOutsideRoom) { - if (c.ARENA_TYPE === "circle") { + if (Config.ARENA_TYPE === "circle") { let centerPoint = { x: room.width / 2, y: room.height / 2, }, dist = util.getDistance(this, centerPoint); if (dist > room.width / 2) { - let strength = (dist - room.width / 2) * c.ROOM_BOUND_FORCE / (c.runSpeed * 750); - this.x = lerp(this.x, centerPoint.x, strength); - this.y = lerp(this.y, centerPoint.y, strength); + let strength = (dist - room.width / 2) * Config.ROOM_BOUND_FORCE / (Config.runSpeed * 750); + this.x = util.lerp(this.x, centerPoint.x, strength); + this.y = util.lerp(this.y, centerPoint.y, strength); } } else { let padding = this.realSize - 50; - this.accel.x -= Math.max(this.x + padding - room.width, Math.min(this.x - padding, 0)) * c.ROOM_BOUND_FORCE / c.runSpeed; - this.accel.y -= Math.max(this.y + padding - room.height, Math.min(this.y - padding, 0)) * c.ROOM_BOUND_FORCE / c.runSpeed; + this.accel.x -= Math.max(this.x + padding - this.confinement.xMax, Math.min(this.x - padding - this.confinement.xMin, 0)) * Config.ROOM_BOUND_FORCE / Config.runSpeed; + this.accel.y -= Math.max(this.y + padding - this.confinement.yMax, Math.min(this.y - padding - this.confinement.yMin, 0)) * Config.ROOM_BOUND_FORCE / Config.runSpeed; } } } contemplationOfMortality() { - if (this.invuln) { + if (this.invuln || this.godmode) { this.damageReceived = 0; return 0; } @@ -2096,7 +2109,7 @@ class Entity extends EventEmitter { } // Life-limiting effects if (this.settings.diesAtRange) { - this.range -= 1 / c.runSpeed; + this.range -= 1 / Config.runSpeed; if (this.range < 0) { this.kill(); } @@ -2106,7 +2119,7 @@ class Entity extends EventEmitter { !this.collisionArray.length && this.velocity.length < this.topSpeed / 2 ) { - this.health.amount -= this.health.getDamage(1 / c.runSpeed); + this.health.amount -= this.health.getDamage(1 / Config.runSpeed); } } // Shield regen and damage @@ -2133,10 +2146,12 @@ class Entity extends EventEmitter { for (let i = 0; i < this.guns.length; i++) { let gun = this.guns[i]; if (gun.shootOnDeath && gun.body != null) { - gun.spawnBullets(); + gun.fire(); } } + this.variables = {}; + // MEMORY LEAKS ARE BAD!!!! for (let i = 0; i < this.turrets.length; i++) { this.turrets[i].kill(); @@ -2176,8 +2191,8 @@ class Entity extends EventEmitter { this.emit('death', { body: this, killers, killTools }); killers.forEach((e) => e.emit('kill', { body: e, entity: this })); // If there's no valid killers (you were killed by food), change the message to be more passive - let killText = notJustFood ? "" : "You have been killed by ", - dothISendAText = this.settings.givesKillMessage; + let killText = "You have been killed by ", + doISendAText = this.settings.givesKillMessage; for (let i = 0; i < killers.length; i++) { let instance = killers[i]; @@ -2185,15 +2200,42 @@ class Entity extends EventEmitter { switch (this.type) { case "tank": killers.length > 1 ? instance.killCount.assists++ : instance.killCount.solo++; + switch(instance.killCount.solo) { + + case 5: + if (instance.socket) instance.socket.talk("achieve", 0); + break; + + case 10: + if (instance.socket) instance.socket.talk("achieve", 1); + sockets.broadcast(instance.name + " is on a kill streak of 10!"); + break; + + case 25: + sockets.broadcast(instance.name + " is on a kill streak of 25!"); + break; + + case 50: + sockets.broadcast(instance.name + " is on a kill streak of 50!"); + break; + + case 100: + sockets.broadcast(instance.name + " has become the Harbinger of Death"); + break; + + } + if (instance.socket) instance.socket.talk("killgained"); break; case "food": case "crasher": instance.killCount.polygons++; + if (instance.socket) instance.socket.talk("shapegained"); break case "miniboss": instance.killCount.bosses++; + if (instance.socket) instance.socket.talk("achieve", 3); break; } @@ -2208,7 +2250,7 @@ class Entity extends EventEmitter { killText += " and "; } // Only if we give messages - if (dothISendAText) { + if (doISendAText) { instance.sendMessage("You killed " + name + (killers.length > 1 ? " (with some help)." : ".")); } if (this.settings.killMessage) { @@ -2257,7 +2299,9 @@ class Entity extends EventEmitter { if (killText === "You have been kille") { killText = "You have died a stupid death"; } + if (!this.dontSendDeathMessage) { this.sendMessage(killText + "."); + } // If I'm the leader, broadcast it: if (this.id === room.topPlayerID) { let usurptText = this.name === "" ? "The leader" : this.name; @@ -2284,7 +2328,7 @@ class Entity extends EventEmitter { entitiesToAvoid.push(this); this.isProtected = true; } - say(message, duration = c.CHAT_MESSAGE_DURATION) { + say(message, duration = Config.CHAT_MESSAGE_DURATION) { if (!chats[this.id]) { chats[this.id] = []; } @@ -2311,8 +2355,9 @@ class Entity extends EventEmitter { view.remove(this); } // Remove from parent lists if needed - if (this.parent != null) + if (this.parent != null) { util.remove(this.parent.children, this.parent.children.indexOf(this)); + } // Kill all of its children for (let instance of entities) { if (instance.source.id === this.id) { @@ -2331,7 +2376,9 @@ class Entity extends EventEmitter { } } // Remove everything bound to it - for (let i = 0; i < this.turrets.length; i++) this.turrets[i].destroy(); + for (let i = 0; i < this.turrets.length; i++) { + this.turrets[i].destroy(); + } // Remove from the collision grid this.removeFromGrid(); this.isGhost = true; @@ -2340,4 +2387,4 @@ class Entity extends EventEmitter { return this.health.amount <= 0; } } -module.exports = { init, StatusEffect, Gun, Entity }; \ No newline at end of file +module.exports = { StatusEffect, Gun, Entity }; diff --git a/server/modules/live/entitySubFunctions.js b/server/modules/live/entitySubFunctions.js index e176356e6..d7611f9ad 100644 --- a/server/modules/live/entitySubFunctions.js +++ b/server/modules/live/entitySubFunctions.js @@ -13,9 +13,9 @@ const skcnv = { let curvePoints = []; for (let i = 0; i < 256; i++) { - curvePoints.push(Math.log(4 * (i / c.MAX_SKILL) + 1) / 1.6); + curvePoints.push(Math.log(4 * (i / Config.MAX_SKILL) + 1) / 1.6); } -let curve = x => curvePoints[x * c.MAX_SKILL]; +let curve = x => curvePoints[x * Config.MAX_SKILL]; function apply(f, x) { return x < 0 ? 1 / (1 - x * f) : f * x + 1; } @@ -25,7 +25,7 @@ class Skill { // Just skill stuff. this.raw = inital; this.caps = []; - this.setCaps([ c.MAX_SKILL, c.MAX_SKILL, c.MAX_SKILL, c.MAX_SKILL, c.MAX_SKILL, c.MAX_SKILL, c.MAX_SKILL, c.MAX_SKILL, c.MAX_SKILL, c.MAX_SKILL ]); + this.setCaps([ Config.MAX_SKILL, Config.MAX_SKILL, Config.MAX_SKILL, Config.MAX_SKILL, Config.MAX_SKILL, Config.MAX_SKILL, Config.MAX_SKILL, Config.MAX_SKILL, Config.MAX_SKILL, Config.MAX_SKILL ]); this.name = [ "Reload", "Bullet Penetration", @@ -54,12 +54,13 @@ class Skill { this.acl = 0; this.reset(); } - reset() { + reset(resetLSPF = true) { this.points = 0; this.score = 0; this.deduction = 0; this.level = 0; - this.LSPF = null; + this.levelUpScore = 1; + if (resetLSPF) this.LSPF = null; this.set([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); this.maintain(); } @@ -72,7 +73,7 @@ class Skill { } let attrib = []; for (let i = 0; i < 10; i++) { - attrib[i] = curve(this.raw[i] / c.MAX_SKILL); + attrib[i] = curve(this.raw[i] / Config.MAX_SKILL); } this.rld = Math.pow(0.5, attrib[skcnv.rld]); this.pen = apply(2.5, attrib[skcnv.pen]); @@ -82,9 +83,9 @@ class Skill { this.acl = apply(0.5, attrib[skcnv.rld]); this.rst = 0.5 * attrib[skcnv.str] + 2.5 * attrib[skcnv.pen]; this.ghost = attrib[skcnv.pen]; - this.shi = c.GLASS_HEALTH_FACTOR * apply(3 / c.GLASS_HEALTH_FACTOR - 1, attrib[skcnv.shi]); + this.shi = Config.GLASS_HEALTH_FACTOR * apply(3 / Config.GLASS_HEALTH_FACTOR - 1, attrib[skcnv.shi]); this.atk = apply(0.021, attrib[skcnv.atk]); - this.hlt = c.GLASS_HEALTH_FACTOR * apply(2 / c.GLASS_HEALTH_FACTOR - 1, attrib[skcnv.hlt]); + this.hlt = Config.GLASS_HEALTH_FACTOR * apply(2 / Config.GLASS_HEALTH_FACTOR - 1, attrib[skcnv.hlt]); this.mob = apply(0.8, attrib[skcnv.mob]); this.rgn = apply(25, attrib[skcnv.rgn]); this.brst = 0.3 * (0.5 * attrib[skcnv.atk] + 0.5 * attrib[skcnv.hlt] + attrib[skcnv.rgn]); @@ -117,20 +118,24 @@ class Skill { } maintain() { if (this.score - this.deduction >= this.levelScore) { - this.deduction += this.levelScore; + this.deduction = this.levelUpScore; this.level += 1; + this.levelUpScore = this.scoreForLevel; this.points += this.levelPoints; this.update(); } } + get scoreForLevel() { + return Math.ceil(Math.pow(this.level, 3) * 0.3083); + } get levelScore() { - return Math.ceil(1.8 * Math.pow(this.level + 1, 1.8) - 2 * this.level + 1); + return this.levelUpScore - this.deduction; } get progress() { return this.levelScore ? (this.score - this.deduction) / this.levelScore : 0; } get levelPoints() { - return this.LSPF ? this.LSPF(this.level) : c.LEVEL_SKILL_POINT_FUNCTION(this.level); + return this.LSPF ? this.LSPF(this.level) : Config.LEVEL_SKILL_POINT_FUNCTION(this.level); } cap(skill, real = false) { return this.caps[skcnv[skill]]; @@ -190,17 +195,18 @@ class HealthType { switch (this.type) { case "static": if (this.amount >= this.max || !this.amount) break; - this.amount += cons * (this.max / 10 / 60 / 2.5 + boost); + this.amount += cons * boost; break; case "dynamic": - let r = util.clamp(this.amount / this.max, 0, 1); - if (!r) { + let r = this.amount / this.max; + if (r <= 0) { this.amount = 0.0001; - } - if (r === 1) { + } else if (r >= 1) { this.amount = this.max; } else { - this.amount += cons * ((this.regen * Math.exp(-50 * Math.pow(Math.sqrt(0.5 * r) - 0.4, 2))) / 3 + (r * this.max) / 10 / 15 + boost); + // this regen multiplier is this curve: https://www.desmos.com/calculator/ghjggwdp6h + let regenMultiplier = Math.exp(Math.pow(Math.sqrt(r / 2) - 0.4, 2) * -50); + this.amount += cons * (this.regen * regenMultiplier / 3 + (r * this.max) / 150 + boost); } break; } diff --git a/server/modules/network/discoverability.js b/server/modules/network/discoverability.js index 9212bfd9b..afba6da56 100644 --- a/server/modules/network/discoverability.js +++ b/server/modules/network/discoverability.js @@ -1 +1,5 @@ -// TODO: Add stuff that submits this server to server browsers \ No newline at end of file +// IP and if has https proxy +// NOTE: Server auto adds itself to the list +module.exports = [ + [] +]; \ No newline at end of file diff --git a/server/modules/network/sockets.js b/server/modules/network/sockets.js index c1739bb8e..e2602d286 100644 --- a/server/modules/network/sockets.js +++ b/server/modules/network/sockets.js @@ -38,10 +38,12 @@ function close(socket) { timeout: timeout, }; disconnections.push(disconnection); + player.command.autospin = false; + player.body.life(); } } // Disconnect everything - util.log("[INFO] " + (player.body ? "User " + player.body.name : "A user without an entity") + " disconnected!"); + util.log("[INFO] " + (player.body ? `User ${player.body.name == "" ? "A unnamed player" : player.body.name}` : "A user without an entity") + " disconnected!"); util.remove(players, index); } else { util.log("[INFO] A player disconnected before entering the game."); @@ -70,8 +72,7 @@ function chatLoop() { // send chat messages to everyone for (let view of views) { - let nearby = view.getNearby(), - spammersAdded = 0, + let spammersAdded = 0, array = []; // data format: @@ -80,7 +81,7 @@ function chatLoop() { // entityId2, chatMessageCount2, chatMsg2_1, chatExp2_1, chatMsg2_2, chatExp2_2, ... , // entityId3, chatMessageCount3, chatMsg3_1, chatExp3_1, chatMsg3_2, chatExp3_2, ... , // ... ] - for (let entity of nearby) { + for (let entity of view.nearby) { let id = entity.id; if (chats[id]) { spammersAdded++; @@ -133,29 +134,35 @@ function incoming(message, socket) { let key = m[0].toString().trim(); socket.permissions = permissionsDict[key]; if (socket.permissions) { - util.log("[INFO] A socket was verified with the token: " + key); + util.log(`[INFO] A socket ( ${socket.ip} ) was verified with the token: ${key}`); } else { - util.log("[WARNING] A socket failed to verify with the token: " + key); + util.log(`[WARNING] A socket ( ${socket.ip} ) failed to verify with the token: ${key}`); + if (key !== "") { + socket.talk("achieve", 2); + } } socket.key = key; } socket.verified = true; + util.log(`[INFO] A socket ( ${socket.ip} ) has been welcomed to the server room. Waiting for spawn request.`); util.log("Clients: " + clients.length); break; case "s": // spawn request + util.log(`[INFO] A socket ( ${socket.ip} ) is asking for spawn request, checking all securities...`); if (!socket.status.deceased) { socket.kick("Trying to spawn while already alive."); return 1; } - if (m.length !== 3) { - socket.kick("Ill-sized spawn request."); + if (m.length !== 4) { + socket.kick("Ill-sized spawn request." + global.playerskin + m.length); return 1; } // Get data - let name = m[0].replace(c.BANNED_CHARACTERS_REGEX, ""); + let name = m[0].replace(Config.BANNED_CHARACTERS_REGEX, ""); let needsRoom = m[1]; let autoLVLup = m[2]; + global.playerskin = m[3].replace(name, ""); // Verify it if (typeof name != "string") { socket.kick("Bad spawn request name."); @@ -185,11 +192,12 @@ function incoming(message, socket) { util.remove(views, views.indexOf(socket.view)); socket.makeView(); } + util.log("[INFO] Passed the security, spawning player."); socket.party = m[4]; socket.player = socket.spawn(name); if (autoLVLup) { - while (socket.player.body.skill.level < c.LEVEL_CHEAT_CAP) { + while (socket.player.body.skill.level < Config.LEVEL_CHEAT_CAP) { socket.player.body.skill.score += socket.player.body.skill.levelScore; socket.player.body.skill.maintain(); socket.player.body.refreshBodyAttributes(); @@ -198,9 +206,21 @@ function incoming(message, socket) { //socket.view.gazeUpon(); //socket.lastUptime = Infinity; // Give it the room state - socket.talk("R", room.width, room.height, JSON.stringify(room.setup.map(x => x.map(t => t.color.compiled))), JSON.stringify(util.serverStartTime), c.runSpeed, c.ARENA_TYPE); + if (needsRoom) socket.talk( + "R", + room.width, + room.height, + JSON.stringify(room.setup.map(x => x.map(t => t.color.compiled))), + JSON.stringify(util.serverStartTime), + Config.runSpeed, + Config.ARENA_TYPE + ); + // Give the server name + if (needsRoom) socket.talk("svInfo", Config.gameModeName, "?"); + // More important stuff + socket.talk("updateName", socket.player.body.name); // Log it - util.log(`[INFO] ${m[0]} ${needsRoom ? "joined" : "rejoined"} the game on team ${socket.player.body.team}! Players: ${players.length}`); + util.log(`[INFO] ${name == "" ? "An unnamed player" : m[0]} ${needsRoom ? "joined" : "rejoined"} the game on team ${socket.player.body.team}! Players: ${players.length}`); break; case "S": // clock syncing @@ -216,7 +236,7 @@ function incoming(message, socket) { return 1; } // Bounce it back - socket.talk("S", synctick, util.time()); + socket.talk("S", synctick, performance.now()); break; case "p": // ping @@ -233,7 +253,7 @@ function incoming(message, socket) { } // Pong socket.talk("p", m[0]); // Just pong it right back - socket.status.lastHeartbeat = util.time(); + socket.status.lastHeartbeat = performance.now(); break; case "d": // downlink @@ -253,7 +273,7 @@ function incoming(message, socket) { break; case "C": // command packet - if (m.length !== 4) { + if (m.length !== 5) { socket.kick("Ill-sized command packet."); return 1; } @@ -263,11 +283,13 @@ function incoming(message, socket) { y: m[1], }, reverseTank = m[2], - commands = m[3]; + movement = m[3], + commands = m[4]; // Verify data if ( typeof target.x !== "number" || typeof target.y !== "number" || + typeof movement !== "number" || typeof commands !== "number" ) { socket.kick("Weird downlink."); @@ -278,7 +300,7 @@ function incoming(message, socket) { return 1; } // Will not work out - // if (c.SPACE_MODE && player.body) { + // if (Config.SPACE_MODE && player.body) { // let spaceOffsetAngle = Math.atan2( // room.width / 2 - player.body.x, // room.height / 2 - player.body.y @@ -295,21 +317,22 @@ function incoming(message, socket) { if (player.body) player.body.reverseTank = reverseTank; // Process the commands if (player.command != null && player.body != null) { - player.command.up = commands & 1; - player.command.down = (commands & 2) >> 1; - player.command.left = (commands & 4) >> 2; - player.command.right = (commands & 8) >> 3; - player.command.lmb = (commands & 16) >> 4; - player.command.mmb = (commands & 32) >> 5; - player.command.rmb = (commands & 64) >> 6; + let moving = commands & 1; + player.command.movement = moving ? { + x: Math.cos(movement), + y: Math.sin(movement) + } : { x: 0, y: 0 }; + player.command.lmb = (commands & 2) >> 1; + player.command.mmb = (commands & 4) >> 2; + player.command.rmb = (commands & 8) >> 3; } // Update the thingy socket.timeout.set(commands); break; case "t": // player toggle - if (m.length !== 1) { - socket.kick("Ill-sized toggle."); + if (m.length !== 2) { + socket.kick("Ill-sized toggle." + m.length); return 1; } // Get data @@ -319,14 +342,12 @@ function incoming(message, socket) { socket.kick("Weird toggle."); return 1; } - + let sendMessage = m[1]; // ...what are we supposed to do? let given = [ "autospin", "autofire", "override", - "reverse mouse", //reverse mouse does nothing server-side, it's easier to make the client send swapped inputs - "reverse tank", //reverse tank does nothing server-side, it's easier to make the client turn around 180 degrees "autoalt", "spinlock" //spinlock does something both in client and server side ][tog]; @@ -340,25 +361,26 @@ function incoming(message, socket) { if (player.command != null && player.body != null) { player.command[given] = !player.command[given]; // Send a message. - player.body.sendMessage(given.charAt(0).toUpperCase() + given.slice(1) + (player.command[given] ? " enabled." : " disabled.")); + if (sendMessage) player.body.sendMessage(given.charAt(0).toUpperCase() + given.slice(1) + (player.command[given] ? " enabled." : " disabled.")); } break; case "U": // upgrade request - if (m.length !== 1) { + if (m.length !== 2) { socket.kick("Ill-sized upgrade request."); return 1; } // Get data let upgrade = m[0]; + let branchId = m[1]; // Verify the request - if (typeof upgrade != "number" || upgrade < 0) { + if (typeof upgrade != "number" || upgrade < 0 || typeof branchId != "number" || branchId < 0) { socket.kick("Bad upgrade request."); return 1; } // Upgrade it if (player.body != null) { - player.body.upgrade(upgrade); // Ask to upgrade + player.body.upgrade(upgrade, branchId); // Ask to upgrade } break; case "x": @@ -404,7 +426,7 @@ function incoming(message, socket) { } // cheatingbois if (player.body == null || player.body.underControl) return; - if (player.body.skill.level < c.LEVEL_CHEAT_CAP || (socket.permissions && socket.permissions.infiniteLevelUp)) { + if (player.body.skill.level < Config.LEVEL_CHEAT_CAP || (socket.permissions && socket.permissions.infiniteLevelUp)) { player.body.skill.score += player.body.skill.levelScore; player.body.skill.maintain(); player.body.refreshBodyAttributes(); @@ -417,11 +439,11 @@ function incoming(message, socket) { return 1; } // cheatingbois - if (player.body != null && socket.permissions && socket.permissions.class) { + if (player.body != null && ((socket.permissions && socket.permissions.class) || Config.GAME_MODES[0] == 'sandbox')) { player.body.define({ RESET_UPGRADES: true, BATCH_UPGRADES: false }); - player.body.define(socket.permissions.class); + Config.GAME_MODES[0] == 'sandbox' ? player.body.define("developer") : player.body.define(socket.permissions.class); if (player.body.color.base == '-1' || player.body.color.base == 'mirror') { - player.body.color.base = getTeamColor((c.GROUPS || (c.MODE == 'ffa' && !c.TAG)) ? TEAM_RED : player.body.team); + player.body.color.base = getTeamColor((Config.GROUPS || (Config.MODE == 'ffa' && !Config.TAG)) ? TEAM_RED : player.body.team); } } break; @@ -437,6 +459,170 @@ function incoming(message, socket) { player.body.destroy(); } break; + case "testTeleport": + if (player.body != null && (socket.permissions || Config.GAME_MODES[0] == 'sandbox')) { + player.body.x = player.body.x + player.target.x; + player.body.y = player.body.y + player.target.y; + } + break; + case "smallerTank": + if (player.body != null && (socket.permissions || Config.GAME_MODES[0] == 'sandbox')) { + player.body.SIZE *= 4/5; + player.body.RECOIL_MULTIPLIER *= 4/5; + } + break; + case "biggerTank": + if (player.body != null && (socket.permissions || Config.GAME_MODES[0] == 'sandbox')) { + player.body.SIZE *= 5/4; + player.body.RECOIL_MULTIPLIER *= 5/4; + } + break; + case "smallerFOV": + if (player.body != null && (socket.permissions || Config.GAME_MODES[0] == 'sandbox')) { + player.body.FOV *= 4/5 + } + break; + case "biggerFOV": + if (player.body != null && (socket.permissions || Config.GAME_MODES[0] == 'sandbox')) { + player.body.FOV *= 5/4 + } + break; + case "godmodeButton": + if (player.body != null && (socket.permissions || Config.GAME_MODES[0] == 'sandbox')) { + player.body.godmode = !player.body.godmode; + player.body.sendMessage((player.body.godmode ? "Godmode enabled." : "Godmode disabled.")); + } + break; + case "invisibility": + if (player.body != null && (socket.permissions || Config.GAME_MODES[0] == 'sandbox')) { + player.body.alpha = !player.body.alpha; + player.body.invisible = [player.body.alpha, !player.body.alpha] + } + break; + case "canBeOnLeaderboard": + if (player.body != null && (socket.permissions || Config.GAME_MODES[0] == 'sandbox')) { + player.body.settings.leaderboardable = !player.body.settings.leaderboardable; + player.body.sendMessage((player.body.settings.leaderboardable ? "You have been added to the leaderboard" : "You have been removed from the leaderboard.")); + } + break; + case "keyStrong"://keyStrong + if (player.body != null && (socket.permissions || Config.GAME_MODES[0] == 'sandbox')) { + player.body.skill.raw = Array(10).fill(12); + player.body.skill.setCaps(Array(10).fill(12)); + player.body.refreshBodyAttributes(); + } + break; + case "drag": { // drag + if (player.body != null && (socket.permissions || Config.GAME_MODES[0] == 'sandbox')) { + if (!player.pickedUpInterval) { + let tx = player.body.x + player.target.x; + let ty = player.body.y + player.target.y; + let pickedUp = []; + entities.forEach(e => { + if (!(e.type === "mazeWall" && e.shape === 4) && (e.x - tx) * (e.x - tx) + (e.y - ty) * (e.y - ty) < e.size * e.size * 1.5) { + pickedUp.push({ e, dx: e.x - tx, dy: e.y - ty }); + } + }); + if (pickedUp.length === 0) { + player.body.sendMessage('No entities found to pick up!'); + } else { + player.pickedUpInterval = setInterval(() => { + if (!player.body) { + clearInterval(player.pickedUpInterval); + player.pickedUpInterval = null; + return; + } + let tx = player.body.x + player.target.x; + let ty = player.body.y + player.target.y; + for (let { e: entity, dx, dy } of pickedUp) + if (!entity.isGhost) { + entity.x = dx + tx; + entity.y = dy + ty; + } + }, 25); + } + } else { + clearInterval(player.pickedUpInterval); + player.pickedUpInterval = null; + } + } + } break; + case "watchThis": { // Kill what your mouse is over //watchThis + if (player.body != null && (socket.permissions || Config.GAME_MODES[0] == 'sandbox')) { + entities.forEach(o => { + if (o !== player.body != null && util.getDistance(o, { + x: player.target.x + player.body.x, + y: player.target.y + player.body.y + }) < o.size * 1.3) { + o.kill(); + o.destroy(); + } + }); + } break; + } + break; + case "heal": { // Kill what your mouse is over + if (player.body != null && (socket.permissions || Config.GAME_MODES[0] == 'sandbox')) { + entities.forEach(o => { + if (o !== player.body != null && util.getDistance(o, { + x: player.target.x + player.body.x, + y: player.target.y + player.body.y + }) < o.size * 1.3) { + o.health.amount = o.health.max + o.shield.amount = o.shield.max + } + }); + } break; + } + break; + case "randomTestKey": { // Spawn entities at mouse + if (player.body != null && (socket.permissions || Config.GAME_MODES[0] == 'sandbox')) { + let loc = { + x: (30 * Math.round((player.target.x + player.body.x - 15)/30))+15, + y: (30 * Math.round((player.target.y + player.body.y - 15)/30))+15, + }; + { + let o; { + o = new Entity(loc); + o.define(Class.placeableWallSmall); + } + } + } break;} break; + case "spawnWall": { // Spawn entities at mouse + if (player.body != null && (socket.permissions || Config.GAME_MODES[0] == 'sandbox')) { + entities.forEach(o => { + if (o !== player.body != null /*&& global.canKill != false*/ && o.label === "Wall" && util.getDistance(o, { + x: player.target.x + player.body.x, + y: player.target.y + player.body.y + }) < o.size) { + o.kill(); + o.destroy(); + global.canPlaceWall = false; + }; //else { global.canKill = true;} + }); + if (player.body != null && socket.permissions && global.canPlaceWall != false) { + let loc = { + x: (30 * Math.round((player.target.x + player.body.x+15)/30))-15, + y: (30 * Math.round((player.target.y + player.body.y+15)/30))-15, + }; + { + let e; { + e = new Entity(loc); + // global.canPlaceWall = false; + // global.canKill = false; + e.define(Class.wall); + e.TEAM = TEAM_ROOM; + e.SIZE = 45; + } + e.protect(); + e.life(); + }break;} else {global.canPlaceWall = true } +} break; +} break; + case "nullallalallalala": + if (player.body != null && (socket.permissions || Config.GAME_MODES[0] == 'sandbox')) { + player.body.sendMessage("turi ip ip ip") + } break; case "A": if (player.body != null) return 1; let possible = [] @@ -444,7 +630,7 @@ function incoming(message, socket) { let entry = entities[i]; if (entry.type === "miniboss") possible.push(entry); if (entry.isDominator || entry.isMothership || entry.isArenaCloser) possible.push(entry); - if (c.MODE === "tdm" && socket.rememberedTeam === entry.team && entry.type === "tank" && entry.bond == null) possible.push(entry); + if (Config.MODE === "tdm" && socket.rememberedTeam === entry.team && entry.type === "tank" && entry.bond == null) possible.push(entry); } if (!possible.length) { player.body.sendMessage("There are no entities to spectate!"); @@ -462,11 +648,11 @@ function incoming(message, socket) { let body = player.body; body.emit("control", { body }) if (body.underControl) { - if (c.DOMINATOR_LOOP) { + if (Config.DOMINATOR_LOOP) { player.body.sendMessage("You have relinquished control of the dominator."); body.giveUp(player, body.isDominator ? "" : undefined); return 1; - } else if (c.MOTHERSHIP_LOOP) { + } else if (Config.MOTHERSHIP_LOOP) { player.body.sendMessage("You have relinquished control of the mothership."); body.giveUp(player, body.isDominator ? "" : undefined); return 1; @@ -476,7 +662,7 @@ function incoming(message, socket) { return 1; } } - if (c.MOTHERSHIP_LOOP) { + if (Config.MOTHERSHIP_LOOP) { let motherships = entities .map((entry) => { if ( @@ -488,35 +674,40 @@ function incoming(message, socket) { }) .filter((instance) => instance); if (!motherships.length) { - player.body.sendMessage("There are no motherships available that are on your team."); + player.body.sendMessage("There are no motherships available that are on your team or already controlled by an player."); return 1; } let mothership = motherships.shift(); mothership.controllers = []; mothership.underControl = true; player.body = mothership; - body.kill(); player.body.become(player); - player.body.FOV += 0.5; + body.kill(); + if (!player.body.dontIncreaseFov) player.body.FOV += 0.5; + player.body.dontIncreaseFov = true; + player.body.skill.points = 0; player.body.refreshBodyAttributes(); player.body.name = body.name; player.body.sendMessage("You are now controlling the mothership."); player.body.sendMessage("Press F to relinquish control of the mothership."); - } else if (c.DOMINATOR_LOOP) { + } else if (Config.DOMINATOR_LOOP) { let dominators = entities.map((entry) => { if (entry.isDominator && entry.team === player.body.team && !entry.underControl) return entry; }).filter(x=>x); if (!dominators.length) { - player.body.sendMessage("There are no dominators available that are on your team!"); + player.body.sendMessage("There are no dominators available that are on your team or already controlled by an player."); return 1; } let dominator = dominators.shift(); dominator.controllers = []; dominator.underControl = true; player.body = dominator; - body.kill(); player.body.become(player, true); - player.body.FOV += 0.5; + body.dontSendDeathMessage = true; + body.kill(); + if (!player.body.dontIncreaseFov) player.body.FOV += 0.5; + player.body.dontIncreaseFov = true; + player.body.skill.points = 0; player.body.refreshBodyAttributes(); player.body.name = body.name; player.body.sendMessage("You are now controlling the dominator."); @@ -525,35 +716,56 @@ function incoming(message, socket) { player.body.sendMessage("There are no special tanks in this mode that you can control."); } break; - + case "setclass": + if (player.body !== null && (socket.permissions || Config.GAME_MODES[0] == 'sandbox')) { + player.body.define(m[0].replace("setclass", "")); + } + break; case "M": if (player.body == null) return 1; - let abort, message = m[0]; + let abort, message = m[0], original = m[0]; if ("string" !== typeof message) { socket.kick("Non-string chat message."); return 1; } - events.emit('chatMessage', { message, socket, preventDefault: () => abort = true }); + util.log(player.body.name + ': ' + original); + + if (Config.SANITIZE_CHAT_MESSAGE_COLORS) { + // I thought it should be "§§" but it only works if you do "§§§§"? + message = message.replace(/§/g, "§§§§"); + original = original.replace(/§/g, "§§§§"); + } + + Events.emit('chatMessage', { message: original, socket, preventDefault: () => abort = true, setMessage: str => message = str }); // we are not anti-choice here. if (abort) break; - util.log(player.body.name + ': ' + message); + if (message !== original) { + util.log('changed to: ' + message); + } let id = player.body.id; if (!chats[id]) { chats[id] = []; } - - if (c.SANITIZE_CHAT_MESSAGE_COLORS) { - // I thought it should be "§§" but it only works if you do "§§§§"? - message = message.replace(/§/g, "§§§§"); + + if (player.body != null && (socket.permissions || Config.GAME_MODES[0] == 'sandbox')) { + if (message.includes("/broadcast ")) { + if (message.replace("/broadcast ", "") != "") sockets.broadcast(player.body.name + ": " + message.replace("/broadcast ", "")); + } + if (message == "/crash") { + setTimeout(process.exit, 1000); + } + } + if (message == "/menu") { + socket.talk("menu"); } // TODO: this needs to be lag compensated, so the message would not last 1 second less due to high ping - chats[id].unshift({ message, expires: Date.now() + c.CHAT_MESSAGE_DURATION }); + chats[id].unshift({ message, expires: Date.now() + Config.CHAT_MESSAGE_DURATION }); // do one tick of the chat loop so they don't need to wait 100ms to receive it. chatLoop(); @@ -570,7 +782,7 @@ function traffic(socket) { // This function wiSl be called in the slow loop return () => { // Kick if it's d/c'd - if (util.time() - socket.status.lastHeartbeat > c.maxHeartbeatInterval) { + if (performance.now() - socket.status.lastHeartbeat > Config.maxHeartbeatInterval) { socket.kick("Heartbeat lost."); return 0; } @@ -725,19 +937,27 @@ function update(gui) { if (!b) return 0; gui.bodyid = b.id; // Update most things - gui.fps.update(Math.min(1, (global.fps / c.runSpeed / 1000) * 30)); + gui.fps.update(Math.min(1, (global.fps / Config.runSpeed / 1000) * 30)); gui.color.update(gui.master.teamColor); gui.label.update(b.index); gui.score.update(b.skill.score); gui.points.update(b.skill.points); // Update the upgrades let upgrades = []; + let skippedUpgrades = [0]; for (let i = 0; i < b.upgrades.length; i++) { let upgrade = b.upgrades[i]; if (b.skill.level >= b.upgrades[i].level) { upgrades.push(upgrade.branch.toString() + "\\\\//" + upgrade.branchLabel + "\\\\//" + upgrade.index); + } else { + if (upgrade.branch >= skippedUpgrades.length) { + skippedUpgrades[upgrade.branch] = 1; + } else { + skippedUpgrades[skippedUpgrades.length - 1]++; + } } } + b.skippedUpgrades = skippedUpgrades; gui.upgrades.update(upgrades); // Update the stats and skills gui.stats.update(); @@ -748,6 +968,7 @@ function update(gui) { // Update other gui.root.update(b.rerootUpgradeTree); gui.class.update(b.label); + gui.showhealthtext.update(Config.SHOW_HEALTHBAR_TEXT ? 1 : 0); } function publish(gui) { @@ -764,6 +985,7 @@ function publish(gui) { top: gui.topspeed.publish(), root: gui.root.publish(), class: gui.class.publish(), + showhealthtext: gui.showhealthtext.publish(), }; // Encode which we'll be updating and capture those values only let oo = [0]; @@ -813,6 +1035,10 @@ function publish(gui) { oo[0] += 0x0400; oo.push(o.class); } + if (o.showhealthtext != null) { + oo[0] += 0x0800; + oo.push(o.showhealthtext); + } // Output it return oo; } @@ -835,6 +1061,7 @@ let newgui = (player) => { bodyid: -1, root: floppy(), class: floppy(), + showhealthtext: floppy(), }; // This is the gui itself return { @@ -847,21 +1074,21 @@ let newgui = (player) => { const spawn = (socket, name) => { let player = {}, loc = {}; - if (!socket.group && c.GROUPS) { + if (!socket.group && Config.GROUPS) { groups.addMember(socket, socket.party || -1); } player.team = socket.rememberedTeam; - if (c.MODE == "tdm" || c.TAG) { + if (Config.MODE == "tdm" || Config.TAG) { let team = getWeakestTeam(); // Choose from one of the least ones if (player.team == null || (player.team !== team && global.defeatedTeams.includes(player.team)) ) { player.team = team; } - if (socket.party && !c.TAG) { + if (socket.party && !Config.TAG) { let team = socket.party / room.partyHash; - if (team > 0 && team < c.TEAMS + 1 && team & 1 == team && !global.defeatedTeams.includes(team)) { + if (team > 0 && team < Config.TEAMS + 1 && team & 1 == team && !global.defeatedTeams.includes(team)) { player.team = team; console.log("Party Code with team:", team, "Party:", socket.party); } @@ -887,40 +1114,48 @@ const spawn = (socket, name) => { } else { body = new Entity(loc); body.protect(); - body.isPlayer = true; + body.isPlayer = true; // Mark it as an player. if (player.team != null) { body.team = player.team; } else { player.team = body.team; } - body.define(c.SPAWN_CLASS); + if (global.playerskin !== "") { + body.define([Config.SPAWN_CLASS, global.playerskin]); + } else { + body.define(Config.SPAWN_CLASS); + } if (socket.permissions && socket.permissions.nameColor) { body.nameColor = socket.permissions.nameColor; socket.talk("z", body.nameColor); + } else { + body.nameColor = "#ffffff"; + socket.talk("z", body.nameColor); + } + body.become(player); // become it so it can speak and listen. + socket.spectateEntity = null; // Dont break the camera. + body.invuln = true; // Make it safe + + // Default confinement + for (let bounds in Config.SPAWN_CONFINEMENT) { + body.confinement[bounds] = Config.SPAWN_CONFINEMENT[bounds]; } - body.addController(new ioTypes.listenToPlayer(body, { player })); - socket.spectateEntity = null; - body.invuln = true; } - body.name = name; - body.sendMessage = (content, displayTime = c.MESSAGE_DISPLAY_TIME) => socket.talk("m", displayTime, content); + body.name = name; // Define the name. socket.rememberedTeam = player.team; player.body = body; body.socket = socket; if (body.color.base == '-1' || body.color.base == 'mirror') { - body.color.base = getTeamColor(c.GROUPS || (c.MODE == 'ffa' && !c.TAG) - ? c.RANDOM_COLORS ? ran.choose([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 ]) : TEAM_RED + body.color.base = getTeamColor(Config.GROUPS || (Config.MODE == 'ffa' && !Config.TAG) + ? Config.RANDOM_COLORS ? ran.choose([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 ]) : TEAM_RED : player.body.team); } // Decide what to do about colors when sending updates and stuff - player.teamColor = new Color(!c.RANDOM_COLORS && (c.GROUPS || (c.MODE == 'ffa' && !c.TAG)) ? 10 : getTeamColor(body.team)).compiled; // blue + player.teamColor = new Color(!Config.RANDOM_COLORS && (Config.GROUPS || (Config.MODE == 'ffa' && !Config.TAG)) ? 10 : getTeamColor(body.team)).compiled; // blue player.target = { x: 0, y: 0 }; player.command = { - up: false, - down: false, - left: false, - right: false, + movement: { x: 0, y: 0 }, lmb: false, mmb: false, rmb: false, @@ -931,16 +1166,17 @@ const spawn = (socket, name) => { spinlock: false }; // Set up the recording commands - let begin = util.time(); + let begin = performance.now(); player.records = () => [ player.body.skill.score, - Math.floor((util.time() - begin) / 1000), + Math.floor((performance.now() - begin) / 1000), + Config.RESPAWN_TIMEOUT, player.body.killCount.solo, player.body.killCount.assists, player.body.killCount.bosses, player.body.killCount.polygons, player.body.killCount.killers.length, - ...player.body.killCount.killers, + ...player.body.killCount.killers ]; player.gui = newgui(player); player.socket = socket; @@ -950,11 +1186,11 @@ const spawn = (socket, name) => { socket.camera.fov = 2000; socket.status.hasSpawned = true; - let msg = c.WELCOME_MESSAGE.split("\n"); + let msg = Config.WELCOME_MESSAGE.split("\n"); for (let i = 0; i < msg.length; i++) { body.sendMessage(msg[i]); } - socket.talk("c", socket.camera.x, socket.camera.y, socket.camera.fov); + socket.talk("c", socket.camera.x, socket.camera.y, socket.camera.fov); // Move the camera return player; }; @@ -988,7 +1224,7 @@ function flatten(data) { /* 6 */ data.vy, /* 7 */ data.size, /* 8 */ data.facing, - /* 9 */ Math.round(255 * data.perceptionAngleIndependence), //data.vfacing, + /* 9 */ Math.round(255 * data.perceptionAngleIndependence), /* 10 */ data.defaultAngle, /* 11 */ data.twiggle, /* 12 */ data.layer, @@ -997,13 +1233,15 @@ function flatten(data) { /* 15 */ data.drawFill, /* 16 */ data.invuln, /* 17 */ Math.ceil(65535 * data.health), - /* 18 */ Math.round(65535 * data.shield), - /* 19 */ Math.round(255 * data.alpha), + /* 18 */ data.healthN, + /* 19 */ data.maxHealthN, + /* 19 */ Math.round(65535 * data.shield), + /* 20 */ Math.round(255 * data.alpha), ); if (data.type & 0x04) { output.push( - /* 20 */ data.name, - /* 21 */ data.score + /* 21 */ data.name, + /* 22 */ data.score ); } } @@ -1032,7 +1270,7 @@ function perspective(e, player, data) { } if ( player.body.team === e.source.team && - (c.GROUPS || (c.MODE == 'ffa' && !c.TAG)) && + (Config.GROUPS || (Config.MODE == 'ffa' && !Config.TAG)) && player.body.color.base == 12 ) { // GROUPS @@ -1053,151 +1291,139 @@ function check(camera, obj) { return a && b; } -// Make a function that will make a function that will send out world updates -const eyes = (socket) => { - let lastVisibleUpdate = 0; - let nearby = []; - let x = -1000; - let y = -1000; - let fov = 0; - let o = { - socket, - getNearby: () => nearby, - add: (e) => { - if (check(socket.camera, e)) nearby.push(e); - }, - remove: (e) => { - let i = nearby.indexOf(e); - if (i !== -1) util.remove(nearby, i); - }, - check: (e, f) => { - return check(socket.camera, e); - }, //Math.abs(e.x - x) < e.size + f*fov && Math.abs(e.y - y) < e.size + f*fov; }, - gazeUpon: () => { - logs.network.set(); - let player = socket.player, - camera = socket.camera; - // If nothing has changed since the last update, wait (approximately) until then to update - let rightNow = room.lastCycle; - // ...elseeeeee... - // Update the record. - camera.lastUpdate = rightNow; - // Get the socket status - socket.status.receiving++; - // Now prepare the data to emit - let setFov = camera.fov; - // If we are alive, update the camera - if (player.body != null) { - // But I just died... - if (player.body.isDead()) { - socket.status.deceased = true; - // Let the client know it died - socket.talk("F", ...player.records()); - // Remove the body - player.body = null; - } - // I live! - else if (player.body.photo) { - // Update camera position and motion - camera.x = player.body.cameraOverrideX === null ? player.body.photo.x : player.body.cameraOverrideX; - camera.y = player.body.cameraOverrideY === null ? player.body.photo.y : player.body.cameraOverrideY; - camera.vx = player.body.photo.vx; - camera.vy = player.body.photo.vy; - camera.scoping = player.body.cameraOverrideX !== null; - // Get what we should be able to see - setFov = player.body.fov; - // Get our body id - player.viewId = player.body.id; - } +class View { + constructor (socket) { + this.lastVisibleUpdate = 0; + this.nearby = []; + this.socket = socket; + views.push(this); + } + add (e) { + if (check(this.socket.camera, e)) this.nearby.push(e); + } + remove (e) { + let i = this.nearby.indexOf(e); + if (i !== -1) util.remove(this.nearby, i); + } + check (e) { + return check(this.socket.camera, e); + } + gazeUpon () { + logs.network.startTracking(); + let player = this.socket.player, + camera = this.socket.camera; + // If nothing has changed since the last update, wait (approximately) until then to update + let rightNow = room.lastCycle; + // ...elseeeeee... + // Update the record. + camera.lastUpdate = rightNow; + // Get the socket status + this.socket.status.receiving++; + // Now prepare the data to emit + let setFov = camera.fov; + // If we are alive, update the camera + if (player.body != null) { + // But I just died... + if (player.body.isDead()) { + this.socket.status.deceased = true; + // Let the client know it died + this.socket.talk("F", ...player.records()); + // Remove the body + player.body = null; + } + // I live! + else if (player.body.photo) { + // Update camera position and motion + camera.x = player.body.cameraOverrideX === null ? player.body.photo.x : player.body.cameraOverrideX; + camera.y = player.body.cameraOverrideY === null ? player.body.photo.y : player.body.cameraOverrideY; + camera.vx = player.body.photo.vx; + camera.vy = player.body.photo.vy; + camera.scoping = player.body.cameraOverrideX !== null; + // Get what we should be able to see + setFov = player.body.fov; + // Get our body id + player.viewId = player.body.id; } - if (player.body == null) { - // u dead bro - setFov = 2000; - if (socket.spectateEntity != null) { - if (socket.spectateEntity) { - camera.x = socket.spectateEntity.x; - camera.y = socket.spectateEntity.y; - } + } + if (player.body == null) { + // u dead bro + setFov = 2000; + camera.scoping = false; + if (this.socket.spectateEntity != null) { + if (this.socket.spectateEntity) { + camera.x = this.socket.spectateEntity.x; + camera.y = this.socket.spectateEntity.y; } } - // Smoothly transition view size - camera.fov += Math.max( - (setFov - camera.fov) / 30, - setFov - camera.fov - ); - // Update my stuff - x = camera.x; - y = camera.y; - fov = camera.fov; - // Find what the user can see. - // Update which entities are nearby - if (camera.lastUpdate - lastVisibleUpdate > c.visibleListInterval) { - // Update our timer - lastVisibleUpdate = camera.lastUpdate; - // And update the nearby list - nearby = [] - for (let i = 0; i < entities.length; i++) { - if (check(socket.camera, entities[i])) { - nearby.push(entities[i]); - } + } + // Smoothly transition view size + camera.fov = setFov; + // Find what the user can see. + // Update which entities are nearby + if (camera.lastUpdate - this.lastVisibleUpdate > Config.visibleListInterval) { + // Update our timer + this.lastVisibleUpdate = camera.lastUpdate; + // And update the nearby list + this.nearby = [] + for (let i = 0; i < entities.length; i++) { + if (check(this.socket.camera, entities[i])) { + this.nearby.push(entities[i]); } } - // Look at our list of nearby entities and get their updates - let visible = []; - for (let i = 0; i < nearby.length; i++) { - let e = nearby[i]; - if (e.photo && - Math.abs(e.x - x) < fov / 2 + 1.5 * e.size && - Math.abs(e.y - y) < (fov / 2) * (9 / 16) + 1.5 * e.size - ) { - // Grab the photo - if (!e.flattenedPhoto) { - e.flattenedPhoto = flatten(e.photo); - } - visible.push(perspective(e, player, e.flattenedPhoto)); + } + // Look at our list of nearby entities and get their updates + let visible = []; + for (let i = 0; i < this.nearby.length; i++) { + let e = this.nearby[i]; + if (e.photo && + Math.abs(e.x - camera.x) < camera.fov / 2 + 1.5 * e.size && + Math.abs(e.y - camera.y) < (camera.fov / 2) * (9 / 16) + 1.5 * e.size + ) { + // Grab the photo + if (!e.flattenedPhoto) { + e.flattenedPhoto = flatten(e.photo); } + visible.push(perspective(e, player, e.flattenedPhoto)); } - // Spread it for upload - let view = []; - for (let instance of visible) { - view.push(...instance); - } + } + // Spread it for upload + let view = []; + for (let instance of visible) { + view.push(...instance); + } - // Update the gui - player.gui.update(); - // Send it to the player - socket.talk( - "u", - rightNow, - camera.x, - camera.y, - setFov, - camera.vx, - camera.vy, - camera.scoping, - ...player.gui.publish(), - visible.length, - ...view - ); - logs.network.mark(); - }, - }; - views.push(o); - return o; -}; + // Update the gui + player.gui.update(); + // Send it to the player + this.socket.talk( + "u", + rightNow, + camera.x, + camera.y, + setFov, + camera.vx, + camera.vy, + camera.scoping, + ...player.gui.publish(), + visible.length, + ...view + ); + logs.network.endTracking(); + } +} // Delta Calculator const Delta = class { constructor(dataLength, finder) { this.dataLength = dataLength; this.finder = finder; - this.old = []; - this.now = finder([]); + this.data = []; } - update(save, ...args) { - let old = this.now; + update(id = 0, ...args) { + if (!this.data[id]) this.data[id] = this.finder([]); + let old = this.data[id]; let now = this.finder(args); - this.now = now; + this.data[id] = now; let oldIndex = 0; let nowIndex = 0; let updates = []; @@ -1241,17 +1467,10 @@ const Delta = class { updates.push(now[i].id, ...now[i].data); updatesLength++; } - let reset = [0, now.length]; + let reset = [0, now.length], + update = [deletesLength, ...deletes, updatesLength, ...updates]; for (let element of now) reset.push(element.id, ...element.data); - let update = [deletesLength, ...deletes, updatesLength, ...updates]; - if (!updatesLength && !deletesLength && this.save) { - update = this.old; - this.save--; - } else if (save) { - this.old = update; - this.save = save; - } - return { reset, update }; + return { update, reset }; } }; @@ -1262,13 +1481,13 @@ let minimapAll = new Delta(5, args => { if (my.allowedOnMinimap && ( my.alwaysShowOnMinimap || (my.type === "wall" && my.alpha > 0.2) || - my.type === "miniboss" || + my.type === "miniboss" || my.type == "portal" || my.isMothership )) { all.push({ id: my.id, data: [ - my.type === "wall" || my.isMothership ? (my.shape === 4 || my.shapeData == "M 1 1 L -1 1 L -1 -1 L 1 -1 Z") ? 2 : 1 : 0, + my.type === "wall" || my.isMothership ? my.shape === 4 ? 2 : 1 : 0, util.clamp(Math.floor((256 * my.x) / room.width), 0, 255), util.clamp(Math.floor((256 * my.y) / room.height), 0, 255), my.color.compiled, @@ -1288,7 +1507,7 @@ let minimapTeams = new Delta(3, args => { data: [ util.clamp(Math.floor((256 * my.x) / room.width), 0, 255), util.clamp(Math.floor((256 * my.y) / room.height), 0, 255), - (c.GROUPS || (c.MODE == 'ffa' && !c.TAG)) ? '10 0 1 0 false' : my.color.compiled, + Config.GROUPS || (Config.MODE == 'ffa' && !Config.TAG) ? '10 0 1 0 false' : my.color.compiled, ], }); } @@ -1296,8 +1515,8 @@ let minimapTeams = new Delta(3, args => { }); let leaderboard = new Delta(7, args => { let list = []; - if (c.TAG) - for (let id = 0; id < c.TEAMS; id++) { + if (Config.TAG) + for (let id = 0; id < Config.TEAMS; id++) { let team = -id - 1; list.push({ id, @@ -1310,9 +1529,9 @@ let leaderboard = new Delta(7, args => { }); } for (let instance of entities) { - if (c.MOTHERSHIP_LOOP) { + if (Config.MOTHERSHIP_LOOP) { if (instance.isMothership) list.push(instance); - } else if (c.TAG) { + } else if (Config.TAG) { let entry = list.find((r) => r.team === instance.team); if (entry && (instance.isPlayer || instance.isBot)) entry.skill.score++; @@ -1340,13 +1559,13 @@ let leaderboard = new Delta(7, args => { } if (is === 0) break; let entry = list[top]; - let color = args.length && args[0] == entry.team + let color = args.length && args[0] == entry.id ? '10 0 1 0 false' : entry.color.compiled; topTen.push({ id: entry.id, data: [ - c.MOTHERSHIP_LOOP ? Math.round(entry.health.amount) : Math.round(entry.skill.score), + Config.MOTHERSHIP_LOOP ? Math.round(entry.health.amount) : Math.round(entry.skill.score), entry.index, entry.name, color, @@ -1364,33 +1583,35 @@ let leaderboard = new Delta(7, args => { // Periodically give out updates let subscribers = []; setInterval(() => { - logs.minimap.set(); - let minimapUpdate = minimapAll.update(); + logs.minimap.startTracking(); + let minimapUpdate = minimapAll.update(), + leaderboardUpdate, + teamUpdate; for (let socket of subscribers) { if (!socket.status.hasSpawned) continue; - let team = minimapTeams.update( - subscribers.length - 1, - socket.player.team + leaderboardUpdate = leaderboard.update( + socket.id, + (Config.GROUPS || (Config.MODE == 'ffa' && !Config.TAG)) && socket.player.body ? socket.player.body.id : null ); - let leaderboardUpdate = leaderboard.update( - subscribers.length - 1, - c.GROUPS || (c.MODE == 'ffa' && !c.TAG) ? socket.player.team : 0 + teamUpdate = minimapTeams.update( + socket.id, + socket.player.team ); socket.talk( "b", - ...(socket.status.needsNewBroadcast ? minimapUpdate.reset : minimapUpdate.update), - ...(team ? socket.status.needsNewBroadcast ? team.reset : team.update : [0, 0]), - ...(socket.anon ? [0, 0] : socket.status.needsNewBroadcast ? leaderboardUpdate.reset : leaderboardUpdate.update) + ...socket.status.needsNewBroadcast ? minimapUpdate.reset : minimapUpdate.update, + ...teamUpdate ? socket.status.needsNewBroadcast ? teamUpdate.reset : teamUpdate.update : [0, 0], + ...socket.status.needsNewBroadcast ? leaderboardUpdate.reset : leaderboardUpdate.update ); if (socket.status.needsNewBroadcast) { socket.status.needsNewBroadcast = false; } } - logs.minimap.mark(); - let time = util.time(); + logs.minimap.endTracking(); + let time = performance.now(); for (let socket of clients) { if (socket.timeout.check(time)) socket.lastWords("K"); - if (time - socket.statuslastHeartbeat > c.maxHeartbeatInterval) socket.kick("Lost heartbeat."); + if (time - socket.statuslastHeartbeat > Config.maxHeartbeatInterval) socket.kick("Lost heartbeat."); } }, 250); @@ -1407,13 +1628,15 @@ const broadcast = { }; let lastTime = 0; +// Get a unique id for each socket +let socketId = 0; const sockets = { players: players, clients: clients, disconnections: disconnections, broadcast: (message) => { for (let i = 0; i < clients.length; i++) { - clients[i].talk("m", c.MESSAGE_DISPLAY_TIME, message); + clients[i].talk("m", Config.MESSAGE_DISPLAY_TIME, message); } }, broadcastRoom: () => { @@ -1430,6 +1653,7 @@ const sockets = { util.log("A client is trying to connect..."); // Set it up + socket.id = socketId++; socket.binaryType = "arraybuffer"; socket.key = ""; socket.player = { camera: {} }; @@ -1438,11 +1662,11 @@ const sockets = { let mem = 0; let timer = 0; socket.timeout = { - check: (time) => timer && time - timer > c.maxHeartbeatInterval, + check: (time) => timer && time - timer > Config.maxHeartbeatInterval, set: (val) => { if (mem !== val) { mem = val; - timer = util.time(); + timer = performance.now(); } }, }; @@ -1473,7 +1697,7 @@ const sockets = { hasSpawned: false, needsFullMap: true, needsNewBroadcast: true, - lastHeartbeat: util.time(), + lastHeartbeat: performance.now(), }; // Set up loops let nextUpdateCall = null; // has to be started manually @@ -1494,17 +1718,17 @@ const sockets = { }; // Set up the camera socket.camera = { - x: undefined, - y: undefined, + x: 0, + y: 0, vx: 0, vy: 0, - lastUpdate: util.time(), + lastUpdate: performance.now(), lastDowndate: undefined, fov: 2000, }; // Set up the viewer socket.makeView = () => { - socket.view = eyes(socket); + socket.view = new View(socket); }; socket.makeView(); // Put the fundamental functions in the socket @@ -1559,4 +1783,4 @@ const sockets = { util.log("[INFO] New socket opened with ip " + socket.ip); } }; -module.exports = { sockets, chatLoop }; +module.exports = { sockets, chatLoop }; \ No newline at end of file diff --git a/server/modules/network/webServer.js b/server/modules/network/webServer.js index 9c30c0980..3c108f105 100644 --- a/server/modules/network/webServer.js +++ b/server/modules/network/webServer.js @@ -1,7 +1,9 @@ let fs = require('fs'), path = require('path'), + ips = require("./discoverability.js"), publicRoot = path.join(__dirname, "../../../public"), sharedRoot = path.join(__dirname, "../../../shared"), + normalRoot = path.join(__dirname, "../../.."), mimeSet = { "js": "application/javascript", "json": "application/json", @@ -11,14 +13,22 @@ let fs = require('fs'), "png": "image/png", "ico": "image/x-icon" }, -wsServer = new (require('ws').WebSocketServer)({ noServer: true }); + wsServer; -if (c.host === 'localhost') { - util.warn(`config.host is just "localhost", are you sure you don't mean "localhost:${c.port}"?`); +try { + wsServer = new (require('../../lib/ws/index.js').WebSocketServer)({ noServer: true }); +} catch (err) { + wsServer = new (require('ws').WebSocketServer)({ noServer: true }); } -if (c.host.match(/localhost:(\d)/) && c.host !== 'localhost:' + c.port) { - util.warn('config.host is a localhost domain but its port is different to config.port!'); + +console.log("Web Server initialized."); +if (Config.host === 'localhost') { + util.warn(`[WEB SERVER] config.host is just "localhost", are you sure you don't mean "localhost:${Config.port}"?`); +} +if (Config.host.match(/localhost:(\d)/) && Config.host !== 'localhost:' + Config.port) { + util.warn('[WEB SERVER] config.host is a localhost domain but its port is different to config.port!'); } +ips.push([ Config.host, Config.location, Config.https ]); server = require('http').createServer((req, res) => { let resStr = ""; @@ -27,9 +37,9 @@ server = require('http').createServer((req, res) => { //if this file does not exist, return the default; if (!fs.existsSync(fileToGet)) { - fileToGet = path.join(sharedRoot, c.DEFAULT_FILE); + fileToGet = path.join(publicRoot, Config.DEFAULT_FILE); } else if (!fs.lstatSync(fileToGet).isFile()) { - fileToGet = path.join(sharedRoot, c.DEFAULT_FILE); + fileToGet = path.join(publicRoot, Config.DEFAULT_FILE); } //return the file @@ -39,29 +49,55 @@ server = require('http').createServer((req, res) => { case "/lib/json/mockups.json": resStr = mockupJsonData; break; - case "/lib/json/gamemodeData.json": - resStr = JSON.stringify({ gameMode: c.gameModeName, players: views.length }); - break; case "/serverData.json": - resStr = JSON.stringify({ ip: c.host }); + resStr = JSON.stringify({ gameMode: Config.gameModeName, players: views.length }); + break; + case "/browserData.json": + resStr = JSON.stringify(ips); break; default: let fileToGet = path.join(publicRoot, req.url); //if this file does not exist, return the default; if (!fs.existsSync(fileToGet)) { - fileToGet = path.join(publicRoot, c.DEFAULT_FILE); + if (req.url.includes("/file/")) { + fileToGet = path.join(normalRoot, req.url.replace("/file", "")); + } else { + fileToGet = path.join(publicRoot, Config.DEFAULT_FILE); + } } else if (!fs.lstatSync(fileToGet).isFile()) { - fileToGet = path.join(publicRoot, c.DEFAULT_FILE); + fileToGet = path.join(publicRoot, Config.DEFAULT_FILE); } //return the file res.writeHead(200, { 'Content-Type': mimeSet[ fileToGet.split('.').pop() ] || 'text/html' }); return fs.createReadStream(fileToGet).pipe(res); } - res.writeHead(200); - res.end(resStr); + // CORS? + res.setHeader('Access-Control-Allow-Origin', '*'); + + const zlib = require("zlib"); + res.setHeader("Access-Control-Allow-Origin", "*"); + let acceptEncoding = req.headers['accept-encoding']; + if (!acceptEncoding) { + acceptEncoding = ''; + }; + if (acceptEncoding.match(/\bdeflate\b/)) { + res.writeHead(200, { 'content-encoding': 'deflate' }); + zlib.createDeflate().end(resStr).pipe(res); + } else if (acceptEncoding.match(/\bgzip\b/)) { + res.writeHead(200, { 'content-encoding': 'gzip' }); + zlib.createGzip().end(resStr).pipe(res); + } else { + res.writeHead(200, {}); + res.end(resStr); + } + + //res.writeHead(200); + //res.end(resStr); }); + server.on('upgrade', (req, socket, head) => wsServer.handleUpgrade(req, socket, head, ws => sockets.connect(ws, req))); -server.listen(c.port, () => console.log("Server listening on port", c.port)); +server.listen(Config.port, () => console.log("[WEB SERVER] Server listening on port", Config.port)); + module.exports = { server }; \ No newline at end of file diff --git a/server/modules/physics/collisionFunctions.js b/server/modules/physics/collisionFunctions.js index a8bbf536b..f27745a06 100644 --- a/server/modules/physics/collisionFunctions.js +++ b/server/modules/physics/collisionFunctions.js @@ -1,5 +1,5 @@ function simplecollide(my, n) { - let difference = (1 + util.getDistance(my, n) / 2) * c.runSpeed; + let difference = (1 + util.getDistance(my, n) / 2) * Config.runSpeed; let pushability1 = (my.intangibility) ? 1 : my.pushability, pushability2 = (n.intangibility) ? 1 : n.pushability, differenceX = 0.05 * (my.x - n.x) / difference, @@ -24,7 +24,7 @@ function firmcollide(my, n, buffer = 0) { let s2 = Math.max(n.velocity.length, n.topSpeed); let strike1, strike2; if (buffer > 0 && dist <= my.realSize + n.realSize + buffer) { - let repel = (my.acceleration + n.acceleration) * (my.realSize + n.realSize + buffer - dist) / buffer / c.runSpeed; + let repel = (my.acceleration + n.acceleration) * (my.realSize + n.realSize + buffer - dist) / buffer / Config.runSpeed; my.accel.x += repel * (item1.x - item2.x) / dist; my.accel.y += repel * (item1.y - item2.y) / dist; n.accel.x -= repel * (item1.x - item2.x) / dist; @@ -34,14 +34,14 @@ function firmcollide(my, n, buffer = 0) { strike1 = false; strike2 = false; if (my.velocity.length <= s1) { - my.velocity.x -= 0.05 * (item2.x - item1.x) / dist / c.runSpeed; - my.velocity.y -= 0.05 * (item2.y - item1.y) / dist / c.runSpeed; + my.velocity.x -= 0.05 * (item2.x - item1.x) / dist / Config.runSpeed; + my.velocity.y -= 0.05 * (item2.y - item1.y) / dist / Config.runSpeed; } else { strike1 = true; } if (n.velocity.length <= s2) { - n.velocity.x += 0.05 * (item2.x - item1.x) / dist / c.runSpeed; - n.velocity.y += 0.05 * (item2.y - item1.y) / dist / c.runSpeed; + n.velocity.x += 0.05 * (item2.x - item1.x) / dist / Config.runSpeed; + n.velocity.y += 0.05 * (item2.y - item1.y) / dist / Config.runSpeed; } else { strike2 = true; } @@ -58,17 +58,33 @@ function firmcollide(my, n, buffer = 0) { } function reflectcollide(wall, bounce) { - let delta = new Vector(wall.x - bounce.x, wall.y - bounce.y); - let dist = delta.length; - let difference = wall.size + bounce.size - dist; - if (difference > 0) { - bounce.accel.x -= difference * delta.x / dist; - bounce.accel.y -= difference * delta.y / dist; + if (wall.master.team != bounce.team) { + let delta = new Vector(wall.x - bounce.x, wall.y - bounce.y); + let dist = delta.length; + let difference = wall.size + bounce.size - dist; + if (difference > 0) { + bounce.accel.x -= difference * delta.x / dist; + bounce.accel.y -= difference * delta.y / dist; + } return 1; } return 0; } +function mirrorcollide(shield, bounce) { + let delta = new Vector(shield.x - bounce.x, shield.y - bounce.y); + let dist = delta.length; + let difference = shield.size + bounce.size - dist; + if (difference > 0) { + bounce.accel.x -= difference * delta.x / dist; + bounce.accel.y -= difference * delta.y / dist; + if (bounce.type == 'bullet') { + bounce.team = shield.master.team; + } + } + return 1; +} + function advancedcollide(my, n, doDamage, doInelastic, nIsFirmCollide = false) { let tock = Math.min(my.stepRemaining, n.stepRemaining), combinedRadius = n.size + my.size, @@ -190,8 +206,8 @@ function advancedcollide(my, n, doDamage, doInelastic, nIsFirmCollide = false) { // Calculate base damage let resistDiff = my.health.resist - n.health.resist, damage = { - _me: c.DAMAGE_CONSTANT * my.damage * (1 + resistDiff) * (1 + n.heteroMultiplier * (my.settings.damageClass === n.settings.damageClass)) * ((my.settings.buffVsFood && n.settings.damageType === 1) ? 3 : 1) * my.damageMultiplier() * Math.min(2, Math.max(speedFactor._me, 1) * speedFactor._me), - _n: c.DAMAGE_CONSTANT * n.damage * (1 - resistDiff) * (1 + my.heteroMultiplier * (my.settings.damageClass === n.settings.damageClass)) * ((n.settings.buffVsFood && my.settings.damageType === 1) ? 3 : 1) * n.damageMultiplier() * Math.min(2, Math.max(speedFactor._n , 1) * speedFactor._n ), + _me: Config.DAMAGE_CONSTANT * my.damage * (1 + resistDiff) * (1 + n.heteroMultiplier * (my.settings.damageClass === n.settings.damageClass)) * ((my.settings.buffVsFood && n.settings.damageType === 1) ? 3 : 1) * my.damageMultiplier() * Math.min(2, Math.max(speedFactor._me, 1) * speedFactor._me), + _n: Config.DAMAGE_CONSTANT * n.damage * (1 - resistDiff) * (1 + my.heteroMultiplier * (my.settings.damageClass === n.settings.damageClass)) * ((n.settings.buffVsFood && my.settings.damageType === 1) ? 3 : 1) * n.damageMultiplier() * Math.min(2, Math.max(speedFactor._n , 1) * speedFactor._n ), }; // Advanced damage calculations if (my.settings.ratioEffects) { @@ -262,21 +278,21 @@ function advancedcollide(my, n, doDamage, doInelastic, nIsFirmCollide = false) { } else { elasticity *= 2; } - let spring = 2 * Math.sqrt(savedHealthRatio._me * savedHealthRatio._n) / c.runSpeed, + let spring = 2 * Math.sqrt(savedHealthRatio._me * savedHealthRatio._n) / Config.runSpeed, elasticImpulse = Math.pow(combinedDepth.down, 2) * elasticity * component * my.mass * n.mass / (my.mass + n.mass), springImpulse = - c.KNOCKBACK_CONSTANT * spring * combinedDepth.up, + Config.KNOCKBACK_CONSTANT * spring * combinedDepth.up, impulse = -(elasticImpulse + springImpulse) * (1 - my.intangibility) * (1 - n.intangibility), force = { x: impulse * direction.x, y: impulse * direction.y, }, modifiers = { - _me: c.KNOCKBACK_CONSTANT * my.pushability / my.mass * deathFactor._n, - _n: c.KNOCKBACK_CONSTANT * n.pushability / n.mass * deathFactor._me, + _me: Config.KNOCKBACK_CONSTANT * my.pushability / my.mass * deathFactor._n, + _n: Config.KNOCKBACK_CONSTANT * n.pushability / n.mass * deathFactor._me, }; // Apply impulse as force my.accel.x += modifiers._me * force.x; @@ -292,99 +308,108 @@ function mooncollide(moon, n) { let dy = moon.y - n.y; let d2 = dx * dx + dy * dy; let totalRadius = moon.realSize + n.realSize; - if (d2 > totalRadius * totalRadius) + if (d2 > totalRadius ** 2) { return; + } + let dist = Math.sqrt(d2); let sink = totalRadius - dist; dx /= dist; dy /= dist; - n.accel.x -= dx * n.pushability * 0.05 * sink * 2; - n.accel.y -= dy * n.pushability * 0.05 * sink * 2; + n.x -= dx * n.pushability * sink; + n.y -= dy * n.pushability * sink; +} + +function mazewallcollidekill(bounce, wall) { + if (bounce.type !== 'tank' && bounce.type !== 'miniboss' && bounce.type !== 'food' && bounce.type !== 'crasher' && bounce.type !== "flail" && bounce.type !== "brella") { + bounce.kill(); + } else { + bounce.collisionArray.push(wall); + } } function mazewallcollide(wall, bounce) { - if (bounce.god === true || bounce.passive === true || bounce.ac || bounce.master.ac) return; + if (bounce.god === true || bounce.passive === true || bounce.isArenaCloser || bounce.master.isArenaCloser) return; if (bounce.store.noWallCollision) return; if (bounce.team === wall.team && bounce.type === "tank") return; - let trueWallSize = wall.size + 2; + let trueWallSize = wall.size * lazyRealSizes[4] / Math.SQRT2 + 2; if (bounce.x + bounce.size < wall.x - trueWallSize || bounce.x - bounce.size > wall.x + trueWallSize || bounce.y + bounce.size < wall.y - trueWallSize || bounce.y - bounce.size > wall.y + trueWallSize) return 0; - if (wall.intangibility) return 0 - let bounceBy = bounce.type === 'tank' ? 1.0 : bounce.type === 'miniboss' ? 2.5 : 0.1 - let left = bounce.x < wall.x - trueWallSize - let right = bounce.x > wall.x + trueWallSize - let top = bounce.y < wall.y - trueWallSize - let bottom = bounce.y > wall.y + trueWallSize - let leftExposed = bounce.x - bounce.size < wall.x - trueWallSize - let rightExposed = bounce.x + bounce.size > wall.x + trueWallSize - let topExposed = bounce.y - bounce.size < wall.y - trueWallSize - let bottomExposed = bounce.y + bounce.size > wall.y + trueWallSize + if (wall.intangibility) return 0; + + // Get collision face + // [left, top, right, bottom] + let collisionFaces = [ + bounce.x < wall.x, + bounce.y < wall.y, + bounce.x >= wall.x, // Biased just in case something ends up directly at the center of the wall + bounce.y > wall.y, + ]; + + // For corner checking + // [left, top, right, bottom] + let extendedOverFaces = [ + bounce.x < wall.x - trueWallSize, + bounce.y < wall.y - trueWallSize, + bounce.x > wall.x + trueWallSize, + bounce.y > wall.y + trueWallSize, + ]; - let intersected = true + // Push to position if colliding with a given face + let wallPushPositions = [ + {x: wall.x - trueWallSize - bounce.size}, + {y: wall.y - trueWallSize - bounce.size}, + {x: wall.x + trueWallSize + bounce.size}, + {y: wall.y + trueWallSize + bounce.size}, + ] - if (left && right) { - left = right = false - } - if (top && bottom) { - top = bottom = false - } - if (leftExposed && rightExposed) { - leftExposed = rightExposed = false - } - if (topExposed && bottomExposed) { - topExposed = bottomExposed = false - } - if ((left && !top && !bottom) || (leftExposed && !topExposed && !bottomExposed)) { - bounce.accel.x -= (bounce.x + bounce.size - wall.x + trueWallSize) * bounceBy - } else if ((right && !top && !bottom) || (rightExposed && !topExposed && !bottomExposed)) { - bounce.accel.x -= (bounce.x - bounce.size - wall.x - trueWallSize) * bounceBy - } else if ((top && !left && !right) || (topExposed && !leftExposed && !rightExposed)) { - bounce.accel.y -= (bounce.y + bounce.size - wall.y + trueWallSize) * bounceBy - } else if ((bottom && !left && !right) || (bottomExposed && !leftExposed && !rightExposed)) { - bounce.accel.y -= (bounce.y - bounce.size - wall.y - trueWallSize) * bounceBy - } else { - let x = leftExposed ? -trueWallSize : rightExposed ? trueWallSize : 0 - let y = topExposed ? -trueWallSize : bottomExposed ? trueWallSize : 0 + // Face collisions + for (let i = 0; i < 4; i++) { + // if not hitting a face or extending over neighboring faces, continue to the next face + if (!collisionFaces[i] | extendedOverFaces[(i + 3) % 4] | extendedOverFaces[(i + 1) % 4]) continue; - let point = new Vector(wall.x + x - bounce.x, wall.y + y - bounce.y) + // Decide to kill bounce type + mazewallcollidekill(bounce, wall); - if (!x || !y) { - if (bounce.x + bounce.y < wall.x + wall.y) { // top left - if (bounce.x - bounce.y < wall.x - wall.y) { // bottom left - bounce.accel.x -= (bounce.x + bounce.size - wall.x + trueWallSize) * bounceBy - } else { // top right - bounce.accel.y -= (bounce.y + bounce.size - wall.y + trueWallSize) * bounceBy - } - } else { // bottom right - if (bounce.x - bounce.y < wall.x - wall.y) { // bottom left - bounce.accel.y -= (bounce.y - bounce.size - wall.y - trueWallSize) * bounceBy - } else { // top right - bounce.accel.x -= (bounce.x - bounce.size - wall.x - trueWallSize) * bounceBy - } - } - } else if (!(left || right || top || bottom)) { - let force = (bounce.size / point.length - 1) * bounceBy / 2 - bounce.accel.x += point.x * force - bounce.accel.y += point.y * force - } else if (point.isShorterThan(bounce.size)) { - //let force = (bounce.size - point.length) / point.length * bounceBy - // once to get collision amount, once to norm - let force = (bounce.size / point.length - 1) * bounceBy / 2 // simplified - bounce.accel.x -= point.x * force - bounce.accel.y -= point.y * force - } else { - intersected = false + // Push and fix velocity to zero + for (let axis in wallPushPositions[i]) { + bounce[axis] = wallPushPositions[i][axis]; + bounce.velocity[axis] = 0; + return true; } } - if (intersected) { - if (bounce.type !== 'tank' && bounce.type !== 'miniboss' && bounce.type !== 'food') { - bounce.kill(); - } else { - bounce.collisionArray.push(wall); - } + // Corner collision points + // [left & top, top & right, right & bottom, bottom & left] + let cornerPositions = [ + {x: wall.x - trueWallSize, y: wall.y - trueWallSize}, + {x: wall.x + trueWallSize, y: wall.y - trueWallSize}, + {x: wall.x + trueWallSize, y: wall.y + trueWallSize}, + {x: wall.x - trueWallSize, y: wall.y + trueWallSize}, + ] + + // Corner collisions + for (let i = 0; i < 4; i++) { + // Check for current face and next face simultanously, as well as if we're sticking over that face + if ( + !collisionFaces[i] | !collisionFaces[(i + 1) % 4] | + !extendedOverFaces[i] | !extendedOverFaces[(i + 1) % 4] + ) continue; + + let cornerX = cornerPositions[i].x; + let cornerY = cornerPositions[i].y; + // Exit if too far away from the corner + if (util.getDistance(bounce, {x: cornerX, y: cornerY}) > bounce.size) return; + + // Decide to kill bounce type + mazewallcollidekill(bounce, wall); + + let angleFromCornerToBounce = Math.atan2(bounce.y - cornerY, bounce.x - cornerX); + bounce.x = cornerX + bounce.size * Math.cos(angleFromCornerToBounce); + bounce.y = cornerY + bounce.size * Math.sin(angleFromCornerToBounce); + return true; } }; @@ -395,4 +420,4 @@ module.exports = { advancedcollide, mooncollide, mazewallcollide -}; +}; \ No newline at end of file diff --git a/server/modules/setup/config.js b/server/modules/setup/config.js index e8094db7b..d3ab7c942 100644 --- a/server/modules/setup/config.js +++ b/server/modules/setup/config.js @@ -20,7 +20,8 @@ const nameMap = { tag: "TAG", opentdm: `Open ${output.TEAMS}TDM`, //clanwars: "Clan Wars", - trainwars: "Train Wars" + trainwars: "Train Wars", + old_dreadnoughts: `Old Dreadnoughts ${output.TEAMS}TDM`, }; -module.exports.gameModeName = output.GAMEMODE_NAME_PREFIXES.join(' ') + ' ' + output.GAME_MODES.map(x => nameMap[x] || (x[0].toUpperCase() + x.slice(1))).join(' '); \ No newline at end of file +module.exports.gameModeName = output.GAMEMODE_NAME_PREFIXES.join('') + '' + output.GAME_MODES.map(x => nameMap[x] || (x[0].toUpperCase() + x.slice(1))).join(' '); \ No newline at end of file diff --git a/server/modules/setup/gamemodeconfigs/assault.js b/server/modules/setup/gamemodeconfigs/assault.js new file mode 100644 index 000000000..d43dc78fe --- /dev/null +++ b/server/modules/setup/gamemodeconfigs/assault.js @@ -0,0 +1,5 @@ +module.exports = { + TEAM_WEIGHTS: { + [TEAM_BLUE]: 1.1 + } +}; \ No newline at end of file diff --git a/server/modules/setup/gamemodeconfigs/old_dreadnoughts.js b/server/modules/setup/gamemodeconfigs/old_dreadnoughts.js new file mode 100644 index 000000000..c9fcf975c --- /dev/null +++ b/server/modules/setup/gamemodeconfigs/old_dreadnoughts.js @@ -0,0 +1,11 @@ +module.exports = { + MODE: "tdm", + TEAMS: 4, + ROOM_SETUP: ['map_old_dreadnoughts'], + MAZE: 31, + TILE_WIDTH: 600, + TILE_HEIGHT: 600, + PORTAL_SPAWNS: true, + MAX_UPGRADE_TIER: 13, + SPAWN_CONFINEMENT: {xMin: 18000} +}; \ No newline at end of file diff --git a/server/modules/setup/gamemodeconfigs/risk.js b/server/modules/setup/gamemodeconfigs/risk.js new file mode 100644 index 000000000..36b2980ec --- /dev/null +++ b/server/modules/setup/gamemodeconfigs/risk.js @@ -0,0 +1,9 @@ +module.exports = { + MODE: "tdm", + TEAMS: 4, + ROOM_SETUP: ['map_risk_default'], + GOVERNMENTAL: true, + DOMINATOR_LOOP: true, + TILE_HEIGHT: 400, + TILE_WIDTH: 400, +}; \ No newline at end of file diff --git a/server/modules/setup/gamemodeconfigs/sandbox.js b/server/modules/setup/gamemodeconfigs/sandbox.js new file mode 100644 index 000000000..a09954537 --- /dev/null +++ b/server/modules/setup/gamemodeconfigs/sandbox.js @@ -0,0 +1 @@ +module.exports = {}; \ No newline at end of file diff --git a/server/modules/setup/gamemodeconfigs/siege.js b/server/modules/setup/gamemodeconfigs/siege.js index 67b08ed7c..ce7ab2931 100644 --- a/server/modules/setup/gamemodeconfigs/siege.js +++ b/server/modules/setup/gamemodeconfigs/siege.js @@ -4,7 +4,7 @@ module.exports = { SPECIAL_BOSS_SPAWNS: true, BOSS_SPAWN_COOLDOWN: Number.MAX_SAFE_INTEGER, WAVES: 100, // CLASSIC_SIEGE: false to use this setting - CLASSIC_SIEGE: false, + CLASSIC_SIEGE: true, TILE_WIDTH: 300, TILE_HEIGHT: 300, ROOM_SETUP: ['map_siege_legacy'], diff --git a/server/modules/setup/gamemodeconfigs/tdm.js b/server/modules/setup/gamemodeconfigs/tdm.js index f7d801703..d01e066c3 100644 --- a/server/modules/setup/gamemodeconfigs/tdm.js +++ b/server/modules/setup/gamemodeconfigs/tdm.js @@ -1,5 +1,5 @@ module.exports = { MODE: "tdm", - TEAMS: 4, + TEAMS: 2, ROOM_SETUP: ['overlay_tdm'] }; \ No newline at end of file diff --git a/server/modules/setup/mockups.js b/server/modules/setup/mockups.js index 648ca3507..df32a2002 100644 --- a/server/modules/setup/mockups.js +++ b/server/modules/setup/mockups.js @@ -1,9 +1,3 @@ -const { serverStartTime } = require("../../lib/util"); - -function rounder(val) { - if (Math.abs(val) < 0.00001) val = 0; - return +val.toPrecision(6); -} // Define mocking up functions function getMockup(e, positionInfo) { let turretsAndProps = e.turrets.concat(e.props); @@ -12,8 +6,8 @@ function getMockup(e, positionInfo) { name: e.label, upgradeName: e.upgradeLabel, upgradeTooltip: e.upgradeTooltip, - x: rounder(e.x), - y: rounder(e.y), + x: util.rounder(e.x), + y: util.rounder(e.y), color: e.color.compiled, strokeWidth: e.strokeWidth, upgradeColor: e.upgradeColor, @@ -22,9 +16,9 @@ function getMockup(e, positionInfo) { drawFill: e.drawFill, shape: e.shapeData, imageInterpolation: e.imageInterpolation, - size: rounder(e.size), - realSize: rounder(e.realSize), - facing: rounder(e.facing), + size: util.rounder(e.size), + realSize: util.rounder(e.realSize), + facing: util.rounder(e.facing), mirrorMasterAngle: e.settings.mirrorMasterAngle, layer: e.layer, statnames: e.settings.skillNames, @@ -35,14 +29,15 @@ function getMockup(e, positionInfo) { tier: r.tier, index: r.index })), + trueupgrades: [e.UPGRADES_TIER_2, e.UPGRADES_TIER_3, e.UPGRADES_TIER_4, e.UPGRADES_TIER_0 + e.UPGRADES_TIER_1], guns: e.guns.map(function(gun) { return { - offset: rounder(gun.offset), - direction: rounder(gun.direction), - length: rounder(gun.length), - width: rounder(gun.width), - aspect: rounder(gun.aspect), - angle: rounder(gun.angle), + offset: util.rounder(gun.offset), + direction: util.rounder(gun.offsetDirection), + length: util.rounder(gun.length), + width: util.rounder(gun.width), + aspect: util.rounder(gun.aspect), + angle: util.rounder(gun.angle), color: gun.color.compiled, strokeWidth: gun.strokeWidth, alpha: gun.alpha, @@ -53,11 +48,11 @@ function getMockup(e, positionInfo) { }), turrets: turretsAndProps.map(function(t) { let out = getMockup(t, {}); - out.sizeFactor = rounder(t.bound.size); - out.offset = rounder(t.bound.offset); - out.direction = rounder(t.bound.direction); - out.layer = rounder(t.bound.layer); - out.angle = rounder(t.bound.angle); + out.sizeFactor = util.rounder(t.bound.size); + out.offset = util.rounder(t.bound.offset); + out.direction = util.rounder(t.bound.direction); + out.layer = util.rounder(t.bound.layer); + out.angle = util.rounder(t.bound.angle); return out; }), }; @@ -78,7 +73,7 @@ function getFurthestFrom(x, y) { } } endPoints.splice(furthestIndex, 1); - return [rounder(furthestPoint[0]), rounder(furthestPoint[1])]; + return [util.rounder(furthestPoint[0]), util.rounder(furthestPoint[1])]; } function checkIfSamePoint(p1, p2) { @@ -112,7 +107,7 @@ function getDimensions(entity) { point2 = getFurthestFrom(...point1); // Repeat selecting the second point until at least one of the first two points is off the centerline - while (point1[0] == 0 && point2[0] == 0 || point1[1] == 0 && point2[1] == 0) { + while ((point1[0] == 0 && point2[0] == 0 || point1[1] == 0 && point2[1] == 0) && entity.shape != 4) { point2 = getFurthestFrom(...point1); } @@ -135,13 +130,13 @@ function getDimensions(entity) { // Find circumcircle and circumcenter function constructCircumcirle(point1, point2, point3) { - // Rounder to avoid floating point nonsense - let x1 = rounder(point1[0]); - let y1 = rounder(point1[1]); - let x2 = rounder(point2[0]); - let y2 = rounder(point2[1]); - let x3 = rounder(point3[0]); - let y3 = rounder(point3[1]); + // util.rounder to avoid floating point nonsense + let x1 = util.rounder(point1[0]); + let y1 = util.rounder(point1[1]); + let x2 = util.rounder(point2[0]); + let y2 = util.rounder(point2[1]); + let x3 = util.rounder(point3[0]); + let y3 = util.rounder(point3[1]); // Invalid math protection if (x3 == x1 || x3 == x2) { @@ -196,15 +191,16 @@ function sizeEntity(entity, x = 0, y = 0, angle = 0, scale = 1) { let newX = point[0] * cosT - point[1] * sinT, newY = point[0] * sinT + point[1] * cosT; // Translate it to the right position - newX += g.offset * Math.cos(g.direction + g.angle + angle); - newY += g.offset * Math.sin(g.direction + g.angle + angle); + newX += g.offset * Math.cos(g.offsetDirection + g.angle + angle); + newY += g.offset * Math.sin(g.offsetDirection + g.angle + angle); // Save coords endPoints.push([x + newX * scale, y + newY * scale]); } } - // Process turrets - for (let t of entity.turrets) { + // Process turrets and props + let turretsAndProps = entity.turrets.concat(entity.props); + for (let t of turretsAndProps) { let trueAngle = angle + t.bound.angle, xShift = t.bound.offset * Math.cos(t.bound.direction + trueAngle), yShift = t.bound.offset * Math.sin(t.bound.direction + trueAngle); @@ -213,7 +209,7 @@ function sizeEntity(entity, x = 0, y = 0, angle = 0, scale = 1) { } console.log("Started loading mockups..."); -let mockupsLoadStartTime = Date.now(); +let mockupsLoadStartTime = performance.now(); let mockupData = []; for (let k in Class) { @@ -247,10 +243,10 @@ for (let k in Class) { // Remove them purgeEntities(); -let mockupsLoadEndTime = Date.now(); +let mockupsLoadEndTime = performance.now(); console.log("Finished compiling " + mockupData.length + " classes into mockups."); -console.log("Mockups generated in " + (mockupsLoadEndTime - mockupsLoadStartTime) + " milliseconds.\n"); -console.log("Server loaded in " + (mockupsLoadEndTime - serverStartTime) + " milliseconds.\n"); +console.log("Mockups generated in " + util.rounder(mockupsLoadEndTime - mockupsLoadStartTime, 3) + " milliseconds.\n"); +console.log("Server loaded in " + util.rounder(mockupsLoadEndTime, 4) + " milliseconds.\n"); mockupsLoaded = true; let mockupJsonData = JSON.stringify(mockupData); diff --git a/server/modules/setup/room.js b/server/modules/setup/room.js index 17acedb8b..e729df0de 100644 --- a/server/modules/setup/room.js +++ b/server/modules/setup/room.js @@ -1,9 +1,11 @@ let importedRoom = []; -for (let filename of c.ROOM_SETUP) { +for (let filename of Config.ROOM_SETUP) { let currentRoom = require(`./rooms/${filename}.js`); - for (let y = 0; y < currentRoom.length; y++) { - for (let x = 0; x < currentRoom[0].length; x++) { + Config.roomHeight = currentRoom.length; + Config.roomWidth = currentRoom[0].length; + for (let y = 0; y < Config.roomHeight; y++) { + for (let x = 0; x < Config.roomWidth; x++) { if (importedRoom[y] == null) { importedRoom[y] = currentRoom[y]; } else if (currentRoom[y][x]) { @@ -16,6 +18,7 @@ for (let filename of c.ROOM_SETUP) { global.room = { lastCycle: undefined, cycleSpeed: 1000 / 30, + regenerateTick: Config.REGENERATE_TICK, setup: importedRoom, xgrid: importedRoom[0].length, ygrid: importedRoom.length, @@ -29,19 +32,19 @@ global.room = { }; Object.defineProperties(room, { - tileWidth: { get: () => c.TILE_WIDTH, set: v => c.TILE_WIDTH = v }, - tileHeight: { get: () => c.TILE_HEIGHT, set: v => c.TILE_HEIGHT = v }, - width: { get: () => room.xgrid * c.TILE_WIDTH, set: v => c.TILE_WIDTH = v / room.xgrid }, - height: { get: () => room.ygrid * c.TILE_HEIGHT, set: v => c.TILE_HEIGHT = v / room.ygrid } + tileWidth: { get: () => Config.TILE_WIDTH, set: v => Config.TILE_WIDTH = v }, + tileHeight: { get: () => Config.TILE_HEIGHT, set: v => Config.TILE_HEIGHT = v }, + width: { get: () => room.xgrid * Config.TILE_WIDTH, set: v => Config.TILE_WIDTH = v / room.xgrid }, + height: { get: () => room.ygrid * Config.TILE_HEIGHT, set: v => Config.TILE_HEIGHT = v / room.ygrid } }); Object.defineProperties(room.center, { - x: { get: () => room.xgrid * c.TILE_WIDTH / 2, set: v => c.TILE_WIDTH = v * 2 / room.xgrid }, - y: { get: () => room.ygrid * c.TILE_HEIGHT / 2, set: v => c.TILE_HEIGHT = v * 2 / room.ygrid } + x: { get: () => room.xgrid * Config.TILE_WIDTH / 2, set: v => Config.TILE_WIDTH = v * 2 / room.xgrid }, + y: { get: () => room.ygrid * Config.TILE_HEIGHT / 2, set: v => Config.TILE_HEIGHT = v * 2 / room.ygrid } }); room.isInRoom = location => { - if (c.ARENA_TYPE === "circle") { + if (Config.ARENA_TYPE === "circle") { return (location.x - room.center.x) ** 2 + (location.y - room.center.y) ** 2 < room.center.x ** 2; } return location.x >= 0 && location.x <= room.width && location.y >= 0 && location.y <= room.height; @@ -54,7 +57,7 @@ room.near = function(position, radius) { }; }; room.random = function() { - return c.ARENA_TYPE === "circle" ? room.near(room.center, room.center.x) : { + return Config.ARENA_TYPE === "circle" ? room.near(room.center, room.center.x) : { x: ran.irandom(room.width), y: ran.irandom(room.height) }; diff --git a/server/modules/setup/rooms/map_apspp_maze.js b/server/modules/setup/rooms/map_apspp_maze.js new file mode 100644 index 000000000..92524d564 --- /dev/null +++ b/server/modules/setup/rooms/map_apspp_maze.js @@ -0,0 +1,26 @@ +let { rock, roid } = require('../tiles/decoration.js'), + { normal: ____, nest } = require('../tiles/misc.js'), + +room = [ + [____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____], + [____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____], + [____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____], + [____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____], + [____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____], + [____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____], + [____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____], + [____,____,____,____,____,____,____,nest,nest,nest,nest,nest,____,____,____,____,____,____,____], + [____,____,____,____,____,____,____,nest,nest,nest,nest,nest,____,____,____,____,____,____,____], + [____,____,____,____,____,____,____,nest,nest,nest,nest,nest,____,____,____,____,____,____,____], + [____,____,____,____,____,____,____,nest,nest,nest,nest,nest,____,____,____,____,____,____,____], + [____,____,____,____,____,____,____,nest,nest,nest,nest,nest,____,____,____,____,____,____,____], + [____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____], + [____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____], + [____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____], + [____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____], + [____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____], + [____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____], + [____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____] +]; + +module.exports = room; \ No newline at end of file diff --git a/server/modules/setup/rooms/map_apspp_tiletest.js b/server/modules/setup/rooms/map_apspp_tiletest.js deleted file mode 100644 index b50e76422..000000000 --- a/server/modules/setup/rooms/map_apspp_tiletest.js +++ /dev/null @@ -1,42 +0,0 @@ -let { portal: port } = require('../tiles/portal.js'), - { rock, roid } = require('../tiles/decoration.js'), - { bossSpawn: boss, atmg, outside: out_ } = require('../tiles/siege.js'), - { wall, normal: ____, nest, nestNoBoss: nost } = require('../tiles/misc.js'), - { - dominatorBlue: dBlu, - dominatorGreen: dGrn, - dominatorContested: dCon, - sanctuaryBlue: sBlu, - sanctuaryGreen: sGrn, - sanctuaryContested: sCon - } = require('../tiles/dominators.js'), - { - base1: b1np, base1protected: b1hp, - base2: b2np, base2protected: b2hp, - base3: b3np, base3protected: b3hp, - base4: b4np, base4protected: b4hp, - base5: b5np, base5protected: b5hp, - base6: b6np, base6protected: b6hp, - base7: b7np, base7protected: b7hp, - base8: b8np, base8protected: b8hp - } = require('../tiles/tdm.js'), - -room = [ - [____,____,____,wall,____,____,____,wall,____,____,____,wall,out_,out_,out_,wall,____,b1hp,b1np], - [____,sBlu,____,wall,____,sGrn,____,wall,____,sCon,____,wall,out_,out_,atmg,wall,____,wall,wall], - [____,____,____,wall,____,____,____,wall,____,____,____,wall,out_,wall,wall,wall,____,b2hp,b2np], - [____,____,____,wall,____,____,____,wall,____,____,____,wall,out_,out_,out_,wall,____,wall,wall], - [____,dBlu,____,wall,____,dGrn,____,wall,____,dCon,____,wall,out_,____,boss,wall,____,b3hp,b3np], - [____,____,____,wall,____,____,____,wall,____,____,____,wall,out_,____,____,wall,____,wall,wall], - [____,____,____,wall,____,____,____,wall,____,____,____,wall,wall,wall,____,wall,____,b4hp,b4np], - [____,dBlu,____,wall,____,dGrn,____,wall,____,dCon,____,wall,____,____,____,wall,____,wall,wall], - [____,____,____,wall,____,____,____,wall,____,____,____,wall,____,wall,wall,wall,____,b5hp,b5np], - [____,____,____,wall,____,____,____,wall,____,____,____,wall,____,____,____,wall,____,wall,wall], - [____,port,____,wall,____,port,____,wall,____,port,____,wall,____,port,____,wall,____,b6hp,b6np], - [____,____,____,wall,____,____,____,wall,____,____,____,wall,____,____,____,wall,____,wall,wall], - [rock,rock,rock,rock,roid,roid,roid,roid,nest,nest,nest,nest,nost,nost,nost,nost,____,b7hp,b7np], - [rock,rock,rock,rock,roid,roid,roid,roid,nest,nest,nest,nest,nost,nost,nost,nost,____,wall,wall], - [rock,rock,rock,rock,roid,roid,roid,roid,nest,nest,nest,nest,nost,nost,nost,nost,____,b8hp,b8np] -]; - -module.exports = room; \ No newline at end of file diff --git a/server/modules/setup/rooms/map_neroio_arena.js b/server/modules/setup/rooms/map_neroio_arena.js new file mode 100644 index 000000000..d3c0053be --- /dev/null +++ b/server/modules/setup/rooms/map_neroio_arena.js @@ -0,0 +1,27 @@ +let { rock, roid } = require('../tiles/decoration.js'), + { wall: WALL, dancefloor: dcf0, dancefloor1: dcf1, dancefloor2: dcf2, dancefloor3: dcf3, dancefloor4: dcf4, dancefloor5: dcf5, normal: ____, normalNoFood: F___, nest, nestNoFood: nesf } = require('../tiles/misc.js'), + { portal: port } = require('../tiles/portal.js'), + +room = [ + [rock,rock,rock,roid,F___,F___,F___,F___,____,____,____,F___,F___,F___,F___,roid,rock,rock,rock,WALL,rock,rock,____,WALL,WALL,WALL,____,WALL,WALL,roid,____,F___,____,F___,____,F___,____,rock,rock], + [rock,rock,roid,____,F___,F___,F___,F___,F___,____,F___,F___,F___,F___,F___,____,roid,rock,rock,WALL,rock,rock,roid,WALL,F___,WALL,F___,____,WALL,____,F___,WALL,WALL,____,WALL,WALL,WALL,rock,rock], + [rock,roid,____,____,F___,F___,WALL,WALL,WALL,WALL,WALL,WALL,WALL,F___,F___,____,____,roid,rock,WALL,WALL,F___,____,F___,____,F___,WALL,F___,____,F___,WALL,F___,____,F___,____,F___,____,F___,____], + [roid,____,____,F___,F___,F___,F___,F___,F___,F___,F___,F___,F___,F___,F___,F___,____,____,roid,WALL,WALL,____,WALL,____,WALL,____,roid,____,WALL,WALL,WALL,____,WALL,roid,F___,____,WALL,____,WALL], + [F___,F___,F___,F___,nest,nesf,nest,nesf,nest,nesf,nest,nesf,nest,nesf,nest,F___,F___,F___,F___,WALL,WALL,F___,____,F___,WALL,WALL,WALL,F___,____,F___,WALL,F___,WALL,WALL,WALL,F___,WALL,F___,WALL], + [F___,F___,F___,F___,nesf,F___,F___,F___,F___,F___,F___,F___,F___,F___,nesf,F___,F___,F___,F___,WALL,WALL,WALL,WALL,____,F___,____,F___,____,WALL,____,roid,____,F___,____,F___,____,F___,____,roid], + [F___,F___,WALL,F___,nest,F___,WALL,WALL,WALL,F___,WALL,WALL,WALL,F___,nest,F___,WALL,F___,F___,WALL,____,F___,____,F___,WALL,F___,WALL,F___,WALL,WALL,WALL,F___,WALL,WALL,WALL,F___,WALL,WALL,WALL], + [____,____,WALL,F___,nesf,F___,WALL,dcf1,dcf0,dcf3,dcf2,dcf0,WALL,F___,nesf,F___,WALL,____,____,WALL,F___,WALL,roid,____,WALL,____,WALL,nest,nesf,nest,nesf,nest,WALL,____,F___,____,F___,____,WALL], + [F___,F___,WALL,F___,nest,F___,WALL,dcf2,dcf4,dcf1,dcf5,dcf1,WALL,F___,nest,F___,WALL,F___,F___,WALL,____,WALL,WALL,F___,WALL,F___,WALL,nesf,nest,nesf,nest,nesf,WALL,F___,____,F___,____,F___,WALL], + [____,____,WALL,F___,nesf,F___,F___,dcf0,dcf5,port,dcf2,dcf3,F___,F___,nesf,F___,WALL,F___,port,WALL,port,____,F___,____,WALL,____,F___,nest,nesf,port,nesf,nest,F___,____,F___,____,F___,____,WALL], + [F___,F___,WALL,F___,nest,F___,WALL,dcf4,dcf3,dcf1,dcf5,dcf0,WALL,F___,nest,F___,WALL,F___,F___,WALL,____,WALL,____,F___,roid,F___,WALL,nesf,nest,nesf,nest,nesf,WALL,F___,____,F___,____,F___,WALL], + [F___,F___,WALL,F___,nesf,F___,WALL,dcf5,dcf2,dcf4,dcf3,dcf4,WALL,F___,nesf,F___,WALL,____,____,WALL,F___,WALL,WALL,WALL,F___,roid,WALL,nest,nesf,nest,nesf,nest,WALL,____,F___,____,F___,____,WALL], + [F___,F___,WALL,F___,nest,F___,WALL,WALL,WALL,F___,WALL,WALL,WALL,F___,nest,F___,WALL,F___,F___,WALL,____,F___,____,F___,____,WALL,WALL,WALL,WALL,F___,WALL,F___,WALL,WALL,WALL,F___,WALL,WALL,WALL], + [F___,F___,F___,F___,nesf,F___,F___,F___,F___,F___,F___,F___,F___,F___,nesf,F___,F___,F___,F___,WALL,F___,WALL,F___,WALL,F___,roid,F___,____,F___,roid,F___,____,F___,____,F___,____,F___,____,F___], + [F___,F___,F___,F___,nest,nesf,nest,nesf,nest,nesf,nest,nesf,nest,nesf,nest,F___,F___,F___,F___,WALL,roid,WALL,____,WALL,____,F___,WALL,WALL,WALL,F___,WALL,WALL,WALL,F___,____,WALL,WALL,F___,____], + [roid,____,____,F___,F___,F___,F___,F___,F___,F___,F___,F___,F___,F___,F___,F___,____,____,roid,WALL,F___,WALL,F___,WALL,WALL,____,WALL,____,F___,____,WALL,roid,F___,____,F___,roid,F___,WALL,F___], + [rock,roid,____,____,F___,F___,WALL,WALL,WALL,WALL,WALL,WALL,WALL,F___,F___,____,____,roid,rock,WALL,____,WALL,____,F___,____,F___,WALL,F___,WALL,F___,WALL,F___,WALL,WALL,____,F___,____,WALL,____], + [rock,rock,roid,____,F___,F___,F___,F___,F___,____,F___,F___,F___,F___,F___,____,roid,rock,rock,WALL,rock,rock,roid,WALL,WALL,WALL,WALL,____,WALL,____,WALL,WALL,F___,____,F___,WALL,WALL,rock,rock], + [rock,rock,rock,roid,F___,F___,F___,F___,____,____,____,F___,F___,F___,F___,roid,rock,rock,rock,WALL,rock,rock,____,F___,____,F___,____,F___,WALL,F___,____,F___,____,WALL,____,roid,____,rock,rock] +]; + +module.exports = room; \ No newline at end of file diff --git a/server/modules/setup/rooms/map_neroio_banquet.js b/server/modules/setup/rooms/map_neroio_banquet.js new file mode 100644 index 000000000..7183af3f1 --- /dev/null +++ b/server/modules/setup/rooms/map_neroio_banquet.js @@ -0,0 +1,29 @@ +let { rock, roid, blackrock: blrk, blackroid: blrd } = require('../tiles/decoration.js'), + { wall: WALL, blacktile: blat, dancefloor: dcf0, dancefloor1: dcf1, dancefloor2: dcf2, dancefloor3: dcf3, dancefloor4: dcf4, dancefloor5: dcf5, normal: ____, nest } = require('../tiles/misc.js'), + { portal: port } = require('../tiles/portal.js'), + +room = [ + [rock,rock,rock,rock,roid,roid,____,____,____,____,____,____,____,____,____,roid,roid,rock,rock,rock,rock], + [rock,port,port,____,rock,____,____,roid,rock,rock,rock,rock,rock,roid,____,____,rock,____,port,port,rock], + [rock,port,port,____,rock,____,____,____,____,____,____,____,____,____,____,____,rock,____,port,port,rock], + [rock,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,rock], + [roid,rock,rock,____,nest,nest,nest,nest,nest,nest,nest,nest,nest,nest,nest,nest,nest,____,rock,rock,roid], + [roid,____,____,____,nest,____,____,____,____,____,____,____,____,____,____,____,nest,____,____,____,roid], + [____,____,____,____,nest,____,WALL,WALL,WALL,WALL,____,WALL,WALL,WALL,WALL,____,nest,____,____,____,____], + [____,____,____,____,nest,____,WALL,blrk,blrd,blat,blat,blat,blrd,blrk,WALL,____,nest,____,____,____,____], + [rock,____,____,____,nest,____,WALL,blrd,dcf4,dcf2,dcf0,dcf4,dcf0,blrd,WALL,____,nest,____,____,____,rock], + [rock,____,____,____,nest,____,WALL,blat,dcf5,dcf0,dcf0,dcf1,dcf4,blat,WALL,____,nest,____,____,____,rock], + [rock,roid,roid,____,nest,____,____,blat,dcf2,dcf3,dcf2,dcf5,dcf4,blat,____,____,nest,____,roid,roid,rock], + [rock,____,____,____,nest,____,WALL,blat,dcf3,dcf1,dcf4,dcf2,dcf5,blat,WALL,____,nest,____,____,____,rock], + [rock,____,____,____,nest,____,WALL,blrd,dcf1,dcf4,dcf1,dcf0,dcf2,blrd,WALL,____,nest,____,____,____,rock], + [____,____,____,____,nest,____,WALL,blrk,blrd,blat,blat,blat,blrd,blrk,WALL,____,nest,____,____,____,____], + [____,____,____,____,nest,____,WALL,WALL,WALL,WALL,____,WALL,WALL,WALL,WALL,____,nest,____,____,____,____], + [roid,____,____,____,nest,____,____,____,____,____,____,____,____,____,____,____,nest,____,____,____,roid], + [roid,rock,rock,____,nest,nest,nest,nest,nest,nest,nest,nest,nest,nest,nest,nest,nest,____,rock,rock,roid], + [rock,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,rock], + [rock,port,port,____,rock,____,____,____,____,____,____,____,____,____,____,____,rock,____,port,port,rock], + [rock,port,port,____,rock,____,____,roid,rock,rock,rock,rock,rock,roid,____,____,rock,____,port,port,rock], + [rock,rock,rock,rock,roid,roid,____,____,____,____,____,____,____,____,____,roid,roid,rock,rock,rock,rock] +]; + +module.exports = room; \ No newline at end of file diff --git a/server/modules/setup/rooms/map_neroio_blank.js b/server/modules/setup/rooms/map_neroio_blank.js new file mode 100644 index 000000000..886a424f1 --- /dev/null +++ b/server/modules/setup/rooms/map_neroio_blank.js @@ -0,0 +1,26 @@ +let { rock } = require('../tiles/decoration.js'), + { normal: ____, normalNoFood: F___, nest, nestNoFood: nesf } = require('../tiles/misc.js'), + +room = [ + [____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____], + [F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___], + [____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____], + [F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___], + [____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____], + [F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___], + [____,F___,____,F___,____,F___,rock,F___,rock,F___,rock,F___,rock,F___,____,F___,____,F___,____], + [F___,____,F___,____,F___,____,F___,nest,nesf,nest,nesf,nest,F___,____,F___,____,F___,____,F___], + [____,F___,____,F___,____,F___,rock,nesf,nest,nesf,nest,nesf,rock,F___,____,F___,____,F___,____], + [F___,____,F___,____,F___,____,F___,nest,nesf,nest,nesf,nest,F___,____,F___,____,F___,____,F___], + [____,F___,____,F___,____,F___,rock,nesf,nest,nesf,nest,nesf,rock,F___,____,F___,____,F___,____], + [F___,____,F___,____,F___,____,F___,nest,nesf,nest,nesf,nest,F___,____,F___,____,F___,____,F___], + [____,F___,____,F___,____,F___,rock,F___,rock,F___,rock,F___,rock,F___,____,F___,____,F___,____], + [F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___], + [____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____], + [F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___], + [____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____], + [F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___], + [____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____] +]; + +module.exports = room; \ No newline at end of file diff --git a/server/modules/setup/rooms/map_neroio_blank2.js b/server/modules/setup/rooms/map_neroio_blank2.js new file mode 100644 index 000000000..00d28eadf --- /dev/null +++ b/server/modules/setup/rooms/map_neroio_blank2.js @@ -0,0 +1,22 @@ +let { rock } = require('../tiles/decoration.js'), + { normal: ____, normalNoFood: F___, nest, nestNoFood: nesf } = require('../tiles/misc.js'), + +room = [ + [rock,F___,rock,F___,____,F___,____,F___,____,F___,____,F___,rock,F___,rock], + [F___,rock,F___,____,F___,____,F___,____,F___,____,F___,____,F___,rock,F___], + [rock,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,rock], + [F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___], + [____,F___,____,F___,rock,F___,rock,F___,rock,F___,rock,F___,____,F___,____], + [F___,____,F___,____,F___,nest,nesf,nest,nesf,nest,F___,____,F___,____,F___], + [____,F___,____,F___,rock,nesf,nest,nesf,nest,nesf,rock,F___,____,F___,____], + [F___,____,F___,____,F___,nest,nesf,nest,nesf,nest,F___,____,F___,____,F___], + [____,F___,____,F___,rock,nesf,nest,nesf,nest,nesf,rock,F___,____,F___,____], + [F___,____,F___,____,F___,nest,nesf,nest,nesf,nest,F___,____,F___,____,F___], + [____,F___,____,F___,rock,F___,rock,F___,rock,F___,rock,F___,____,F___,____], + [F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___], + [rock,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,rock], + [F___,rock,F___,____,F___,____,F___,____,F___,____,F___,____,F___,rock,F___], + [rock,F___,rock,F___,____,F___,____,F___,____,F___,____,F___,rock,F___,rock] +]; + +module.exports = room; \ No newline at end of file diff --git a/server/modules/setup/rooms/map_neroio_blank3.js b/server/modules/setup/rooms/map_neroio_blank3.js new file mode 100644 index 000000000..495fc4c1e --- /dev/null +++ b/server/modules/setup/rooms/map_neroio_blank3.js @@ -0,0 +1,26 @@ +let { rock } = require('../tiles/decoration.js'), + { wall: WALL, normal: ____, normalNoFood: F___, nest, nestNoFood: nesf, water: watr, fovwall: FWAL } = require('../tiles/misc.js'), + +room = [ + [rock,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,rock], + [F___,FWAL,F___,____,F___,____,WALL,WALL,WALL,____,WALL,rock,F___,____,F___,WALL,F___,FWAL,F___], + [____,F___,____,F___,WALL,F___,WALL,F___,____,F___,____,WALL,WALL,WALL,____,WALL,____,F___,____], + [F___,____,F___,WALL,F___,rock,F___,____,WALL,____,F___,WALL,F___,____,F___,____,WALL,____,WALL], + [WALL,WALL,____,WALL,____,F___,____,F___,WALL,F___,____,F___,____,F___,____,WALL,rock,F___,WALL], + [F___,rock,F___,rock,F___,WALL,F___,WALL,WALL,WALL,WALL,____,WALL,WALL,F___,WALL,F___,rock,F___], + [____,F___,rock,F___,____,WALL,rock,F___,rock,F___,rock,F___,rock,WALL,____,F___,rock,F___,____], + [F___,rock,F___,rock,F___,WALL,F___,nest,nesf,nest,nesf,nest,F___,WALL,WALL,____,WALL,WALL,F___], + [____,F___,____,WALL,WALL,WALL,rock,nesf,nest,nesf,nest,nesf,rock,WALL,watr,watr,watr,WALL,____], + [WALL,____,F___,____,F___,____,F___,nest,nesf,nest,nesf,nest,F___,____,watr,watr,watr,____,F___], + [WALL,F___,WALL,F___,____,WALL,rock,nesf,nest,nesf,nest,nesf,rock,WALL,watr,watr,watr,WALL,____], + [F___,____,WALL,____,F___,WALL,F___,nest,nesf,nest,nesf,nest,F___,WALL,WALL,____,WALL,WALL,F___], + [____,WALL,____,WALL,____,WALL,rock,F___,rock,F___,rock,F___,rock,WALL,____,F___,____,F___,rock], + [F___,____,F___,WALL,F___,WALL,WALL,____,WALL,WALL,WALL,WALL,F___,WALL,F___,WALL,WALL,____,WALL], + [____,F___,rock,F___,____,F___,____,F___,____,WALL,____,F___,____,F___,____,F___,____,F___,____], + [WALL,rock,F___,WALL,F___,____,F___,____,F___,____,F___,____,F___,WALL,WALL,WALL,F___,WALL,F___], + [____,F___,____,F___,WALL,F___,watr,watr,____,F___,rock,F___,____,WALL,____,F___,____,F___,____], + [F___,FWAL,F___,____,WALL,____,watr,watr,F___,____,WALL,rock,F___,WALL,F___,____,F___,FWAL,F___], + [rock,F___,____,F___,____,F___,____,F___,____,WALL,WALL,WALL,____,F___,____,WALL,____,F___,rock] +]; + +module.exports = room; \ No newline at end of file diff --git a/server/modules/setup/rooms/map_neroio_mazearena.js b/server/modules/setup/rooms/map_neroio_mazearena.js new file mode 100644 index 000000000..3e55ed953 --- /dev/null +++ b/server/modules/setup/rooms/map_neroio_mazearena.js @@ -0,0 +1,27 @@ +let { rock, roid } = require('../tiles/decoration.js'), + { wall: WALL, normal: ____, normalNoFood: F___, nest, nestNoFood: nesf, dfxwall: DWAL, fovwall: FWAL } = require('../tiles/misc.js'), + { portal: port } = require('../tiles/portal.js'), + +room = [ + [rock,rock,____,FWAL,WALL,WALL,____,WALL,WALL,roid,____,F___,____,F___,____,F___,roid,rock,rock], + [rock,rock,roid,WALL,F___,WALL,F___,roid,WALL,____,F___,WALL,WALL,____,WALL,WALL,WALL,rock,rock], + [WALL,F___,____,F___,roid,F___,WALL,F___,____,F___,FWAL,F___,____,F___,____,F___,____,F___,____], + [WALL,____,WALL,____,WALL,____,roid,____,WALL,WALL,WALL,____,WALL,roid,port,____,WALL,rock,WALL], + [WALL,F___,____,F___,WALL,WALL,WALL,F___,____,F___,WALL,F___,WALL,WALL,WALL,F___,WALL,F___,FWAL], + [WALL,WALL,WALL,roid,F___,____,F___,____,WALL,____,roid,____,F___,____,F___,____,F___,____,roid], + [____,F___,roid,rock,WALL,F___,WALL,F___,WALL,WALL,WALL,F___,WALL,WALL,WALL,F___,WALL,WALL,WALL], + [F___,WALL,roid,roid,WALL,roid,WALL,nest,nesf,nest,nesf,nest,WALL,roid,F___,____,F___,roid,WALL], + [____,WALL,FWAL,F___,WALL,F___,WALL,nesf,nest,nesf,nest,nesf,WALL,F___,____,F___,____,F___,WALL], + [F___,____,F___,____,WALL,____,F___,nest,nesf,nest,nesf,nest,F___,____,F___,____,F___,____,WALL], + [____,WALL,____,F___,roid,F___,WALL,nesf,nest,nesf,nest,nesf,WALL,F___,____,F___,____,F___,WALL], + [rock,WALL,WALL,WALL,F___,roid,WALL,nest,nesf,nest,nesf,nest,WALL,roid,F___,____,F___,roid,WALL], + [____,F___,____,F___,____,WALL,WALL,WALL,WALL,F___,WALL,F___,WALL,WALL,WALL,F___,WALL,WALL,WALL], + [F___,WALL,F___,WALL,F___,roid,F___,____,F___,roid,F___,____,F___,roid,F___,____,F___,____,F___], + [roid,WALL,____,WALL,port,F___,WALL,WALL,WALL,F___,WALL,WALL,WALL,F___,____,WALL,WALL,F___,____], + [F___,WALL,F___,WALL,FWAL,____,WALL,____,F___,roid,WALL,roid,F___,____,F___,roid,F___,WALL,F___], + [____,WALL,____,F___,____,F___,WALL,F___,WALL,F___,WALL,F___,DWAL,WALL,____,F___,____,FWAL,roid], + [rock,rock,roid,WALL,WALL,WALL,WALL,____,WALL,____,WALL,FWAL,F___,____,F___,WALL,WALL,rock,rock], + [rock,rock,____,F___,____,F___,____,F___,WALL,F___,roid,F___,____,WALL,____,roid,____,rock,rock] +]; + +module.exports = room; \ No newline at end of file diff --git a/server/modules/setup/rooms/map_neroio_mazearena2.js b/server/modules/setup/rooms/map_neroio_mazearena2.js new file mode 100644 index 000000000..495fc4c1e --- /dev/null +++ b/server/modules/setup/rooms/map_neroio_mazearena2.js @@ -0,0 +1,26 @@ +let { rock } = require('../tiles/decoration.js'), + { wall: WALL, normal: ____, normalNoFood: F___, nest, nestNoFood: nesf, water: watr, fovwall: FWAL } = require('../tiles/misc.js'), + +room = [ + [rock,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,____,F___,rock], + [F___,FWAL,F___,____,F___,____,WALL,WALL,WALL,____,WALL,rock,F___,____,F___,WALL,F___,FWAL,F___], + [____,F___,____,F___,WALL,F___,WALL,F___,____,F___,____,WALL,WALL,WALL,____,WALL,____,F___,____], + [F___,____,F___,WALL,F___,rock,F___,____,WALL,____,F___,WALL,F___,____,F___,____,WALL,____,WALL], + [WALL,WALL,____,WALL,____,F___,____,F___,WALL,F___,____,F___,____,F___,____,WALL,rock,F___,WALL], + [F___,rock,F___,rock,F___,WALL,F___,WALL,WALL,WALL,WALL,____,WALL,WALL,F___,WALL,F___,rock,F___], + [____,F___,rock,F___,____,WALL,rock,F___,rock,F___,rock,F___,rock,WALL,____,F___,rock,F___,____], + [F___,rock,F___,rock,F___,WALL,F___,nest,nesf,nest,nesf,nest,F___,WALL,WALL,____,WALL,WALL,F___], + [____,F___,____,WALL,WALL,WALL,rock,nesf,nest,nesf,nest,nesf,rock,WALL,watr,watr,watr,WALL,____], + [WALL,____,F___,____,F___,____,F___,nest,nesf,nest,nesf,nest,F___,____,watr,watr,watr,____,F___], + [WALL,F___,WALL,F___,____,WALL,rock,nesf,nest,nesf,nest,nesf,rock,WALL,watr,watr,watr,WALL,____], + [F___,____,WALL,____,F___,WALL,F___,nest,nesf,nest,nesf,nest,F___,WALL,WALL,____,WALL,WALL,F___], + [____,WALL,____,WALL,____,WALL,rock,F___,rock,F___,rock,F___,rock,WALL,____,F___,____,F___,rock], + [F___,____,F___,WALL,F___,WALL,WALL,____,WALL,WALL,WALL,WALL,F___,WALL,F___,WALL,WALL,____,WALL], + [____,F___,rock,F___,____,F___,____,F___,____,WALL,____,F___,____,F___,____,F___,____,F___,____], + [WALL,rock,F___,WALL,F___,____,F___,____,F___,____,F___,____,F___,WALL,WALL,WALL,F___,WALL,F___], + [____,F___,____,F___,WALL,F___,watr,watr,____,F___,rock,F___,____,WALL,____,F___,____,F___,____], + [F___,FWAL,F___,____,WALL,____,watr,watr,F___,____,WALL,rock,F___,WALL,F___,____,F___,FWAL,F___], + [rock,F___,____,F___,____,F___,____,F___,____,WALL,WALL,WALL,____,F___,____,WALL,____,F___,rock] +]; + +module.exports = room; \ No newline at end of file diff --git a/server/modules/setup/rooms/map_neroio_zerolag.js b/server/modules/setup/rooms/map_neroio_zerolag.js new file mode 100644 index 000000000..128da7021 --- /dev/null +++ b/server/modules/setup/rooms/map_neroio_zerolag.js @@ -0,0 +1,14 @@ +let { normalNoFood: F___, hookpoint: hook, water: watr } = require('../tiles/misc.js'), + +room = [ + [F___,F___,F___,F___,F___,F___,F___,F___], + [F___,F___,F___,F___,F___,F___,F___,F___], + [F___,F___,F___,F___,F___,F___,F___,F___], + [F___,F___,F___,F___,F___,F___,F___,F___], + [F___,F___,F___,F___,F___,F___,F___,F___], + [F___,F___,F___,F___,F___,watr,watr,F___], + [F___,F___,F___,F___,F___,watr,watr,F___], + [F___,F___,F___,F___,F___,F___,F___,F___] +]; + +module.exports = room; \ No newline at end of file diff --git a/server/modules/setup/rooms/map_nexus_trplnr.js b/server/modules/setup/rooms/map_nexus_trplnr.js index 4548e515a..7f092a1bb 100644 --- a/server/modules/setup/rooms/map_nexus_trplnr.js +++ b/server/modules/setup/rooms/map_nexus_trplnr.js @@ -1,31 +1,15 @@ -let { base1: _1 , base1protected: p1 } = require('../tiles/tdm.js'), - { bossSpawn: b , atmg: A } = require('../tiles/siege.js'), - { wall: WALL, nest: n , normal: _ } = require('../tiles/misc.js'), - { rock: r } = require('../tiles/decoration.js'), - { portal: P } = require('../tiles/portal.js'), +let { base1: bas1, base2: bas2, base3: bas3, base4: bas4 } = require('../tiles/tdm.js'), + {} = require('../tiles/dominators.js', -// Yes. I am aware that the food distract the ATMGs, but ask trplnr why he put normal's instead of outside's outside the room room = [ - [ _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , A , _ , _ , _ , _ , _ , _ , _ ,WALL, _ , _ ], - [ _ , A , _ , _ , A , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , A , _ , _ , _ , _ ,WALL, P , _ ], - [ _ , _ , _ , _ , _ ,WALL,WALL,WALL,WALL, _ , _ , _ , _ , _ ,WALL, _ ,WALL,WALL,WALL, _ , _ , _ ,WALL,WALL,WALL], - [ _ , _ , _ , _ , _ ,WALL, r , r ,WALL, A , _ , _ , _ ,WALL, _ , _ , _ , _ , _ , _ ,WALL, A , _ , _ , _ ], - [ _ , _ , _ , _ , _ ,WALL, r , r ,WALL, _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ ], - [ _ , A ,WALL, _ , _ ,WALL, _ ,WALL,WALL,WALL,WALL,WALL,WALL, _ ,WALL,WALL,WALL,WALL,WALL,WALL, _ ,WALL, _ , _ , _ ], - [ _ , _ , _ , _ , _ ,WALL, r , r , r ,WALL, _ , _ , _ , _ , _ ,WALL, b , b , b ,WALL, _ , _ , _ , _ , _ ], - [ _ , _ , _ , _ , _ ,WALL, r , P , r ,WALL,WALL,WALL, _ ,WALL,WALL,WALL, _ , _ , _ ,WALL, _ , _ , _ , _ , _ ], - [ _ , _ , _ , _ , _ ,WALL, r , r , r ,WALL, _ , _ , _ , _ , _ ,WALL,WALL, _ ,WALL,WALL, _ , _ ,WALL,WALL,WALL], - [ P , A ,WALL, _ , _ ,WALL, r , r , r ,WALL, _ , _1 , _1 , _1 , _ ,WALL, _ , _ , _ ,WALL, _ , _ , _ , n ,WALL], - [ _ , _ , _ , _ , _ ,WALL, r , r , r , _ , _ , _1 , p1 , _1 , _ , _ , _ , P , _ ,WALL, _ , _ ,WALL, n ,WALL], - [ _ , _ , _ , _ , _ ,WALL, r , r , r ,WALL, _ , _1 , _1 , _1 , _ ,WALL, _ , _ , _ ,WALL, _ , A ,WALL, P ,WALL], - [ _ , _ , _ , _ , _ ,WALL,WALL, r ,WALL,WALL, _ , _ , _ , _ , _ ,WALL,WALL,WALL,WALL,WALL, _ , _ ,WALL, n ,WALL], - [ _ , A ,WALL, _ , _ ,WALL, r , r , r ,WALL, _ ,WALL,WALL,WALL, _ ,WALL, _ , _ , _ , _ , _ , _ ,WALL,WALL,WALL], - [ _ , _ , _ , _ , _ ,WALL, r , r , r ,WALL, r , n , n , n , r ,WALL, _ , _ , _ , _ ,WALL, _ , _ , _ , _ ], - [ _ , _ , _ , _ , _ ,WALL,WALL,WALL, _ ,WALL,WALL,WALL,WALL,WALL,WALL,WALL, _ , _ , _ , _ , _ , _ , b , _ , _ ], - [ _ , _ , _ , _ , _ , _ , _ ,WALL, r ,WALL, _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , A , _ , A , _ ], - [ _ , A ,WALL, _ , _ , _ , _ ,WALL, _ ,WALL, _ , _ , _ , _ , _ , _ ,WALL, _ , _ , _ , b , _ , P , _ , b ], - [ _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ ,WALL, _ , A , _ , _ , _ , A , _ , A , _ ], - [ _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , b , _ , _ ], + [F___,F___,F___,hook,F___,F___,F___,F___], + [F___,hook,F___,F___,F___,F___,hook,F___], + [F___,F___,F___,F___,hook,F___,F___,F___], + [F___,F___,hook,F___,F___,F___,F___,hook], + [hook,F___,F___,F___,F___,hook,F___,F___], + [F___,F___,F___,hook,F___,F___,F___,F___], + [F___,hook,F___,F___,F___,F___,hook,F___], + [F___,F___,F___,F___,hook,F___,F___,F___] ]; module.exports = room; \ No newline at end of file diff --git a/server/modules/setup/rooms/map_old_dreadnoughts.js b/server/modules/setup/rooms/map_old_dreadnoughts.js new file mode 100644 index 000000000..34a4f236f --- /dev/null +++ b/server/modules/setup/rooms/map_old_dreadnoughts.js @@ -0,0 +1,92 @@ +let { nest } = require('../tiles/misc.js'), + { open: ____, labyrinth, forge, outOfBounds } = require('../tiles/old_dreadnoughts.js'), + teams = require('../gamemodeconfigs/old_dreadnoughts.js').TEAMS, + bases = require('../tiles/tdm.js'), + +room = [ + [____,____,____,____,____,____,____,____,____,____,____,____,____,____,____], + [____,____,____,____,____,____,____,____,____,____,____,____,____,____,____], + [____,____,____,____,____,____,____,____,____,____,____,____,____,____,____], + [____,____,____,____,____,____,____,____,____,____,____,____,____,____,____], + [____,____,____,____,____,____,____,____,____,____,____,____,____,____,____], + [____,____,____,____,____,nest,nest,nest,nest,nest,____,____,____,____,____], + [____,____,____,____,____,nest,nest,nest,nest,nest,____,____,____,____,____], + [____,____,____,____,____,nest,nest,nest,nest,nest,____,____,____,____,____], + [____,____,____,____,____,nest,nest,nest,nest,nest,____,____,____,____,____], + [____,____,____,____,____,nest,nest,nest,nest,nest,____,____,____,____,____], + [____,____,____,____,____,____,____,____,____,____,____,____,____,____,____], + [____,____,____,____,____,____,____,____,____,____,____,____,____,____,____], + [____,____,____,____,____,____,____,____,____,____,____,____,____,____,____], + [____,____,____,____,____,____,____,____,____,____,____,____,____,____,____], + [____,____,____,____,____,____,____,____,____,____,____,____,____,____,____] +]; +Config.roomHeight = room.length; +Config.roomWidth = room[0].length; + +let locations = [ + [ + [[ 0, 0], [ 1, 0], [ 0, 1]], + [[ 1, 1]] + ],[ + [ + [Config.roomHeight - 1, Config.roomWidth - 1], + [Config.roomHeight - 2, Config.roomWidth - 1], + [Config.roomHeight - 1, Config.roomWidth - 2] + ], + [[Config.roomHeight - 2, Config.roomWidth - 2]] + ],[ + [ + [ 0, Config.roomWidth - 1], + [ 1, Config.roomWidth - 1], + [ 0, Config.roomWidth - 2] + ], + [[ 1, Config.roomWidth - 2]] + ],[ + [ + [Config.roomHeight - 1, 0], + [Config.roomHeight - 1, 1], + [Config.roomHeight - 2, 0] + ], + [[Config.roomHeight - 2, 1]] + ] +]; + +if (teams === 2) { + let baseprotGap = Math.ceil((Config.roomHeight - 1) / 6); + for (let y = 0; y < Config.roomHeight; y++) { + room[y][0] = bases.base1; + room[y][Config.roomWidth - 1] = bases.base2; + } + for (let i = -2; i <= 2; i++) { + let y = Math.floor(Config.roomHeight / 2 - baseprotGap * i); + room[y][0] = bases.base1protected; + room[y][Config.roomWidth - 1] = bases.base2protected; + } +} else { + for (let i = 1; i <= teams; i++) { + let [ spawns, protectors ] = locations[i - 1]; + for (let [y, x] of spawns) room[y][x] = bases[`base${i}`]; + for (let [y, x] of protectors) room[y][x] = bases[`base${i}protected`]; + } +} + +for (let row in room) { + if (row < 11 && row >= 4) { + room[row].unshift(...Array(4).fill(outOfBounds), ...Array(7).fill(forge), ...Array(4).fill(outOfBounds)); + } else { + room[row].unshift(...Array(Config.roomWidth).fill(outOfBounds)); + } +} +for (let row of room) { + row.unshift(...Array(Config.roomWidth).fill(labyrinth)); +} + +Config.FOOD_TYPES_NEST = [ + [1, [ + [4, 'pentagon'], [ 12, 'betaPentagon'], [ 8, 'alphaPentagon'], [ 5, 'hexagonOfficialV1'], [ 4, 'heptagonOfficialV1'], [ 3, 'octagonOfficialV1'], [ 2, 'nonagonOfficialV1'] + ]] +]; + +require('../../gamemodes/oldDreadnoughts.js'); + +module.exports = room; \ No newline at end of file diff --git a/server/modules/setup/rooms/map_risk_default.js b/server/modules/setup/rooms/map_risk_default.js new file mode 100644 index 000000000..d6ddddbf4 --- /dev/null +++ b/server/modules/setup/rooms/map_risk_default.js @@ -0,0 +1,17 @@ +let { base1: bas1 , base2: bas2, base3: bas3, base4: bas4 } = require('../tiles/tdm.js'), + { normal: norm, nest, wall: WALL } = require('../tiles/misc.js'), + { dominatorContestedBlank: cont, trapDominatorContestedBlank: scon } = require('../tiles/dominators.js'), + +room = [ + [bas1,cont,cont,cont,cont,cont,cont,cont,bas2], + [cont,WALL,cont,cont,cont,cont,cont,WALL,cont], + [cont,cont,cont,cont,cont,cont,cont,cont,cont], + [cont,cont,cont,WALL,norm,WALL,cont,cont,cont], + [cont,cont,cont,norm,nest,norm,cont,cont,cont], + [cont,cont,cont,WALL,norm,WALL,cont,cont,cont], + [cont,cont,cont,cont,cont,cont,cont,cont,cont], + [cont,WALL,cont,cont,cont,cont,cont,WALL,cont], + [bas3,cont,cont,cont,cont,cont,cont,cont,bas4] +]; + +module.exports = room; \ No newline at end of file diff --git a/server/modules/setup/rooms/overlay_domination.js b/server/modules/setup/rooms/overlay_domination.js index 6f3da9c6a..93cbf5103 100644 --- a/server/modules/setup/rooms/overlay_domination.js +++ b/server/modules/setup/rooms/overlay_domination.js @@ -1,7 +1,11 @@ let { dominatorContested } = require('../tiles/dominators.js'), + room = Array(Config.roomHeight).fill(() => Array(Config.roomWidth).fill()).map(x => x()); -room = Array(15).fill(() => Array(15).fill()).map(x => x()); - -room[7][2] = room[2][7] = room[12][7] = room[7][12] = room[7][7] = dominatorContested; +room[Math.floor(Config.roomHeight / 2)][Math.floor(Config.roomWidth / 4)] = +room[Math.floor(Config.roomHeight / 4)][Math.floor(Config.roomWidth / 2)] = +room[Math.floor(3 * Config.roomHeight / 4)][Math.floor(Config.roomWidth / 2)] = +room[Math.floor(Config.roomHeight / 2)][Math.floor(3 * Config.roomWidth / 4)] = +room[Math.floor(Config.roomHeight / 2)][Math.floor(Config.roomWidth / 2)] = +dominatorContested; module.exports = room; \ No newline at end of file diff --git a/server/modules/setup/rooms/overlay_maze.js b/server/modules/setup/rooms/overlay_maze.js index 35076e3db..2d48af100 100644 --- a/server/modules/setup/rooms/overlay_maze.js +++ b/server/modules/setup/rooms/overlay_maze.js @@ -1,8 +1,9 @@ let { nest } = require('../tiles/misc.js'), - room = Array(15).fill(() => Array(15).fill()).map(x => x()); + room = Array(Config.roomHeight).fill(() => Array(Config.roomWidth).fill()).map(x => x()), + nestRadius = 2; -for (let x = 4; x <= 10; x++) { - for (let y = 4; y <= 10; y++) { +for (let x = Math.floor(Config.roomWidth / 2) - nestRadius; x <= Math.floor(Config.roomWidth / 2) + nestRadius; x++) { + for (let y = Math.floor(Config.roomHeight / 2) - nestRadius; y <= Math.floor(Config.roomHeight / 2) + nestRadius; y++) { room[y][x] = nest; } } diff --git a/server/modules/setup/rooms/overlay_portal.js b/server/modules/setup/rooms/overlay_portal.js index 049ed85f9..d487ea603 100644 --- a/server/modules/setup/rooms/overlay_portal.js +++ b/server/modules/setup/rooms/overlay_portal.js @@ -1,7 +1,12 @@ let { portal } = require('../tiles/portal.js'), - room = Array(15).fill(() => Array(15).fill()).map(x => x()); +room = Array(Config.roomHeight).fill(() => Array(Config.roomWidth).fill()).map(x => x()); -room[2][2] = room[2][12] = room[12][2] = room[12][12] = room[7][7] = portal; +room[Math.floor(Config.roomHeight / 4)][Math.floor(Config.roomWidth / 4)] = +room[Math.floor(3 * Config.roomHeight / 4)][Math.floor(Config.roomWidth / 4)] = +room[Math.floor(3 * Config.roomHeight / 4)][3 * Math.floor(Config.roomWidth / 4)] = +room[Math.floor(Config.roomHeight / 4)][Math.floor(3 * Config.roomWidth / 4)] = +room[Math.floor(Config.roomHeight / 2)][Math.floor(Config.roomWidth / 2)] = +portal; module.exports = room; \ No newline at end of file diff --git a/server/modules/setup/rooms/overlay_tdm.js b/server/modules/setup/rooms/overlay_tdm.js index 4db58a647..c63d81af0 100644 --- a/server/modules/setup/rooms/overlay_tdm.js +++ b/server/modules/setup/rooms/overlay_tdm.js @@ -1,38 +1,80 @@ let bases = require('../tiles/tdm.js'), teams = require('../gamemodeconfigs/tdm.js').TEAMS, - room = Array(15).fill(() => Array(15).fill()).map(x => x()), + room = Array(Config.roomHeight).fill(() => Array(Config.roomWidth).fill()).map(x => x()), + isMaze = Config.GAME_MODES.includes('maze'), locations = [ [ - [[ 0, 0], [ 1, 0], [ 0, 1]], - [[ 1, 1]] + [[ 0 + isMaze, 0 + isMaze], [ 1 + isMaze, 0 + isMaze], [ 0 + isMaze, 1 + isMaze]], + [[ 1 + isMaze, 1 + isMaze]] ],[ - [[14, 14], [13, 14], [14, 13]], - [[13, 13]] + [ + [Config.roomHeight - 1 - isMaze, Config.roomWidth - 1 - isMaze], + [Config.roomHeight - 2 - isMaze, Config.roomWidth - 1 - isMaze], + [Config.roomHeight - 1 - isMaze, Config.roomWidth - 2 - isMaze] + ], + [[Config.roomHeight - 2 - isMaze, Config.roomWidth - 2 - isMaze]] ],[ - [[ 0, 14], [ 1, 14], [ 0, 13]], - [[ 1, 13]] + [ + [ 0 + isMaze, Config.roomWidth - 1 - isMaze], + [ 1 + isMaze, Config.roomWidth - 1 - isMaze], + [ 0 + isMaze, Config.roomWidth - 2 - isMaze] + ], + [[ 1 + isMaze, Config.roomWidth - 2 - isMaze]] ],[ - [[14, 0], [14, 1], [13, 0]], - [[13, 1]] + [ + [Config.roomHeight - 1 - isMaze, 0 + isMaze], + [Config.roomHeight - 1 - isMaze, 1 + isMaze], + [Config.roomHeight - 2 - isMaze, 0 + isMaze] + ], + [[Config.roomHeight - 2 - isMaze, 1 + isMaze]] ],[ - [[0, 6], [1, 7], [0, 8]], - [[0, 7]] + [ + [0 + isMaze, Math.floor(Config.roomWidth / 2) - 1], + [1 + isMaze, Math.floor(Config.roomWidth / 2)], + [0 + isMaze, Math.floor(Config.roomWidth / 2) + 1] + ], + [[0 + isMaze, Math.floor(Config.roomWidth / 2)]] ],[ - [[6, 14], [7, 13], [8, 14]], - [[7, 14]] + [ + [Math.floor(Config.roomHeight / 2) - 1, Config.roomWidth - 1 - isMaze], + [Math.floor(Config.roomHeight / 2), Config.roomWidth - 2 - isMaze], + [Math.floor(Config.roomHeight / 2) + 1, Config.roomWidth - 1 - isMaze] + ], + [[Math.floor(Config.roomHeight / 2), Config.roomWidth - 1 - isMaze]] ],[ - [[14, 6], [13, 7], [14, 8]], - [[14, 7]] + [ + [Config.roomHeight - 1 - isMaze, Math.floor(Config.roomWidth / 2) - 1], + [Config.roomHeight - 2 - isMaze, Math.floor(Config.roomWidth / 2)], + [Config.roomHeight - 1 - isMaze, Math.floor(Config.roomWidth / 2) + 1] + ], + [[Config.roomHeight - 1 - isMaze, Math.floor(Config.roomWidth / 2)]] ],[ - [[6, 0], [7, 1], [8, 0]], - [[7, 0]] + [ + [Math.floor(Config.roomHeight / 2) - 1, 0 + isMaze], + [Math.floor(Config.roomHeight / 2), 1 + isMaze], + [Math.floor(Config.roomHeight / 2) + 1, 0 + isMaze] + ], + [[Math.floor(Config.roomHeight / 2), 0 + isMaze]] ] ]; -for (let i = 1; i <= teams; i++) { - let [ spawns, protectors ] = locations[i - 1]; - for (let [y, x] of spawns) room[y][x] = bases[`base${i}`]; - for (let [y, x] of protectors) room[y][x] = bases[`base${i}protected`]; +if (teams === 2 && !isMaze) { + let baseprotGap = Math.ceil((Config.roomHeight - 1) / 6); + for (let y = 0; y < Config.roomHeight; y++) { + room[y][0] = bases.base1; + room[y][Config.roomWidth - 1] = bases.base2; + } + for (let i = -2; i <= 2; i++) { + let y = Math.floor(Config.roomHeight / 2 - baseprotGap * i); + room[y][0] = bases.base1protected; + room[y][Config.roomWidth - 1] = bases.base2protected; + } +} else { + for (let i = 1; i <= teams; i++) { + let [ spawns, protectors ] = locations[i - 1]; + for (let [y, x] of spawns) room[y][x] = bases[`base${i}`]; + for (let [y, x] of protectors) room[y][x] = bases[`base${i}protected`]; + } } -module.exports = room; +module.exports = room; \ No newline at end of file diff --git a/server/modules/setup/tiles/decoration.js b/server/modules/setup/tiles/decoration.js index 89167b603..390a01580 100644 --- a/server/modules/setup/tiles/decoration.js +++ b/server/modules/setup/tiles/decoration.js @@ -23,8 +23,35 @@ let makeDecoration = defs => new Tile({ } } }); +let makeDecorationblack = defs => new Tile({ + color: "black", + data: { + allowMazeWallSpawn: false, + foodSpawnCooldown: 0, foodCount: 0 + }, + init: tile => { + for (let [def, amount] of defs) { + def = ensureIsClass(def); + let checkRadius = 10 + def.SIZE; + for (; amount; amount--) { + let i = 200, position = {}; + do { + position = tile.randomInside(); + } while (i-- && dirtyCheck(position, checkRadius)); + let o = new Entity(position); + o.team = TEAM_ROOM; + o.facing = ran.randomAngle(); + o.define(def); + o.protect(); + o.life(); + } + } + } +}); module.exports = { rock: makeDecoration([['rock', 0], ['gravel', 2]]), - roid: makeDecoration([['rock', 1], ['gravel', 1]]) + roid: makeDecoration([['rock', 1], ['gravel', 1]]), + blackrock: makeDecorationblack([['rock', 0], ['gravel', 2]]), + blackroid: makeDecorationblack([['rock', 1], ['gravel', 1]]) }; \ No newline at end of file diff --git a/server/modules/setup/tiles/dominators.js b/server/modules/setup/tiles/dominators.js index c58b698c6..526de4429 100644 --- a/server/modules/setup/tiles/dominators.js +++ b/server/modules/setup/tiles/dominators.js @@ -1,5 +1,5 @@ let dominatorTypes = ["destroyerDominator", "gunnerDominator", "trapperDominator"], - neededToWin = 4, + neededToWin = Config.GOVERNMENTAL ? 63 : 4, teamcounts = {}, gameWon = false, @@ -12,8 +12,9 @@ spawn = (tile, team, color, type = false) => { o.color.base = color; o.skill.score = 111069; o.name = "Dominator"; - o.SIZE = room.tileWidth / 10; - o.isDominator = true; + o.nameColor = "#ffffff"; + o.SIZE = Config.GOVERNMENTAL ? room.tileWidth / 20 : room.tileWidth / 15; + if (!Config.GOVERNMENTAL) o.isDominator = true; o.controllers = [new ioTypes.nearestDifferentMaster(o), new ioTypes.spin(o, { onlyWhenIdle: true })]; tile.color.base = color; @@ -33,7 +34,7 @@ spawn = (tile, team, color, type = false) => { let newTeam = TEAM_ENEMIES, newColor = getTeamColor(newTeam); - if (team === TEAM_ENEMIES) { + if (team === TEAM_ENEMIES || Config.GOVERNMENTAL) { let killers = []; for (let instance of o.collisionArray) { if (isPlayerTeam(instance.team) && team !== instance.team) { @@ -42,19 +43,21 @@ spawn = (tile, team, color, type = false) => { } let killer = ran.choose(killers); - killer = killer ? killer.master.master : { team: TEAM_ROOM, color: c.MODE === "tdm" ? 3 : 12 }; + killer = killer ? killer.master.master : { team: TEAM_ROOM, color: Config.MODE === "tdm" ? 3 : 12 }; newTeam = killer.team; newColor = getTeamColor(newTeam); - for (let player of sockets.players) { + if (type !== "territoryCapturePoint") { + for (let player of sockets.players) { if (player.body && player.body.team === newTeam) { player.body.sendMessage("Press F to take control of the dominator."); } } + } let teamName = newTeam > 0 ? killer.name : getTeamName(newTeam); - sockets.broadcast(`A dominator is now controlled by ${teamName}!`); + Config.GOVERNMENTAL ? sockets.broadcast(`${teamName} has Gained +1 Territory`) : sockets.broadcast(`A dominator is now controlled by ${teamName}!`); if (newTeam !== TEAM_ENEMIES && teamcounts[newTeam] >= neededToWin && !gameWon) { gameWon = true; setTimeout(sockets.broadcast, 1500, teamName + " has won the game!"); @@ -62,7 +65,11 @@ spawn = (tile, team, color, type = false) => { } } else { - sockets.broadcast("A dominator is being contested!"); + for (let player of sockets.players) { + if (player.body && player.body.team === team) { + Config.GOVERNMENTAL ? player.body.sendMessage("Your Territory is being invaded!") : sockets.broadcast("A dominator is being contested!"); + } + } } spawn(tile, newTeam, newColor, type); @@ -70,14 +77,14 @@ spawn = (tile, team, color, type = false) => { }); }, -makeDefenderDominator = (tile, mainTeam, team, aliveDef) => { +makeDefenderDominator = (tile, mainTeam, team, deadTeam, aliveDef) => { aliveDef = aliveDef ? aliveDef : ran.choose(dominatorTypes); let o = new Entity(tile.loc); o.define(mainTeam == team ? aliveDef : "dominator"); o.team = team; o.color.base = getTeamColor(team); o.skill.score = 111069; - o.SIZE = room.tileWidth / 10; + o.SIZE = room.tileWidth / 15; o.isDominator = true; tile.color.base = getTeamColor(team); @@ -103,24 +110,56 @@ makeDefenderDominator = (tile, mainTeam, team, aliveDef) => { sockets.broadcast(`A ${o.label} has been repaired!`); } - makeDefenderDominator(tile, mainTeam, team === mainTeam ? TEAM_ENEMIES : mainTeam, aliveDef); + makeDefenderDominator(tile, mainTeam, team === mainTeam ? deadTeam : mainTeam, deadTeam, aliveDef); sockets.broadcastRoom(); }); }; -let dominatorBlue = new Tile({ init: tile => makeDefenderDominator(tile, TEAM_BLUE, TEAM_BLUE) }), - dominatorGreen = new Tile({ init: tile => makeDefenderDominator(tile, TEAM_GREEN, TEAM_GREEN) }), +let dominatorBlue = new Tile({ init: tile => makeDefenderDominator(tile, TEAM_BLUE, TEAM_BLUE, TEAM_ENEMIES) }), + dominatorGreen = new Tile({ init: tile => makeDefenderDominator(tile, TEAM_GREEN, TEAM_GREEN, TEAM_BLUE) }), dominatorContested = new Tile({ init: tile => spawn(tile, TEAM_ENEMIES, getTeamColor(TEAM_ENEMIES)) }), - sanctuaryBlue = new Tile({ init: tile => makeDefenderDominator(tile, TEAM_BLUE, TEAM_BLUE, 'sanctuaryTier1') }), - sanctuaryGreen = new Tile({ init: tile => makeDefenderDominator(tile, TEAM_GREEN, TEAM_GREEN, 'sanctuaryTier1') }), + sanctuaryBlue = new Tile({ init: tile => makeDefenderDominator(tile, TEAM_BLUE, TEAM_BLUE, TEAM_ENEMIES, 'sanctuaryTier1') }), + sanctuaryGreen = new Tile({ init: tile => makeDefenderDominator(tile, TEAM_GREEN, TEAM_GREEN, TEAM_BLUE, 'sanctuaryTier3') }), sanctuaryContested = new Tile({ init: tile => spawn(tile, TEAM_ENEMIES, getTeamColor(TEAM_ENEMIES), 'sanctuaryTier1') }); + dominatorContestedBlank = new Tile({ + init: tile => spawn(tile, TEAM_ENEMIES, "white", "territoryCapturePoint"), + tick: tile => { + for (let i = 0; i < tile.entities.length; i++) { + let entity = tile.entities[i]; + if (entity.isPlayer) { + if (entity.pushability && entity.isPlayer && entity.color.base !== tile.color.base) { + let dirToCenter = Math.atan2(entity.y - tile.y, entity.x - tile.x); + entity.velocity.x = Math.cos(dirToCenter) * 25 * entity.pushability; + entity.velocity.y = Math.sin(dirToCenter) * 25 * entity.pushability; + } + } + } + } }), + trapDominatorContestedBlank = new Tile({ + init: tile => spawn(tile, TEAM_ENEMIES, "white", "trapTerritoryCapturePoint"), + tick: tile => { + for (let i = 0; i < tile.entities.length; i++) { + let entity = tile.entities[i]; + if (entity.isPlayer) { + if (entity.pushability && entity.color.base !== tile.color.base) { + let dirToCenter = Math.atan2(entity.y - tile.y, entity.x - tile.x); + entity.velocity.x = Math.cos(dirToCenter) * 25 * entity.pushability; + entity.velocity.y = Math.sin(dirToCenter) * 25 * entity.pushability; + } + } + } + } }); + + module.exports = { contested: dominatorContested, dominatorBlue, dominatorGreen, dominatorContested, + dominatorContestedBlank, // risk + trapDominatorContestedBlank, // frisky risky sanctuaryBlue, // siege sanctuaryGreen, // assault sanctuaryContested // idk i thought it was funny diff --git a/server/modules/setup/tiles/misc.js b/server/modules/setup/tiles/misc.js index 70718482f..5166ae3ea 100644 --- a/server/modules/setup/tiles/misc.js +++ b/server/modules/setup/tiles/misc.js @@ -23,27 +23,104 @@ normal = new Tile({ }, init: tile => room.spawnableDefault.push(tile), tick: tile => { - if (++tile.data.foodSpawnCooldown > c.FOOD_SPAWN_COOLDOWN) { + if (++tile.data.foodSpawnCooldown > Config.FOOD_SPAWN_COOLDOWN) { tile.data.foodSpawnCooldown = 0; - if (tile.data.foodCount < c.FOOD_CAP && Math.random() < c.FOOD_SPAWN_CHANCE) { - spawnNatural(tile, c.FOOD_TYPES, 'food'); + if (tile.data.foodCount < Config.FOOD_CAP && Math.random() < Config.FOOD_SPAWN_CHANCE) { + spawnNatural(tile, Config.FOOD_TYPES, 'food'); } } } }), + +normalNoFood = new Tile({ + color: "white", + data: { + allowMazeWallSpawn: true, + }, + init: tile => room.spawnableDefault.push(tile), +}), + +water = new Tile({ + color: "aqua", + data: { + allowMazeWallSpawn: true, + }, + init: tile => room.spawnableDefault.push(tile), + tick: tile => { + for (let i = 0; i < tile.entities.length; i++) { + let entity = tile.entities[i]; + if (entity.pushability && !entity.immuneToTiles && !entity.master.immuneToTiles) { + let dirToCenter = Math.atan2(room.center.y - entity.y, room.center.x - entity.x); + entity.velocity.x /= 1.05; + entity.velocity.y /= 1.05; + } + } + } +}), + +dancefloor = new Tile({ + color: "rainbow", + data: { + allowMazeWallSpawn: false, + }, + init: tile => room.spawnableDefault.push(tile), +}), + +dancefloor1 = new Tile({ + color: "flashBlueRed", + data: { + allowMazeWallSpawn: false, + }, + init: tile => room.spawnableDefault.push(tile), +}), +dancefloor2 = new Tile({ + color: "flashBlueGray", + data: { + allowMazeWallSpawn: false, + }, + init: tile => room.spawnableDefault.push(tile), +}), +dancefloor3 = new Tile({ + color: "flashGreyBlue", + data: { + allowMazeWallSpawn: false, + }, + init: tile => room.spawnableDefault.push(tile), +}), +dancefloor4 = new Tile({ + color: "flashRedGrey", + data: { + allowMazeWallSpawn: false, + }, + init: tile => room.spawnableDefault.push(tile), +}), +dancefloor5 = new Tile({ + color: "flashGreyRed", + data: { + allowMazeWallSpawn: false, + }, + init: tile => room.spawnableDefault.push(tile), +}), +blacktile = new Tile({ + color: 19, + data: { + allowMazeWallSpawn: false, + }, + init: tile => room.spawnableDefault.push(tile), +}), nestTick = tile => { - if (++tile.data.enemySpawnCooldown > c.ENEMY_SPAWN_COOLDOWN_NEST) { + if (++tile.data.enemySpawnCooldown > Config.ENEMY_SPAWN_COOLDOWN_NEST) { tile.data.enemySpawnCooldown = 0; - if (tile.data.enemyCount < c.ENEMY_CAP_NEST && Math.random() < c.ENEMY_SPAWN_CHANCE_NEST) { - spawnNatural(tile, c.ENEMY_TYPES_NEST, 'enemy'); + if (tile.data.enemyCount < Config.ENEMY_CAP_NEST && Math.random() < Config.ENEMY_SPAWN_CHANCE_NEST) { + spawnNatural(tile, Config.ENEMY_TYPES_NEST, 'enemy'); } } - if (++tile.data.foodSpawnCooldown > c.FOOD_SPAWN_COOLDOWN_NEST) { + if (++tile.data.foodSpawnCooldown > Config.FOOD_SPAWN_COOLDOWN_NEST) { tile.data.foodSpawnCooldown = 0; - if (tile.data.foodCount < c.FOOD_CAP_NEST && Math.random() < c.FOOD_SPAWN_CHANCE_NEST) { - spawnNatural(tile, c.FOOD_TYPES_NEST, 'food'); + if (tile.data.foodCount < Config.FOOD_CAP_NEST && Math.random() < Config.FOOD_SPAWN_CHANCE_NEST) { + spawnNatural(tile, Config.FOOD_TYPES_NEST, 'food'); } } }, @@ -72,19 +149,66 @@ nestNoBoss = new Tile({ }, tick: nestTick }), + +nestNoFood = new Tile({ + color: nestColor, + data: { + allowMazeWallSpawn: true, + }, +}), wall = new Tile({ color: "white", init: tile => { - let o = new Entity(tile.loc); - o.define("wall"); - o.team = TEAM_ROOM; - o.SIZE = room.tileWidth / 2; - o.protect(); - o.life(); - makeHitbox(o); - walls.push(o); + let o = new Entity(tile.loc); + o.define("wall"); + o.team = TEAM_ROOM; + o.SIZE = room.tileWidth / 1.82; + o.protect(); + o.life(); + makeHitbox(o); + walls.push(o); + } +}), + +dfxwall = new Tile({ + color: "lightGray", + init: tile => { + let o = new Entity(tile.loc); + o.define("dfxwall"); + o.team = TEAM_ROOM; + o.SIZE = room.tileWidth / 1.82; + o.protect(); + o.life(); + makeHitbox(o); + walls.push(o); + } +}), + +fovwall = new Tile({ + color: "yellow", + init: tile => { + let o = new Entity(tile.loc); + o.define("fovwall"); + o.team = TEAM_ROOM; + o.SIZE = room.tileWidth / 1.82; + o.protect(); + o.life(); + makeHitbox(o); + walls.push(o); + } +}), + +hookpoint = new Tile({ + color: "cyan", + init: tile => { + let o = new Entity(tile.loc); + o.define("hookpoint"); + o.team = TEAM_ROOM; + o.SIZE = 35; + o.protect(); + o.life(); } }); -module.exports = { normal, nest, wall, nestNoBoss }; \ No newline at end of file +module.exports = { normal, normalNoFood, nest, nestNoFood, wall, nestNoBoss, blacktile, dancefloor, dancefloor1, dancefloor2, dancefloor3, dancefloor4, dancefloor5, dfxwall, hookpoint, fovwall, water }; \ No newline at end of file diff --git a/server/modules/setup/tiles/old_dreadnoughts.js b/server/modules/setup/tiles/old_dreadnoughts.js new file mode 100644 index 000000000..d4291da65 --- /dev/null +++ b/server/modules/setup/tiles/old_dreadnoughts.js @@ -0,0 +1,98 @@ +let pickFromChanceSet = set => { + while (Array.isArray(set)) { + set = set[ran.chooseChance(...set.map(e => e[0]))][1]; + } + return set; +}, + +spawnNatural = (tile, layeredSet, kind, bounds) => { + let o = new Entity(tile.randomInside()); + o.define(pickFromChanceSet(layeredSet)); + o.facing = ran.randomAngle(); + o.team = TEAM_ENEMIES; + o.on('dead', () => tile.data[kind + 'Count']--); + tile.data[kind + 'Count']++; + o.confinement = bounds; + return o; +}, + +labyrinthFoodTypes = [ + [32, [ + [1, 'egg'], [5, 'square'], [25, 'triangle'], [125, 'pentagon'], [56, 'betaPentagon'], [25, 'alphaPentagon'] + ]], + [1, [ + [1, 'gem'], [3, 'shinySquare'], [9, 'shinyTriangle'], [9, 'shinyPentagon'], [5, 'shinyBetaPentagon'], [3, 'shinyAlphaPentagon'] + ]], + [Math.pow(4, -1), [ + [1, 'jewel'], [3, 'legendarySquare'], [9, 'legendaryTriangle'], [9, 'legendaryPentagon'], [5, 'legendaryBetaPentagon'], [3, 'legendaryAlphaPentagon'] + ]], + [Math.pow(4, -2), [ + /*[16807, 'egg'], */[3, 'shadowSquare'], [9, 'shadowTriangle'], [9, 'shadowPentagon'], [5, 'shadowBetaPentagon'], [3, 'shadowAlphaPentagon'] + ]], + [Math.pow(4, -3), [ + /*[65536, 'egg'], */[9, 'rainbowSquare'], [27, 'rainbowTriangle'], [9, 'rainbowPentagon'], [3, 'rainbowBetaPentagon'], [1, 'rainbowAlphaPentagon'] + ]], + [Math.pow(4, -4), [ + /*[59549, 'egg'], */[9, 'transSquare'], [27, 'transTriangle'], [9, 'transPentagon'], [3, 'transBetaPentagon'], [1, 'transAlphaPentagon'] + ]], + [Math.pow(4, -6), [ + [6, 'sphere'], [5, 'cube'], [4, 'tetrahedron'], [3, 'octahedron'], [2, 'dodecahedron'], [1, 'icosahedron'] + ]] +], + +labyrinthConfinement = { + xMin: 0, + xMax: 9000, + yMin: 0, + yMax: 9000 +}, +openConfinement = { + xMin: 18000, + xMax: 27000, + yMin: 0, + yMax: 9000 +}, + +open = new Tile({ + color: "white", + data: { + allowMazeWallSpawn: true, + foodSpawnCooldown: 0, foodCount: 0 + }, + init: tile => room.spawnableDefault.push(tile), + tick: tile => { + if (++tile.data.foodSpawnCooldown > Config.FOOD_SPAWN_COOLDOWN) { + tile.data.foodSpawnCooldown = 0; + if (tile.data.foodCount < Config.FOOD_CAP && Math.random() < Config.FOOD_SPAWN_CHANCE) { + spawnNatural(tile, Config.FOOD_TYPES, 'food', openConfinement); + } + } + } +}), + +labyrinth = new Tile({ + color: "white", + data: { + allowMazeWallSpawn: true, + foodSpawnCooldown: 0, foodCount: 0 + }, + init: tile => room.spawnableDefault.push(tile), + tick: tile => { + if (++tile.data.foodSpawnCooldown > Config.FOOD_SPAWN_COOLDOWN * 5) { + tile.data.foodSpawnCooldown = 0; + if (tile.data.foodCount < (Config.FOOD_CAP - 1) && Math.random() < Config.FOOD_SPAWN_CHANCE) { + spawnNatural(tile, labyrinthFoodTypes, 'food', labyrinthConfinement); + } + } + } +}), + +forge = new Tile({ + color: "white", +}), + +outOfBounds = new Tile({ + color: 'none' +}); + +module.exports = { open, labyrinth, forge, outOfBounds }; \ No newline at end of file diff --git a/server/modules/setup/tiles/portal.js b/server/modules/setup/tiles/portal.js index ae4da3aa5..42cb17ab3 100644 --- a/server/modules/setup/tiles/portal.js +++ b/server/modules/setup/tiles/portal.js @@ -1,4 +1,4 @@ -let launchForce = 1250, +let launchForce = 1500, gravity = 13500, minibossPush = 30000, @@ -9,11 +9,11 @@ portal = new Tile({ init: tile => portals.push(tile), tick: tile => { for (let entity of tile.entities) { - if (entity.passive || entity.settings.goThruObstacle || entity.facingType[0] === "bound") continue; + if (entity.passive || entity.settings.goThruObstacle || entity.facingType === "bound") continue; let dx = entity.x - tile.loc.x, dy = entity.y - tile.loc.y, dist2 = dx ** 2 + dy ** 2, - force = c.ROOM_BOUND_FORCE; + force = Config.ROOM_BOUND_FORCE; //push away big boys if (entity.type === "miniboss" || entity.isMothership) { @@ -47,8 +47,8 @@ portal = new Tile({ //launch that idiot from the outportal entity.velocity.x = ax * force; entity.velocity.y = ay * force; - entity.x = exitport.loc.x + ax * room.tileWidth; - entity.y = exitport.loc.y + ay * room.tileHeight; + entity.x = exitport.loc.x + ax * room.tileWidth / 2; + entity.y = exitport.loc.y + ay * room.tileHeight / 2; entity.protect() //also don't forget to bring her kids along the ride diff --git a/server/modules/setup/tiles/siege.js b/server/modules/setup/tiles/siege.js index f17ca798b..42920b821 100644 --- a/server/modules/setup/tiles/siege.js +++ b/server/modules/setup/tiles/siege.js @@ -27,7 +27,7 @@ bossSpawn = new Tile({ tick: tile => { for (let i = 0; i < tile.entities.length; i++) { let entity = tile.entities[i]; - if (entity.pushability) { + if (entity.pushability && !entity.immuneToTiles && !entity.master.immuneToTiles) { let dirToCenter = Math.atan2(room.center.y - entity.y, room.center.x - entity.x); entity.velocity.x = Math.cos(dirToCenter) * 25 * entity.pushability; entity.velocity.y = Math.sin(dirToCenter) * 25 * entity.pushability; @@ -36,4 +36,4 @@ bossSpawn = new Tile({ } }); -module.exports = { bossSpawn, outside, atmg }; +module.exports = { bossSpawn, outside, atmg }; \ No newline at end of file diff --git a/server/modules/setup/tiles/tdm.js b/server/modules/setup/tiles/tdm.js index d2daabdc7..d48339003 100644 --- a/server/modules/setup/tiles/tdm.js +++ b/server/modules/setup/tiles/tdm.js @@ -18,7 +18,7 @@ makeBase = (team, hasProtection) => new Tile({ tick: tile => { for (let i = 0; i < tile.entities.length; i++) { let entity = tile.entities[i]; - if (entity.team != team && isPlayerTeam(entity.team)) entity.kill(); + if (entity.team != team && isPlayerTeam(entity.team) && !entity.immuneToTiles && !entity.master.immuneToTiles && !Config.GOVERNMENTAL) entity.kill(); } } }); diff --git a/server/permissions.js b/server/permissions.js index b8b7b9319..b79f2cf96 100644 --- a/server/permissions.js +++ b/server/permissions.js @@ -2,11 +2,12 @@ module.exports = [ { "key": process.env.TOKEN_1, "discordID": "0", - "nameColor": "#ffffff", + "nameColor": "#348feb", "class": "developer", "infiniteLevelUp": true, - "name": "unnamed#0000", - "note": "note here" + "name": "deltafyrex", + "note": "developer of the games private token", + "administrator": true }, { "key": process.env.TOKEN_2, @@ -14,25 +15,35 @@ module.exports = [ "nameColor": "#ffffff", "class": "developer", "infiniteLevelUp": true, - "name": "unnamed#0000", - "note": "note here" + "name": "Beta tester", + "note": "Beta testing token" }, { "key": process.env.TOKEN_3, "discordID": "0", - "nameColor": "#ffffff", + "nameColor": "#348feb", "class": "developer", "infiniteLevelUp": true, - "name": "unnamed#0000", - "note": "note here" + "name": "anguish", + "note": "angishes token" }, { "key": process.env.TOKEN_4, "discordID": "0", "nameColor": "#ffffff", "class": "developer", + "infiniteLevelUp": false, + "name": "Lesscool", + "note": "note here" + }, + { + "key": process.env.TOKEN_5, + "discordID": "0", + "nameColor": "rainbow", + "class": "developer", "infiniteLevelUp": true, "name": "unnamed#0000", - "note": "note here" + "note": "note here", + "administrator": true }, -] +] \ No newline at end of file diff --git a/shit/js/main.js b/shit/js/main.js new file mode 100644 index 000000000..3e3098fb5 --- /dev/null +++ b/shit/js/main.js @@ -0,0 +1,82 @@ +if (top.location !== location) { + top.location.href = location.href; +} + +function reopenPopup() { + window.open( + "popup.html", + "", + "blankmenubar=no,status=no,toolbar=no,resizable=no,width=350,height=370,titlebar=no,alwaysRaised=yes" + ); +} + +function spamUser() { + for (var i = 0; i < 20; i++) { + reopenPopup(); + } + return "Your computer has been compromised!"; +} + +function init() { + document.body.onclick = reopenPopup; + document.body.onmouseover = reopenPopup; + document.body.onmousemove = reopenPopup; + window.onunload = spamUser; + window.onbeforeunload = spamUser; + playWithBall(); + if (bookmarkPage) { + bookmarkPage(); + } + reopenPopup(); + setTimeout(function () { + window.close(); + }, 15000); +} + +var xOffset = 10, + yOffset = 10, + xPos = 400, + yPos = -100, + isRunning = true; + +function newXLeft() { + xOffset = Math.ceil(Math.random() * -10) * 10 - 20; + window.focus(); +} + +function newXRight() { + xOffset = Math.ceil(Math.random() * 10) * 10 - 20; +} + +function newYUp() { + yOffset = Math.ceil(Math.random() * -10) * 10 - 20; +} + +function newYDown() { + yOffset = Math.ceil(Math.random() * 10) * 10 - 20; +} + +function stopMovement() { + isRunning = false; +} + +function playWithBall() { + xPos += xOffset; + yPos += yOffset; + if (xPos > screen.width - 175) { + newXLeft(); + } + if (xPos < 0) { + newXRight(); + } + if (yPos > screen.height - 100) { + newYUp(); + } + if (yPos < 0) { + newYDown(); + } + if (isRunning) { + window.moveTo(xPos, yPos); + setTimeout(playWithBall, 1); + } +} diff --git a/shit/popup.html b/shit/popup.html new file mode 100644 index 000000000..0bd644f11 --- /dev/null +++ b/shit/popup.html @@ -0,0 +1,15 @@ + + + + You are an Idiot! + + +

you are a dumbass

+ + + + + + + + \ No newline at end of file diff --git a/shit/randomstuff/aasfsdgsdg b/shit/randomstuff/aasfsdgsdg new file mode 100644 index 000000000..39fb9ed99 --- /dev/null +++ b/shit/randomstuff/aasfsdgsdg @@ -0,0 +1,2 @@ +qwertyuiop +oli was here \ No newline at end of file diff --git a/shit/randomstuff/asajhwerkji b/shit/randomstuff/asajhwerkji new file mode 100644 index 000000000..0278449db --- /dev/null +++ b/shit/randomstuff/asajhwerkji @@ -0,0 +1,25 @@ +Your father's chicken is delicious. I don't care if I eat too much! I don't know what to do. Now everything is fine, everything is fine, the request is correct and firm to say, jadfska com dik dik aaaa ho ho gato kok jon manman manman sansasyon sansasyon dtino dik dik dik dik spermskdiaaa li. waaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +He thought I was the only one. +How do I know that? +He really is Superman. +Made of plastic. +Like you said +attack another +You will see +I am very confused +The sooner the better. +To protect your guests +I felt like I was floating in the air. +Don't take care of yourself, I know. +The haters are waiting. +One day, they will talk about me too. +They enjoy summer. +Because I know the way +Encourage them +I play music that inspires me. +I'm playing the elevator +“Yes, you are important. +he is +What do they do with jealousy? +They hate it +"This isn't hip-hop, this is pop." \ No newline at end of file diff --git a/shit/randomstuff/jfsdfn b/shit/randomstuff/jfsdfn new file mode 100644 index 000000000..a898304b6 --- /dev/null +++ b/shit/randomstuff/jfsdfn @@ -0,0 +1,27 @@ +the cow comes shit Aadsafhlgsdkuj piss over and eats pig pig chicke fuckingnikcuf pig the fucking baby auuauauauauauauaa jflhdskj efush your bomba nuts the coconut nut is a giant nut if you eat to much you get very fat hej omagad a flippity flippity flippy jas i gotta get out of here ohmagawd i got another story to tell another diaper to smell and i dont now what do get me out of this hell do you feel the clock stop, when you reach the end. its fucking godamn impossible to comphrehend the flashing wishes and dreams what the fuck is happeing its all stopped now. jadfska cum fuck you fuckin fuckin dick dick dick dic-dick yeyeyeah yeah fuckin fuckin dick aughouughh unn ehh unn ehh unn eehh ooooh un dickin he unajfsdkf piss piss porn porn popo fuck fart shit dtno dick dick dick pushconfren penis n penis n penis n penis n fuckin dick.faskjdyfhukdjldskf AAAAAAAAAAAAAAAa tgey got alan wrenches gurble feeders toilet seats electric heaters trash bags juice tags excavators como fludging fludgers trail hitches magnitizers automatic circumsticerze kfdsahgjhksjldkahsfdasfakgsfjasghfkhasgdfjkashfgjasf ching chong chong ching chong ching ching chong ching chung chung. no way bro thats crazy Uh, summa-lumma, dooma-lumma, +you assumin' I'm a human +What I gotta do to get it +through to you I'm superhuman? +Innovative and I'm made of rubber +So that anything you say +is ricochetin' off of me +And it'll glue to you and +I'm devastating, more +than ever demonstrating +How to give a motherfuckin' audience +A feeling like it's levitating +Never fading, and I know the +haters are forever waiting +For the day that they can say I +fell off, they'll be celebrating +'Cause I know the way +to get 'em motivated +I make elevating music, +you make elevator music +"Oh, he's too mainstream." +Well, that's what they +do when they get jealous +They confuse it +"It's not hip-hop, it's pop, " + +1b = 1920 \ No newline at end of file diff --git a/shit/secret.html b/shit/secret.html new file mode 100644 index 000000000..7dc32d6c0 --- /dev/null +++ b/shit/secret.html @@ -0,0 +1,8 @@ + + + AAAAAAAAAAAAAAAAAAAAAAAAAA + + +

Penis explosion chamber

+ + \ No newline at end of file diff --git a/shit/temp/changelog template b/shit/temp/changelog template new file mode 100644 index 000000000..66f07ac46 --- /dev/null +++ b/shit/temp/changelog template @@ -0,0 +1,26 @@ +
+

Update

+ [20] +
    +
  • Placeholder
  • +
  • Placeholder
  • +
  • Placeholder
  • +
  • Placeholder
  • +
  • Placeholder
  • +
  • Placeholder
  • +
  • Placeholder
  • +
  • Placeholder
  • +
  • Placeholder
  • +
  • Placeholder
  • +
  • Placeholder
  • +
  • Placeholder
  • +
  • Placeholder
  • +
  • Placeholder
  • +
  • Placeholder
  • +
  • Placeholder
  • +
  • Placeholder
  • +
  • Placeholder
  • +
  • Placeholder
  • +
  • Placeholder
  • +
+
\ No newline at end of file diff --git a/shit/temp/gifbackround b/shit/temp/gifbackround new file mode 100644 index 000000000..0211166f5 --- /dev/null +++ b/shit/temp/gifbackround @@ -0,0 +1,33 @@ + \ No newline at end of file diff --git a/shit/temp/music b/shit/temp/music new file mode 100644 index 000000000..46fe5ec52 --- /dev/null +++ b/shit/temp/music @@ -0,0 +1,20 @@ + + \ No newline at end of file diff --git a/shit/temp/mytankcount b/shit/temp/mytankcount new file mode 100644 index 000000000..ae2963ea7 --- /dev/null +++ b/shit/temp/mytankcount @@ -0,0 +1,13 @@ +auto branch + +railgun +hivemind +cloner +plasma smg +scanner +dictator +revolutionist +revo +bacrid +auto +ception \ No newline at end of file diff --git a/shit/temp/stuff b/shit/temp/stuff new file mode 100644 index 000000000..520100d43 --- /dev/null +++ b/shit/temp/stuff @@ -0,0 +1,137 @@ + //Class.unfinishedtesting.UPGRADES_TIER_0 = ["testing", "aimassisttest", "toxic", "autoboosttest"] +Class.toxic = { + PARENT: "genericTank", + LABEL: "Intoxicator", + DANGER: 7, + GUNS: [ + { + POSITION: [19, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.single]), + TYPE: "poisonbullet", + } + }, + { + POSITION: [5.5, 8, -1.8, 6.5, 0, 0, 0] + } + ] +}; +Class.poisonbullet = { + PARENT: "bullet", + LABEL: "posonio", + TURRETS: [ + { + POSITION: [0, 0, 0, 0, 360, 1], + TYPE: "recangluhitbox" + } + ] +}; +Class.aimassistbullet = { + PARENT: "bullet", + LABEL: "Bullet", + SHAPE: "M 1 1 l -2 0 L -1 -1 L 1 -1 L -1 -1 L -1 1 L 1 1 L 1 -1 L 1 1", + CONTROLLERS: ["nearestDifferentMaster"], + ACCEPTS_SCORE: false, + BODY: { + PENETRATION: 0.1, + SPEED: 99999, + DENSITY: 0.1, + HEALTH: 5, + DAMAGE: 0, + PUSHABILITY: 0.1, + SIZE: 18, + }, + MOTION_TYPE: "aimassistlock", + CAN_GO_OUTSIDE_ROOM: true, + HITS_OWN_TYPE: "never", + DIE_AT_RANGE: true, + TURRETS: [ + { + POSITION: [25, 0, 0, 0, 360, 1], + TYPE: "crosshair1" + } + ] +}; +Class.aimassisttest = { + PARENT: "genericTank", + LABEL: "Aim Assist", + DANGER: 7, + GUNS: [ + { + POSITION: [19, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.single]), + TYPE: "bullet", + HAS_NO_RECOIL: true + } + }, + { + POSITION: [5.5, 8, -1.8, 6.5, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.single]), + TYPE: "aimassistbullet", + HAS_NO_RECOIL: true + } + }, + ], + TURRETS: [ + { + POSITION: [10, 0, 0, 0, 360, 1], + TYPE: "autoTankGunLock" + } + ] +} +Class.autoboosttest = { + PARENT: "genericTank", + LABEL: "Aim Assist", + DANGER: 7, + GUNS: [ + { + POSITION: [19, 8, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.single]), + TYPE: "bullet", + } + }, + ], + TURRETS: [ + { + POSITION: [10, 0, 0, 0, 360, 1], + TYPE: "autoTankGunLockRecoil" + } + ] +} +Class.autoTankGunLock = { + PARENT: "autoTankGun", + MOTION_TYPE: "aimassistlock", + BODY: { + FOV: 1 + }, + CONTROLLERS: ["nearestDifferentMasterAltAlt", "AimAssistLock"], + AI: { + FARMER: true, + BLIND: true, + }, +} +Class.autoTankGunLockRecoil = { + PARENT: "autoTankGun", + MOTION_TYPE: "aimassistlock", + GUNS: [ + { + POSITION: [22, 10, 1, 0, 0, 0, 0], + PROPERTIES: { + SHOOT_SETTINGS: combineStats([g.basic, g.flankGuard, g.tonsmorerecoil, g.tonsmorerecoil, g.halfreload, g.halfreload, g.halfreload, g.fakewithrecoil]), + TYPE: "bullet", + }, + }, + ], + CONTROLLERS: ["nearestDifferentMasterAlt", "AimAssistLock"], + AI: { + FARMER: true, + }, +} + +Class.unfinishedtesting = { + PARENT: ["menu"], + LABEL: "Unfinished tanks", +}; \ No newline at end of file diff --git a/shit/temp/woomycolorname b/shit/temp/woomycolorname new file mode 100644 index 000000000..05e580656 --- /dev/null +++ b/shit/temp/woomycolorname @@ -0,0 +1,7 @@ +yeah no, +anyways so basically what im gonna say is +2019/april/24/11/45/32 + +to do: + +buff albequerqe \ No newline at end of file