/* Shoot your projectile at the other tank before they get you! @title: Tanks @author: Om Raheja @tags: ["two-player", "fighting", "pvp"] @addedOn: 2024-06-30 In the color picker: AD to move player one cursor. JL to move player two cursor. W and I to set READY state for players. In the actual game: WASD for player one to move, IJKL for player two to move. The game moves the players automatically every 500 ms. Each keypress shoots a projectile and changes direction. Shoot the other tank to win! */ const player = "a"; const player2 = "b"; const wall = "w"; const projectile = "p"; // direction of the tanks var direction1 = ">"; var direction2 = "<"; const colorTanks = [{ "^": bitmap` ......0000...... ......0000...... .......00....... .......00....... ...0033003300... ..C0330000330C.. ..C3303333033C.. ..C3030303303C.. ..C3033030303C.. ..C3033333303C.. ..C3303333033C.. ..C3330000333C.. ..C0333333330C.. ..C0033333300C.. ..C0000000000C.. ..C..........C..`, ".": bitmap` ................ ................ ...0033333300... ..C0333333330C.. ..C3330000333C.. ..C3303333033C.. ..C3030303303C.. ..C3033030303C.. ..C3033333303C.. ..C3303333033C.. ..C0330000330C.. ..C0033003300C.. ..C0000000000C.. ..C....00....C.. ......0000...... ......0000......`, "<": bitmap` ................ ................ ................ ......0000000... 00...033333330.. 000000330330030. 00..03333333330. .....0000000000. .....00494949330 ....000000000000 ...0F03CF03CF300 ..0F3F0F3F0F3F0. ...0FC30FC30F0.. ....000000000... ................ ................`, ">": bitmap` ................ ................ ................ ...0000000...... ..033333330...00 .030033033000000 .03333333330..00 .0000000000..... 03394949400..... 000000000000.... 003FC30FC30F0... .0F3F0F3F0F3F0.. ..0F03CF03CF0... ...000000000.... ................ ................` }, { "^": bitmap` ......0000...... ......0000...... .......00....... .......00....... ...0099009900... ..C0990000990C.. ..C9909999099C.. ..C9090909909C.. ..C9099090909C.. ..C9099999909C.. ..C9909999099C.. ..C9990000999C.. ..C0999999990C.. ..C0099999900C.. ..C0000000000C.. ..C..........C..`, ".": bitmap` ................ ................ ...0099999900... ..C0999999990C.. ..C9990000999C.. ..C9909999099C.. ..C9090909909C.. ..C9099090909C.. ..C9099999909C.. ..C9909999099C.. ..C0990000990C.. ..C0099009900C.. ..C0000000000C.. ..C....00....C.. ......0000...... ......0000......`, "<": bitmap` ................ ................ ................ ......0000000... 00...099999990.. 000000990990090. 00..09999999990. .....0000000000. .....00434343990 ....000000000000 ...0F09CF09CF900 ..0F9F0F9F0F9F0. ...0FC90FC90F0.. ....000000000... ................ ................`, ">": bitmap` ................ ................ ................ ...0000000...... ..099999990...00 .090099099000000 .09999999990..00 .0000000000..... 09934343400..... 000000000000.... 009FC90FC90F0... .0F9F0F9F0F9F0.. ..0F09CF09CF0... ...000000000.... ................ ................` }, { "^": bitmap` ......0000...... ......0000...... .......00....... .......00....... ...0066006600... ..C0660000660C.. ..C6606666066C.. ..C6060606606C.. ..C6066060606C.. ..C6066666606C.. ..C6606666066C.. ..C6660000666C.. ..C0666666660C.. ..C0066666600C.. ..C0000000000C.. ..C..........C..`, ".": bitmap` ................ ................ ...0066666600... ..C0666666660C.. ..C6660000666C.. ..C6606666066C.. ..C6060606606C.. ..C6066060606C.. ..C6066666606C.. ..C6606666066C.. ..C0660000660C.. ..C0066006600C.. ..C0000000000C.. ..C....00....C.. ......0000...... ......0000......`, "<": bitmap` ................ ................ ................ ......0000000... 00...066666660.. 000000660660060. 00..06666666660. .....0000000000. .....00434343660 ....000000000000 ...0F06CF06CF600 ..0F6F0F6F0F6F0. ...0FC60FC60F0.. ....000000000... ................ ................`, ">": bitmap` ................ ................ ................ ...0000000...... ..066666660...00 .060066066000000 .06666666660..00 .0000000000..... 06634343400..... 000000000000.... 006FC60FC60F0... .0F6F0F6F0F6F0.. ..0F06CF06CF0... ...000000000.... ................ ................` }, { "^": bitmap` ......0000...... ......0000...... .......00....... .......00....... ...00DD00DD00... ..C0DD0000DD0C.. ..CDD0DDDD0DDC.. ..CD0D0D0DD0DC.. ..CD0DD0D0D0DC.. ..CD0DDDDDD0DC.. ..CDD0DDDD0DDC.. ..CDDD0000DDDC.. ..C0DDDDDDDD0C.. ..C00DDDDDD00C.. ..C0000000000C.. ..C..........C..`, ".": bitmap` ................ ................ ...00DDDDDD00... ..C0DDDDDDDD0C.. ..CDDD0000DDDC.. ..CDD0DDDD0DDC.. ..CD0D0D0DD0DC.. ..CD0DD0D0D0DC.. ..CD0DDDDDD0DC.. ..CDD0DDDD0DDC.. ..C0DD0000DD0C.. ..C00DD00DD00C.. ..C0000000000C.. ..C....00....C.. ......0000...... ......0000......`, "<": bitmap` ................ ................ ................ ......0000000... 00...0DDDDDDD0.. 000000DD0DD00D0. 00..0DDDDDDDDD0. .....0000000000. .....00434343DD0 ....000000000000 ...0F0DCF0DCFD00 ..0FDF0FDF0FDF0. ...0FCD0FCD0F0.. ....000000000... ................ ................`, ">": bitmap` ................ ................ ................ ...0000000...... ..0DDDDDDD0...00 .0D00DD0DD000000 .0DDDDDDDDD0..00 .0000000000..... 0DD34343400..... 000000000000.... 00DFCD0FCD0F0... .0FDF0FDF0FDF0.. ..0F0DCF0DCF0... ...000000000.... ................ ................` }, { "^": bitmap` ......0000...... ......0000...... .......00....... .......00....... ...0077007700... ..C0770000770C.. ..C7707777077C.. ..C7070707707C.. ..C7077070707C.. ..C7077777707C.. ..C7707777077C.. ..C7770000777C.. ..C0777777770C.. ..C0077777700C.. ..C0000000000C.. ..C..........C..`, ".": bitmap` ................ ................ ...0077777700... ..C0777777770C.. ..C7770000777C.. ..C7707777077C.. ..C7070707707C.. ..C7077070707C.. ..C7077777707C.. ..C7707777077C.. ..C0770000770C.. ..C0077007700C.. ..C0000000000C.. ..C....00....C.. ......0000...... ......0000......`, "<": bitmap` ................ ................ ................ ......0000000... 00...077777770.. 000000770770070. 00..07777777770. .....0000000000. .....00434343770 ....000000000000 ...0F07CF07CF700 ..0F7F0F7F0F7F0. ...0FC70FC70F0.. ....000000000... ................ ................`, ">": bitmap` ................ ................ ................ ...0000000...... ..077777770...00 .070077077000000 .07777777770..00 .0000000000..... 07734343400..... 000000000000.... 007FC70FC70F0... .0F7F0F7F0F7F0.. ..0F07CF07CF0... ...000000000.... ................ ................` }, { "^": bitmap` ......0000...... ......0000...... .......00....... .......00....... ...00HH00HH00... ..C0HH0000HH0C.. ..CHH0HHHH0HHC.. ..CH0H0H0HH0HC.. ..CH0HH0H0H0HC.. ..CH0HHHHHH0HC.. ..CHH0HHHH0HHC.. ..CHHH0000HHHC.. ..C0HHHHHHHH0C.. ..C00HHHHHH00C.. ..C0000000000C.. ..C..........C..`, ".": bitmap` ................ ................ ...00HHHHHH00... ..C0HHHHHHHH0C.. ..CHHH0000HHHC.. ..CHH0HHHH0HHC.. ..CH0H0H0HH0HC.. ..CH0HH0H0H0HC.. ..CH0HHHHHH0HC.. ..CHH0HHHH0HHC.. ..C0HH0000HH0C.. ..C00HH00HH00C.. ..C0000000000C.. ..C....00....C.. ......0000...... ......0000......`, "<": bitmap` ................ ................ ................ ......0000000... 00...0HHHHHHH0.. 000000HH0HH00H0. 00..0HHHHHHHHH0. .....0000000000. .....00434343HH0 ....000000000000 ...0F0HCF0HCFH00 ..0FHF0FHF0FHF0. ...0FCH0FCH0F0.. ....000000000... ................ ................`, ">": bitmap` ................ ................ ................ ...0000000...... ..0HHHHHHH0...00 .0H00HH0HH000000 .0HHHHHHHHH0..00 .0000000000..... 0HH34343400..... 000000000000.... 00HFCH0FCH0F0... .0FHF0FHF0FHF0.. ..0F0HCF0HCF0... ...000000000.... ................ ................` }, { "^": bitmap` ......0000...... ......0000...... .......00....... .......00....... ...0088008800... ..C0880000880C.. ..C8808888088C.. ..C8080808808C.. ..C8088080808C.. ..C8088888808C.. ..C8808888088C.. ..C8880000888C.. ..C0888888880C.. ..C0088888800C.. ..C0000000000C.. ..C..........C..`, ".": bitmap` ................ ................ ...0088888800... ..C0888888880C.. ..C8880000888C.. ..C8808888088C.. ..C8080808808C.. ..C8088080808C.. ..C8088888808C.. ..C8808888088C.. ..C0880000880C.. ..C0088008800C.. ..C0000000000C.. ..C....00....C.. ......0000...... ......0000......`, "<": bitmap` ................ ................ ................ ......0000000... 00...088888880.. 000000880880080. 00..08888888880. .....0000000000. .....00434343880 ....000000000000 ...0F08CF08CF800 ..0F8F0F8F0F8F0. ...0FC80FC80F0.. ....000000000... ................ ................`, ">": bitmap` ................ ................ ................ ...0000000...... ..088888880...00 .080088088000000 .08888888880..00 .0000000000..... 08834343400..... 000000000000.... 008FC80FC80F0... .0F8F0F8F0F8F0.. ..0F08CF08CF0... ...000000000.... ................ ................` }, ]; /* since the sprites for colored tanks are 0,1,2... respectively */ const colorCode = [ color`3`, color`9`, color`6`, color`D`, color`7`, color`H`, color`8` ]; const colorString = [ "RED", "ORANGE", "YELLOW", "GREEN", "BLUE", "PURPLE", "PINK" ]; const wallBitmap = bitmap` 10LLLLLLLLLLLL01 010LLLLLLLLLL010 L010LLLLLLLL010L LL010LLLLLL010LL LLL010LLLL010LLL LLLL01022010LLLL LLLLL010010LLLLL LLLLL201102LLLLL LLLLL201102LLLLL LLLLL010010LLLLL LLLL01022010LLLL LLL010LLLL010LLL LL010LLLLLL010LL L010LLLLLLLL010L 010LLLLLLLLLL010 10LLLLLLLLLLLL01`; const projectileBitmap = bitmap` ................ ................ ................ ................ ................ ................ ......LLLL...... ......LL0L...... ......L0LL...... ......LLLL...... ................ ................ ................ ................ ................ ................`; var musicPlaying = null; // scores var score1 = 0; var score2 = 0; // sprite type var player1Type = 3; var player2Type = 3; // color ready var player1Ready = false; var player2Ready = false; // time of last win var lastWin = 0; registerSprites(); setSolids([player, player2, wall, projectile]); const Maps = { End: 0, ColorPicker: 1, FirstLevel: 2 }; const Music = { End: tune` 283.0188679245283: B4~283.0188679245283, 283.0188679245283: C5~283.0188679245283, 283.0188679245283: D5~283.0188679245283, 283.0188679245283: D5~283.0188679245283, 283.0188679245283: C5~283.0188679245283, 283.0188679245283: B4~283.0188679245283, 283.0188679245283: A4~283.0188679245283, 283.0188679245283: G4~283.0188679245283 + E4-283.0188679245283, 283.0188679245283: G4~283.0188679245283 + E4-283.0188679245283, 283.0188679245283: A4~283.0188679245283, 283.0188679245283: B4~283.0188679245283, 283.0188679245283: B4~283.0188679245283, 283.0188679245283: A4~283.0188679245283 + E4-283.0188679245283, 283.0188679245283: A4~283.0188679245283 + E4-283.0188679245283, 283.0188679245283: B4~283.0188679245283, 283.0188679245283: C5~283.0188679245283, 283.0188679245283: D5~283.0188679245283, 283.0188679245283: D5~283.0188679245283, 283.0188679245283: C5~283.0188679245283, 283.0188679245283: B4~283.0188679245283, 283.0188679245283: A4~283.0188679245283, 283.0188679245283: G4~283.0188679245283 + E4-283.0188679245283 + C4/283.0188679245283, 283.0188679245283: G4~283.0188679245283 + E4-283.0188679245283 + C4/283.0188679245283, 283.0188679245283: A4~283.0188679245283, 283.0188679245283: B4~283.0188679245283, 283.0188679245283: B4~283.0188679245283, 283.0188679245283: A4~283.0188679245283 + E4^283.0188679245283, 283.0188679245283: G4~283.0188679245283 + D4^283.0188679245283, 1132.0754716981132`, ColorPickCheck: tune` 230.76923076923077, 230.76923076923077: B5-230.76923076923077, 230.76923076923077: B5-230.76923076923077, 6692.307692307692`, ColorPickFail: tune` 153.0612244897959: E4/153.0612244897959, 153.0612244897959: D4/153.0612244897959, 153.0612244897959: C4/153.0612244897959, 4438.775510204081`, }; let level = Maps.ColorPicker; const levels = [ map` wwwww wwwww wwwww wwwww wwwww`, map` ........... ........... ........... ..0123456.. .....x..... ..0123456.. .....y..... ........... ...........`, map`a......... .......... ..w..ww... ..w....... ..w....... .....b.... ...www.... ..........` ]; loadColorPicker(); function registerSprites() { setLegend( [player, player1Bitmap()], [player2, player2Bitmap()], [wall, wallBitmap], [projectile, projectileBitmap] ); } function registerColorSprites() { const chooser1 = "x"; const chooser2 = "y"; setLegend( ["0", colorTanks[0][">"]], ["1", colorTanks[1][">"]], ["2", colorTanks[2][">"]], ["3", colorTanks[3][">"]], ["4", colorTanks[4][">"]], ["5", colorTanks[5][">"]], ["6", colorTanks[6][">"]], [chooser1, bitmap` 4444444444444444 4444444444444444 4444444444444444 ................ ................ ................ ................ ................ ................ ................ ................ ................ ................ ................ ................ ................`], [chooser2, bitmap` 4444444444444444 4444444444444444 4444444444444444 ................ ................ ................ ................ ................ ................ ................ ................ ................ ................ ................ ................ ................`] ); } function loadLevel() { clearText(); direction1 = ">"; direction2 = "<"; registerSprites(); level = Maps.FirstLevel; setMap(levels[level]); } function loadColorPicker() { level = 1; registerColorSprites(); setMap(levels[level]); addText("L/R MOVE,UP SELECT", { y: 1 }); } // holds all the flying bullets var projEntities = []; function addProjectile(x, y, direction) { if (level >= Maps.FirstLevel) { setLegend([projectile, projectileBitmap]); if (x >= 0 && x < width() && y >= 0 && y < height() && getTile(x, y).length <= 0) { projEntities.push([x, y, direction]); addSprite(x, y, projectile); } checkWinLose(x, y); } } function player1Bitmap() { return colorTanks[player1Type][direction1]; } function player2Bitmap() { return colorTanks[player2Type][direction2]; } function oneMusic(tune) { if (musicPlaying) { musicPlaying.end(); } musicPlaying = playTune(tune); } function checkWinLose(x, y) { if (level >= Maps.FirstLevel) { registerSprites(); if (getFirst(player).x == x && getFirst(player).y == y) { level = 0; oneMusic(Music.End); setMap(levels[level]); clearText(); addText(colorString[player2Type] + " WIN", { x: 0, y: 0, color: colorCode[player2Type] }); addText("ANY KEY TO CONT", { x: 0, y: 2, color: color`2` }); score2++; lastWin = new Date().getTime(); } else if (getFirst(player2).x == x && getFirst(player2).y == y) { level = 0; oneMusic(Music.End); setMap(levels[level]); clearText(); addText(colorString[player1Type] + " WIN", { x: 0, y: 0, color: colorCode[player1Type] }); addText("ANY KEY TO CONT", { x: 0, y: 2, color: color`2` }); score1++; lastWin = new Date().getTime(); } } } /* change direction */ onInput("w", () => { if (level >= Maps.FirstLevel) { direction1 = "^"; registerSprites(); addProjectile(getFirst(player).x, getFirst(player).y - 1, "^"); } else if (level == Maps.ColorPicker) { const chooser1 = "x"; const chooser2 = "y"; player1Ready = true; player1Type = getFirst(chooser1).x - 2; player2Type = getFirst(chooser2).x - 2; if (player1Type == player2Type) { oneMusic(Music.ColorPickFail); } else if (player2Ready) { oneMusic(Music.ColorPickCheck); loadLevel(); } else { oneMusic(Music.ColorPickCheck); } } }) onInput("s", () => { if (level >= Maps.FirstLevel) { direction1 = "."; registerSprites(); addProjectile(getFirst(player).x, getFirst(player).y + 1, "."); } }) onInput('a', () => { if (level >= Maps.FirstLevel) { direction1 = "<"; registerSprites(); addProjectile(getFirst(player).x - 1, getFirst(player).y, "<"); } else if (level == Maps.ColorPicker) { const chooser1 = "x"; registerColorSprites(); if (getFirst(chooser1).x > 2) { getFirst(chooser1).x -= 1; } } }) onInput('d', () => { if (level >= Maps.FirstLevel) { direction1 = ">"; registerSprites(); addProjectile(getFirst(player).x + 1, getFirst(player).y, ">"); } else if (level == Maps.ColorPicker) { const chooser1 = "x"; registerColorSprites(); if (getFirst(chooser1).x < 8) { getFirst(chooser1).x += 1; } } }) onInput("i", () => { if (level >= Maps.FirstLevel) { direction2 = "^"; registerSprites(); addProjectile(getFirst(player2).x, getFirst(player2).y - 1, "^"); } else if (level == Maps.ColorPicker) { const chooser1 = "x"; const chooser2 = "y"; player2Ready = true; player1Type = getFirst(chooser1).x - 2; player2Type = getFirst(chooser2).x - 2; if (player1Type == player2Type) { oneMusic(Music.ColorPickFail); } else if (player1Ready) { oneMusic(Music.ColorPickCheck); loadLevel(); } else { oneMusic(Music.ColorPickCheck); } } }) onInput('k', () => { if (level >= Maps.FirstLevel) { direction2 = "."; registerSprites(); addProjectile(getFirst(player2).x, getFirst(player2).y + 1, "."); } }) onInput('j', () => { if (level >= Maps.FirstLevel) { direction2 = "<"; registerSprites(); addProjectile(getFirst(player2).x - 1, getFirst(player2).y, "<"); } else if (level == Maps.ColorPicker) { const chooser2 = "y"; registerColorSprites(); if (getFirst(chooser2).x > 2) { getFirst(chooser2).x -= 1; } } }); onInput("l", () => { if (level >= Maps.FirstLevel) { direction2 = ">"; registerSprites(); addProjectile(getFirst(player2).x + 1, getFirst(player2).y, ">"); } else if (level == Maps.ColorPicker) { const chooser2 = "y"; registerColorSprites(); if (getFirst(chooser2).x < 8) { getFirst(chooser2).x += 1; } } }) // restart the game if the level is different afterInput(() => { if (new Date().getTime() - lastWin >= 250 && level == Maps.End) { loadLevel(); addText(score1 + ":" + score2, { color: color`4` }); } }); // actually move the sprite in a forever loop function run() { if (level >= Maps.FirstLevel) { // projectiles go first registerSprites(); for (var i = 0; i < projEntities.length;) { clearTile(projEntities[i][0], projEntities[i][1]); switch (projEntities[i][2]) { case "^": projEntities[i][1] -= 1; break; case "<": projEntities[i][0] -= 1; break; case ">": projEntities[i][0] += 1; break; case ".": projEntities[i][1] += 1; break; default: break; } const x = projEntities[i][0]; const y = projEntities[i][1]; var items = getTile(x, y); checkWinLose(x, y); if (x < 0 || x >= width() || y < 0 || y >= height() || items.length > 0) { projEntities.splice(i, 1); } else { i++; addSprite(x, y, projectile); } } // process tank movement if (level >= Maps.FirstLevel) { switch (direction1) { case "^": getFirst(player).y -= 1; break; case "<": getFirst(player).x -= 1; break; case ">": getFirst(player).x += 1; break; case ".": getFirst(player).y += 1; break; default: break; } switch (direction2) { case "^": getFirst(player2).y -= 1; break; case "<": getFirst(player2).x -= 1; break; case ">": getFirst(player2).x += 1; break; case ".": getFirst(player2).y += 1; break; default: break; } } } } setInterval(run, 500);