您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds a lot new settings to the game https://rocketer.glitch.me/
// ==UserScript== // @name Rocketer Utilities // @namespace http://tampermonkey.net/ // @version 1.4 // @description Adds a lot new settings to the game https://rocketer.glitch.me/ // @author DB423 (Impsaccrain) // @match http*://rocketer.glitch.me/* // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== // @grant none // @license DISTRIBUTION // ==/UserScript== (function() { 'use strict'; localStorage.RocketerUtilities = localStorage.RocketerUtilities || JSON.stringify({ Options: { AuraState: 1, AutoRespawn: 0, Theme: 0 }, version: 1.4 }); if (JSON.parse(localStorage.RocketerUtilities).version != 1.4) { localStorage.RocketerUtilities = JSON.stringify({ Options: { AuraState: 1, AutoRespawn: 0, Theme: 0 }, version: 1.4 }); }; const Utils = JSON.parse(localStorage.RocketerUtilities); const Options = Utils.Options; var settings = document.getElementById('settingsPopup'); var closesettingspopup = document.getElementById('closeSettingsPopup'); var themes = document.getElementById('theme'); changetheme = function (selectObject) { colortheme = selectObject.value; let newutils = JSON.parse(localStorage.RocketerUtilities); newutils.Options.Theme = document.getElementById('theme').selectedIndex; newutils = JSON.stringify(newutils); localStorage.RocketerUtilities = newutils; } var playershape = 'circle'; var whitetheme = document.createElement('option'); whitetheme.value = 'whitetheme'; whitetheme.textContent = 'White'; themes.appendChild(whitetheme); var simplistic = document.createElement('option'); simplistic.value = 'simplistic'; simplistic.textContent = 'Simplistic'; themes.appendChild(simplistic); for (let i = 3; i < 15; i++) { shapecolors[i].whitetheme = { color: "#FFFFFF", outline: "#FFFFFF", hitcolor: "#FFFFFF", hitoutline: "#FFFFFF", }; shapecolors[i].simplistic = { color: shapecolors[i].default.color, outline: shapecolors[i].default.color, hitcolor: shapecolors[i].default.hitcolor, hitoutline: shapecolors[i].default.hitcolor, }; }; var chatstate = true; function toggleChat() { let chatinput = document.getElementById('chat'); chatstate = !chatstate; if (!chatstate) { chatinput.style.display = 'none'; } else { chatinput.style.display = 'block'; }; }; var aurastate = Options.AuraState == 1 ? true : false; function toggleAura() { aurastate = !aurastate Options.AuraState = aurastate ? 1 : 0; localStorage.RocketerUtilities = JSON.stringify(Utils); }; var autorespawn = Options.AutoRespawn == 1 ? true : false; function toggleAutoRespawn() { autorespawn = !autorespawn Options.AutoRespawn = autorespawn ? 1 : 0; localStorage.RocketerUtilities = JSON.stringify(Utils); }; var chattoggle = document.createElement('label'); chattoggle.className = 'switch'; var cti = document.createElement('input'); cti.type = 'checkbox'; cti.checked = true; cti.onclick = toggleChat; var cts = document.createElement('span'); cts.className = 'slider round'; chattoggle.appendChild(cti); chattoggle.appendChild(cts); var auratoggle = document.createElement('label'); auratoggle.className = 'switch'; var ati = document.createElement('input'); ati.type = 'checkbox'; ati.checked = Options.AuraState == 1 ? false : true; ati.onclick = toggleAura; var ats = document.createElement('span'); ats.className = 'slider round'; auratoggle.appendChild(ati); auratoggle.appendChild(ats); var respawntoggle = document.createElement('label'); respawntoggle.className = 'switch'; var rti = document.createElement('input'); rti.type = 'checkbox'; rti.checked = Options.AutoRespawn == 1 ? true : false; rti.onclick = toggleAutoRespawn; var rts = document.createElement('span'); rts.className = 'slider round'; respawntoggle.appendChild(rti); respawntoggle.appendChild(rts); var utilities = document.createElement('span'); utilities.style = 'font-weight: 700; font-size: 25px;'; utilities.textContent = 'Rocketer Utilities'; settings.appendChild(document.createElement('br')); settings.appendChild(document.createElement('br')); settings.appendChild(utilities); settings.appendChild(document.createElement('hr')); settings.appendChild(document.createTextNode("Chat ")); settings.appendChild(chattoggle); settings.appendChild(document.createElement('br')); settings.appendChild(document.createElement('br')); settings.appendChild(document.createTextNode("Invisible auras ")); settings.appendChild(auratoggle); settings.appendChild(document.createElement('br')); settings.appendChild(document.createElement('br')); settings.appendChild(document.createTextNode("Auto-respawn ")); settings.appendChild(respawntoggle); var playershapediv = document.createElement('div'); playershapediv.appendChild(document.createElement('br')); playershapediv.appendChild(document.createTextNode('Player shape: ')); var playershapeselect = document.createElement('select'); playershapeselect.id = 'player-shape-select' playershapeselect.style.backgroundColor = 'rgba(0, 0, 0, 0.5)'; playershapeselect.style.color = 'white'; playershapeselect.style.borderRadius = '7px'; playershapeselect.style.width = '100px'; playershapeselect.style.height = '30px'; var playershapecircle = document.createElement('option'); playershapecircle.value = 'circle'; playershapecircle.textContent = 'Circle'; playershapeselect.appendChild(playershapecircle); var playershapesquare = document.createElement('option'); playershapesquare.value = 'square'; playershapesquare.textContent = 'Square'; playershapeselect.appendChild(playershapesquare); var playershapetriangle = document.createElement('option'); playershapetriangle.value = 'triangle'; playershapetriangle.textContent = 'Triangle'; playershapeselect.appendChild(playershapetriangle); playershapediv.appendChild(playershapeselect); setTimeout(function() { let changelogDisplayElement = document.getElementById('changelogDisplay'); changelogDisplayElement.appendChild(document.createElement('br')); changelogDisplayElement.appendChild(document.createElement('br')); let rucspan = document.createElement('span'); rucspan.id = 'rocketer-utils-changelog'; let ruc = document.createTextNode('ROCKETER UTILITIES CHANGELOG - 1.4 - 6 December 2023'); rucspan.style.color = 'orange'; rucspan.appendChild(ruc); let rucp = document.createElement('p'); function cct(text, br) { rucp.appendChild(document.createTextNode(text)); if (br) { rucp.appendChild(document.createElement('br')); }; }; cct('- BUGFIX: Fixed the chat doubling itself', true); cct('- FEATURE: Added the smooth chat transitions (they didn\'t appear)', false) rucspan.appendChild(rucp); changelogDisplayElement.appendChild(rucspan); themes.selectedIndex = Options.Theme; changetheme(themes); }, 500); function newdrawplayer(canvas, object, fov, spawnProtect, playercolor, playeroutline, eternal, objectangle){//only barrels and body (no heath bars, names, and chats) const CRTP = document.getElementById('theme').value; //objectangle refers to angle rotated before triggering this function //fov is clientFovMultiplier for ctx, hctx is 1 canvas.lineJoin = "round"; //make nice round corners //draw assets below body, e.g. rammer body base for (let assetID in object.assets){ var asset = object.assets[assetID]; if (asset.type == "under") { if (('angle' in asset) && asset.angle != 0) { canvas.rotate(asset.angle * Math.PI / 180); } canvas.translate( (object.width / fov) * asset.x, (object.width / fov) * asset.y ); canvas.fillStyle = asset.color; canvas.strokeStyle = asset.outline; canvas.lineWidth = asset.outlineThickness / fov; if (asset.sides == 0) { canvas.beginPath(); canvas.arc(0, 0, (object.width / fov) * asset.size, 0, 2 * Math.PI); canvas.fill(); if (CRTP != 'simplistic') { canvas.stroke(); }; } else { canvas.beginPath(); let baseSides = asset.sides; canvas.moveTo((object.width / fov) * asset.size, 0); for (let i = 1; i <= baseSides; i++) { canvas.lineTo((object.width / fov) * asset.size * Math.cos((i * 2 * Math.PI) / baseSides), (object.width / fov) * asset.size * Math.sin((i * 2 * Math.PI) / baseSides)); } canvas.fill(); if (CRTP != 'simplistic') { canvas.stroke(); }; } canvas.translate( (-object.width / fov) * asset.x, (-object.width / fov) * asset.y ); if (('angle' in asset) && asset.angle != 0) { canvas.rotate(-asset.angle * Math.PI / 180); } } } //draw barrel canvas.lineWidth = 4 / fov; //weapon barrels for (let barrel in object.barrels){ let thisBarrel = object.barrels[barrel]; canvas.rotate((thisBarrel.additionalAngle * Math.PI) / 180); //rotate to barrel angle canvas.fillStyle = bodyColors.barrel.col; canvas.strokeStyle = bodyColors.barrel.outline; if (spawnProtect == "yes") { //if have spawn protection canvas.fillStyle = bodyColors.barrel.hitCol; canvas.strokeStyle = bodyColors.barrel.hitOutline; } //bullet barrel //note: barrelHeightChange refers to reduction in barrel height for barrel animation when shooting if (thisBarrel.barrelType == "bullet") { drawBulletBarrel(canvas,thisBarrel.x,thisBarrel.barrelWidth,thisBarrel.barrelHeight,thisBarrel.barrelHeightChange,fov) } //drone barrel else if (thisBarrel.barrelType == "drone") { drawDroneBarrel(canvas,thisBarrel.x,thisBarrel.barrelWidth,thisBarrel.barrelHeight,thisBarrel.barrelHeightChange,fov) } //trap barrel else if (thisBarrel.barrelType == "trap") { drawTrapBarrel(canvas,thisBarrel.x,thisBarrel.barrelWidth,thisBarrel.barrelHeight,thisBarrel.barrelHeightChange,fov) } //mine barrel else if (thisBarrel.barrelType == "mine") { drawMineBarrel(canvas,thisBarrel.x,thisBarrel.barrelWidth,thisBarrel.barrelHeight,thisBarrel.barrelHeightChange,fov) } //minion barrel else if (thisBarrel.barrelType == "minion") { drawMinionBarrel(canvas,thisBarrel.x,thisBarrel.barrelWidth,thisBarrel.barrelHeight,thisBarrel.barrelHeightChange,fov) } canvas.rotate((-thisBarrel.additionalAngle * Math.PI) / 180); //rotate back } //draw player body canvas.fillStyle = playercolor; canvas.strokeStyle = playeroutline; if (eternal == "no") { //not a tier 6 tank canvas.beginPath(); canvas.arc(0, 0, object.width / fov, 0, 2 * Math.PI); canvas.fill(); if (CRTP != 'simplistic') { canvas.stroke(); }; } else { //if a tier 6 tank canvas.beginPath(); let baseSides = 6; canvas.moveTo((object.width / fov), 0); for (var i = 1; i <= baseSides; i++) { canvas.lineTo((object.width / fov) * Math.cos((i * 2 * Math.PI) / baseSides), (object.width / fov) * Math.sin((i * 2 * Math.PI) / baseSides)); } canvas.fill(); if (CRTP != 'simplistic') { canvas.stroke(); }; } //barrels in body upgrade for (let barrel in object.bodybarrels){ let thisBarrel = object.bodybarrels[barrel]; canvas.rotate(thisBarrel.additionalAngle - objectangle); //rotate to barrel angle canvas.fillStyle = bodyColors.barrel.col; canvas.strokeStyle = bodyColors.barrel.outline; if (spawnProtect == "yes") { //if have spawn protection canvas.fillStyle = bodyColors.barrel.hitCol; canvas.strokeStyle = bodyColors.barrel.hitOutline; } //bullet barrel if (thisBarrel.barrelType == "bullet") { drawBulletBarrel(canvas,thisBarrel.x,thisBarrel.barrelWidth,thisBarrel.barrelHeight,thisBarrel.barrelHeightChange,fov) } //drone barrel else if (thisBarrel.barrelType == "drone") { drawDroneBarrel(canvas,thisBarrel.x,thisBarrel.barrelWidth,thisBarrel.barrelHeight,thisBarrel.barrelHeightChange,fov) } //trap barrel (doesnt exist atm) else if (thisBarrel.barrelType == "trap") { drawTrapBarrel(canvas,thisBarrel.x,thisBarrel.barrelWidth,thisBarrel.barrelHeight,thisBarrel.barrelHeightChange,fov) } //mine barrel (doesnt exist atm) else if (thisBarrel.barrelType == "mine") { drawMineBarrel(canvas,thisBarrel.x,thisBarrel.barrelWidth,thisBarrel.barrelHeight,thisBarrel.barrelHeightChange,fov) } //minion barrel (doesnt exist atm) else if (thisBarrel.barrelType == "minion") { drawMinionBarrel(canvas,thisBarrel.x,thisBarrel.barrelWidth,thisBarrel.barrelHeight,thisBarrel.barrelHeightChange,fov) } canvas.rotate(-thisBarrel.additionalAngle + objectangle); //rotate back } //draw turret base if ('turretBaseSize' in object){ canvas.fillStyle = bodyColors.barrel.col; canvas.strokeStyle = bodyColors.barrel.outline; canvas.beginPath(); canvas.arc(0, 0, (object.width / clientFovMultiplier) * object.turretBaseSize, 0, 2 * Math.PI); canvas.fill(); if (CRTP != 'simplistic') { canvas.stroke(); }; } //draw assets above body, e.g. aura assets for (let assetID in object.assets){ var asset = object.assets[assetID]; if (asset.type == "above") { if (('angle' in asset) && asset.angle != 0) { canvas.rotate(asset.angle * Math.PI / 180); } canvas.translate( (object.width / fov) * asset.x, (object.width / fov) * asset.y ); canvas.fillStyle = asset.color; canvas.strokeStyle = asset.outline; canvas.lineWidth = asset.outlineThickness / fov; if (asset.sides == 0) { canvas.beginPath(); canvas.arc(0, 0, (object.width / fov) * asset.size, 0, 2 * Math.PI); canvas.fill(); if (CRTP != 'simplistic') { canvas.stroke(); }; } else { canvas.beginPath(); let baseSides = asset.sides; canvas.moveTo((object.width / fov) * asset.size, 0); for (var i = 1; i <= baseSides; i++) { canvas.lineTo((object.width / fov) * asset.size * Math.cos((i * 2 * Math.PI) / baseSides), (object.width / fov) * asset.size * Math.sin((i * 2 * Math.PI) / baseSides)); } canvas.fill(); if (CRTP != 'simplistic') { canvas.stroke(); }; } canvas.translate( (-object.width / fov) * asset.x, (-object.width / fov) * asset.y ); if (('angle' in asset) && asset.angle != 0) { canvas.rotate(-asset.angle * Math.PI / 180); } } } canvas.lineJoin = "miter"; //change back }; function newdraw(object, id, playerstring, auraWidth) { const CRTP = document.getElementById('theme').value; //function for drawing objects on the canvas. need to provide aura width because this fuction cannot access variables outside var drawingX = (object.x - px) / clientFovMultiplier + canvas.width / 2; //calculate the location on canvas to draw object var drawingY = (object.y - py) / clientFovMultiplier + canvas.height / 2; if (object.type == "bullet") { //draw bullet if (object.hasOwnProperty("deadOpacity")) { //if this is an animation of a dead object ctx.globalAlpha = object.deadOpacity; } var chooseflash = 3; if (object.hit > 0 && object.bulletType != "aura") { //if shape is hit AND bullet is not aura, choose whether it's color is white or original color to create flashing effect chooseflash = Math.floor(Math.random() * 3); //random number 0, 1 or 2 } if (chooseflash == 0) { ctx.fillStyle = "white"; } else if (chooseflash == 1) { ctx.fillStyle = "pink"; } else { if (object.ownsIt == "yes" || object.bulletType == "aura") { //if it's an aura or client's tank owns the bullet ctx.fillStyle = object.color; } else { ctx.fillStyle = "#f04f54"; //bullet color is red } } if (object.bulletType == "aura") { var choosing; if (aurastate && CRTP != 'simplistic') { choosing = Math.floor(Math.random() * 2); //choose if particle spawn } else { choosing = 0; }; if (choosing == 1) { //spawn a particle var angleDegrees = Math.floor(Math.random() * 360); //choose angle in degrees var angleRadians = (angleDegrees * Math.PI) / 180; //convert to radians var randomDistFromCenter = Math.floor(Math.random() * object.width * 2) - object.width; radparticles[particleID] = { angle: angleRadians, x: object.x + randomDistFromCenter * Math.cos(angleRadians), y: object.y + randomDistFromCenter * Math.sin(angleRadians), width: 5, height: 5, speed: 1, timer: 30, maxtimer: 50, color: object.color, outline: object.outline, type: "particle", }; particleID++; } } if (object.ownsIt == "yes" || object.bulletType == "aura") { //if it's an aura or client's tank owns the bullet ctx.strokeStyle = object.outline; } else { ctx.strokeStyle = "#b33b3f"; //bullet is red } //bullet is purple even if bullet belongs to enemy if (object.color == "#934c93") { ctx.fillStyle = object.color; } if (object.outline == "#660066") { ctx.strokeStyle = object.outline; } //team colors if (object.team == "blue" || object.team == "green" || object.team == "red" || object.team == "purple" || object.team == "eternal" || object.team == "magenta" || object.team == "fallen" || object.team == "celestial") { ctx.fillStyle = bodyColors[object.team].col; ctx.strokeStyle = bodyColors[object.team].outline; } if (object.bulletType == "aura"){ //color is aura color, regardless of team ctx.fillStyle = object.color; ctx.strokeStyle = object.outline; } if (object.passive == "yes") { if (object.bulletType == "aura") { ctx.strokeStyle = "rgba(128,128,128,.2)"; ctx.fillStyle = "rgba(128,128,128,.2)"; } else { ctx.strokeStyle = "dimgrey"; ctx.fillStyle = "grey"; } } if (object.team=="mob"){ //dune mob's bullets is the colo of mob ctx.fillStyle = botcolors[object.ownerName].color; ctx.strokeStyle = botcolors[object.ownerName].outline; } ctx.lineWidth = 4 / clientFovMultiplier; if (object.bulletType == "bullet" || object.bulletType == "aura") { if (!object.color.includes('rgba(56,183,100')){//not a heal aura ctx.beginPath(); ctx.arc( drawingX, drawingY, object.width / clientFovMultiplier, 0, 2 * Math.PI ); if (aurastate || object.bulletType != "aura") { ctx.fill(); }; if (object.bulletType == 'aura') { ctx.stroke(); } else if (CRTP != 'simplistic') { ctx.stroke(); }; } else{//8 sides for healing aura ctx.beginPath(); ctx.moveTo((object.width / clientFovMultiplier) + drawingX, drawingY); for (var i = 1; i <= 8 + 1; i += 1) { ctx.lineTo( (object.width / clientFovMultiplier) * Math.cos((i * 2 * Math.PI) / 8) + drawingX, (object.width / clientFovMultiplier) * Math.sin((i * 2 * Math.PI) / 8) + drawingY ); } if (aurastate || object.bulletType != "aura") { ctx.fill(); }; if (CRTP != 'simplistic') { ctx.stroke(); }; } } else if (object.bulletType == "trap") { //width is the radius, so need to times two to get total width //note: x and y of object are the center of object, but when drawing rectangles, the x and y coordinates given need to be the top left corner of the rectangle, so need to minus the width and height ctx.fillRect( drawingX - object.width / clientFovMultiplier, drawingY - object.width / clientFovMultiplier, (object.width * 2) / clientFovMultiplier, (object.width * 2) / clientFovMultiplier ); if (CRTP != 'simplistic') { ctx.strokeRect( drawingX - object.width / clientFovMultiplier, drawingY - object.width / clientFovMultiplier, (object.width * 2) / clientFovMultiplier, (object.width * 2) / clientFovMultiplier ); }; } else if (object.bulletType == "drone") { ctx.save(); ctx.translate(drawingX, drawingY); ctx.rotate(object.moveAngle); //ctx.rotate((object.moveAngle*180/Math.PI - 90) *Math.PI/180);//cannot straightaway use the angle, must add 90 degrees to it, because 0 degrees is pointing right, but we are drawing the triangle upwards ctx.beginPath(); ctx.moveTo( (object.width / clientFovMultiplier) * Math.cos(0), (object.width / clientFovMultiplier) * Math.sin(0) ); for (var i = 1; i <= 3; i += 1) { ctx.lineTo( (object.width / clientFovMultiplier) * Math.cos((i * 2 * Math.PI) / 3), (object.width / clientFovMultiplier) * Math.sin((i * 2 * Math.PI) / 3) ); } ctx.fill(); if (CRTP != 'simplistic') { ctx.stroke(); }; ctx.restore(); } else if (object.bulletType == "mine" || object.bulletType == "minion") { //console.log(object.moveAngle/Math.PI*180) //mine is trap with barrel, minion is bullet with barrel ctx.save(); ctx.translate(drawingX, drawingY); ctx.rotate(object.moveAngle); //ctx.rotate((object.moveAngle*180/Math.PI - 90) *Math.PI/180);//cannot straightaway use the angle, must add 90 degrees to it, because 0 degrees is pointing right, but we are drawing the triangle upwards if (object.bulletType == "minion"){ //draw barrels underneath var prevfill = ctx.fillStyle; var prevstroke = ctx.strokeStyle;//store previous bullet color so can change back later ctx.fillStyle = bodyColors.barrel.col; ctx.strokeStyle = bodyColors.barrel.outline; Object.keys(object.barrels).forEach((barrel) => { let thisBarrel = object.barrels[barrel]; ctx.rotate(thisBarrel.additionalAngle); //rotate to barrel angle if (thisBarrel.barrelType == "bullet") { ctx.fillRect( -thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier, thisBarrel.barrelWidth / clientFovMultiplier, (thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier ); if (CRTP != 'simplistic') { ctx.strokeRect( -thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier, thisBarrel.barrelWidth / clientFovMultiplier, (thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier ); }; } //drone barrel else if (thisBarrel.barrelType == "drone") { ctx.beginPath(); ctx.moveTo( -thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, 0 ); ctx.lineTo( -thisBarrel.barrelWidth / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier ); ctx.lineTo( thisBarrel.barrelWidth / clientFovMultiplier + (thisBarrel.x * 2) / clientFovMultiplier, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier ); ctx.lineTo( thisBarrel.barrelWidth / 2 / clientFovMultiplier + (thisBarrel.x * 2) / clientFovMultiplier, 0 ); ctx.fill(); if (CRTP != 'simplistic') { ctx.stroke(); }; } //trap barrel else if (thisBarrel.barrelType == "trap") { ctx.fillRect( -thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, ((-( thisBarrel.barrelHeight - thisBarrel.barrelHeightChange ) / 3) * 2) / clientFovMultiplier, thisBarrel.barrelWidth / clientFovMultiplier, (((thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / 3) * 2) / clientFovMultiplier ); if (CRTP != 'simplistic') { ctx.strokeRect( -thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, ((-( thisBarrel.barrelHeight - thisBarrel.barrelHeightChange ) / 3) * 2) / clientFovMultiplier, thisBarrel.barrelWidth / clientFovMultiplier, (((thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / 3) * 2) / clientFovMultiplier ); }; ctx.beginPath(); ctx.moveTo( -thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, ((-( thisBarrel.barrelHeight - thisBarrel.barrelHeightChange ) / 3) * 2) / clientFovMultiplier ); ctx.lineTo( -thisBarrel.barrelWidth / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier ); ctx.lineTo( thisBarrel.barrelWidth / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier ); ctx.lineTo( thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, ((-( thisBarrel.barrelHeight - thisBarrel.barrelHeightChange ) / 3) * 2) / clientFovMultiplier ); ctx.fill(); if (CRTP != 'simplistic') { ctx.stroke(); }; } //mine barrel else if (thisBarrel.barrelType == "mine") { ctx.fillRect( -thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, ((-( thisBarrel.barrelHeight - thisBarrel.barrelHeightChange ) / 3) * 2) / clientFovMultiplier, thisBarrel.barrelWidth / clientFovMultiplier, (((thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / 3) * 2) / clientFovMultiplier ); if (CRTP != 'simplistic') { ctx.strokeRect( -thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, ((-( thisBarrel.barrelHeight - thisBarrel.barrelHeightChange ) / 3) * 2) / clientFovMultiplier, thisBarrel.barrelWidth / clientFovMultiplier, (((thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / 3) * 2) / clientFovMultiplier ); }; ctx.beginPath(); ctx.moveTo( -thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, ((-( thisBarrel.barrelHeight - thisBarrel.barrelHeightChange ) / 3) * 2) / clientFovMultiplier ); ctx.lineTo( -thisBarrel.barrelWidth / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier ); ctx.lineTo( thisBarrel.barrelWidth / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier ); ctx.lineTo( thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, ((-( thisBarrel.barrelHeight - thisBarrel.barrelHeightChange ) / 3) * 2) / clientFovMultiplier ); ctx.fill(); if (CRTP != 'simplistic') { ctx.stroke(); }; } //minion barrel else if (thisBarrel.barrelType == "minion") { ctx.fillRect( -thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier, thisBarrel.barrelWidth / clientFovMultiplier, (thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier ); if (CRTP != 'simplistic') { ctx.strokeRect( -thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier, thisBarrel.barrelWidth / clientFovMultiplier, (thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier ); }; ctx.fillRect( (-thisBarrel.barrelWidth * 1.5) / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / 1.5 / clientFovMultiplier, (thisBarrel.barrelWidth / clientFovMultiplier) * 1.5, (thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / 1.5 / clientFovMultiplier ); if (CRTP != 'simplistic') { ctx.strokeRect( (-thisBarrel.barrelWidth * 1.5) / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / 1.5 / clientFovMultiplier, (thisBarrel.barrelWidth / clientFovMultiplier) * 1.5, (thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / 1.5 / clientFovMultiplier ); }; ctx.fillRect( (-thisBarrel.barrelWidth * 1.5) / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier, (thisBarrel.barrelWidth / clientFovMultiplier) * 1.5, (thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) /5/ clientFovMultiplier ); if (CRTP != 'simplistic') { ctx.strokeRect( (-thisBarrel.barrelWidth * 1.5) / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier, (thisBarrel.barrelWidth / clientFovMultiplier) * 1.5, (thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) /5 /clientFovMultiplier ); }; } }) ctx.fillStyle = prevfill; ctx.strokeStyle = prevstroke; } ctx.beginPath(); if (object.bulletType == "mine"){//mine ctx.moveTo( (object.width / clientFovMultiplier) * Math.cos(0), (object.width / clientFovMultiplier) * Math.sin(0) ); for (var i = 1; i <= 3; i += 1) { ctx.lineTo( (object.width / clientFovMultiplier) * Math.cos((i * 2 * Math.PI) / 3), (object.width / clientFovMultiplier) * Math.sin((i * 2 * Math.PI) / 3) ); } } else{//minion ctx.arc(0, 0, object.width / clientFovMultiplier, 0, 2 * Math.PI); } ctx.fill(); if (CRTP != 'simplistic') { ctx.stroke(); }; ctx.rotate(-object.moveAngle); //rotate back //BARREL FOR THE MINE TRAP if (object.bulletType == "mine"){ Object.keys(object.barrels).forEach((barrel) => { let thisBarrel = object.barrels[barrel]; ctx.rotate(thisBarrel.additionalAngle); //rotate to barrel angle ctx.fillStyle = "grey"; ctx.strokeStyle = "#5e5e5e"; if (thisBarrel.barrelType == "bullet") { ctx.fillRect( -thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier, thisBarrel.barrelWidth / clientFovMultiplier, (thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier ); if (CRTP != 'simplistic') { ctx.strokeRect( -thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier, thisBarrel.barrelWidth / clientFovMultiplier, (thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier ); }; } //drone barrel else if (thisBarrel.barrelType == "drone") { ctx.beginPath(); ctx.moveTo( -thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, 0 ); ctx.lineTo( -thisBarrel.barrelWidth / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier ); ctx.lineTo( thisBarrel.barrelWidth / clientFovMultiplier + (thisBarrel.x * 2) / clientFovMultiplier, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier ); ctx.lineTo( thisBarrel.barrelWidth / 2 / clientFovMultiplier + (thisBarrel.x * 2) / clientFovMultiplier, 0 ); ctx.fill(); if (CRTP != 'simplistic') { ctx.stroke(); }; } //trap barrel else if (thisBarrel.barrelType == "trap") { ctx.fillRect( -thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, ((-( thisBarrel.barrelHeight - thisBarrel.barrelHeightChange ) / 3) * 2) / clientFovMultiplier, thisBarrel.barrelWidth / clientFovMultiplier, (((thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / 3) * 2) / clientFovMultiplier ); if (CRTP != 'simplistic') { ctx.strokeRect( -thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, ((-( thisBarrel.barrelHeight - thisBarrel.barrelHeightChange ) / 3) * 2) / clientFovMultiplier, thisBarrel.barrelWidth / clientFovMultiplier, (((thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / 3) * 2) / clientFovMultiplier ); }; ctx.beginPath(); ctx.moveTo( -thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, ((-( thisBarrel.barrelHeight - thisBarrel.barrelHeightChange ) / 3) * 2) / clientFovMultiplier ); ctx.lineTo( -thisBarrel.barrelWidth / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier ); ctx.lineTo( thisBarrel.barrelWidth / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier ); ctx.lineTo( thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, ((-( thisBarrel.barrelHeight - thisBarrel.barrelHeightChange ) / 3) * 2) / clientFovMultiplier ); ctx.fill(); if (CRTP != 'simplistic') { ctx.stroke(); }; } //mine barrel else if (thisBarrel.barrelType == "mine") { ctx.fillRect( -thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, ((-( thisBarrel.barrelHeight - thisBarrel.barrelHeightChange ) / 3) * 2) / clientFovMultiplier, thisBarrel.barrelWidth / clientFovMultiplier, (((thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / 3) * 2) / clientFovMultiplier ); if (CRTP != 'simplistic') { ctx.strokeRect( -thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, ((-( thisBarrel.barrelHeight - thisBarrel.barrelHeightChange ) / 3) * 2) / clientFovMultiplier, thisBarrel.barrelWidth / clientFovMultiplier, (((thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / 3) * 2) / clientFovMultiplier ); }; ctx.beginPath(); ctx.moveTo( -thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, ((-( thisBarrel.barrelHeight - thisBarrel.barrelHeightChange ) / 3) * 2) / clientFovMultiplier ); ctx.lineTo( -thisBarrel.barrelWidth / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier ); ctx.lineTo( thisBarrel.barrelWidth / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier ); ctx.lineTo( thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, ((-( thisBarrel.barrelHeight - thisBarrel.barrelHeightChange ) / 3) * 2) / clientFovMultiplier ); ctx.fill(); if (CRTP != 'simplistic') { ctx.stroke(); }; } //minion barrel else if (thisBarrel.barrelType == "minion") { ctx.fillRect( -thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier, thisBarrel.barrelWidth / clientFovMultiplier, (thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier ); if (CRTP != 'simplistic') { ctx.strokeRect( -thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier, thisBarrel.barrelWidth / clientFovMultiplier, (thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier ); }; ctx.fillRect( (-thisBarrel.barrelWidth * 1.5) / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / 1.5 / clientFovMultiplier, (thisBarrel.barrelWidth / clientFovMultiplier) * 1.5, (thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / 1.5 / clientFovMultiplier ); if (CRTP != 'simplistic') { ctx.strokeRect( (-thisBarrel.barrelWidth * 1.5) / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / 1.5 / clientFovMultiplier, (thisBarrel.barrelWidth / clientFovMultiplier) * 1.5, (thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / 1.5 / clientFovMultiplier ); }; ctx.fillRect( (-thisBarrel.barrelWidth * 1.5) / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier, (thisBarrel.barrelWidth / clientFovMultiplier) * 1.5, (thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) /5/ clientFovMultiplier ); if (CRTP != 'simplistic') { ctx.strokeRect( (-thisBarrel.barrelWidth * 1.5) / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier, (thisBarrel.barrelWidth / clientFovMultiplier) * 1.5, (thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) /5 /clientFovMultiplier ); }; } ctx.beginPath(); ctx.arc( 0, 0, thisBarrel.barrelWidth / clientFovMultiplier, 0, 2 * Math.PI ); ctx.fill(); if (CRTP != 'simplistic') { ctx.stroke(); }; ctx.rotate(-thisBarrel.additionalAngle); //rotate back }); } ctx.restore(); } if (object.hasOwnProperty("deadOpacity")) { //if this is an animation of a dead object ctx.globalAlpha = 1.0; //reset opacity } if (showHitBox == "yes") { //draw hitbox ctx.strokeStyle = "blue"; ctx.lineWidth = 3; ctx.beginPath(); ctx.arc( drawingX, drawingY, object.width / clientFovMultiplier, 0, 2 * Math.PI ); ctx.stroke(); } } else if (object.type == "bot") { //draw bot if (object.hasOwnProperty("deadOpacity")) { //if this is an animation of a dead object ctx.globalAlpha = object.deadOpacity; } ctx.lineWidth = 4 / clientFovMultiplier; ctx.lineJoin = "round"; //prevent spikes above the capital letter "M" ctx.save(); ctx.translate(drawingX, drawingY); ctx.rotate(object.angle); //draw barrels if (object.name!="Pillbox"){//pillbox's barrel is visually a turret Object.keys(object.barrels).forEach((barrel) => { let thisBarrel = object.barrels[barrel]; ctx.rotate(((thisBarrel.additionalAngle + 90) * Math.PI) / 180); //rotate to barrel angle ctx.fillStyle = bodyColors.barrel.col; ctx.strokeStyle = bodyColors.barrel.outline; if (thisBarrel.barrelType == "bullet") { ctx.fillRect( -thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier, thisBarrel.barrelWidth / clientFovMultiplier, (thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier ); if (CRTP != 'simplistic') { ctx.strokeRect( -thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier, thisBarrel.barrelWidth / clientFovMultiplier, (thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier ); }; } //drone barrel else if (thisBarrel.barrelType == "drone") { ctx.beginPath(); ctx.moveTo( -thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, 0 ); ctx.lineTo( -thisBarrel.barrelWidth / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier ); ctx.lineTo( thisBarrel.barrelWidth / clientFovMultiplier + (thisBarrel.x * 2) / clientFovMultiplier, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier ); ctx.lineTo( thisBarrel.barrelWidth / 2 / clientFovMultiplier + (thisBarrel.x * 2) / clientFovMultiplier, 0 ); ctx.fill(); if (CRTP != 'simplistic') { ctx.stroke(); }; } //trap barrel else if (thisBarrel.barrelType == "trap") { ctx.fillRect( -thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, ((-(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / 3) * 2) / clientFovMultiplier, thisBarrel.barrelWidth / clientFovMultiplier, (((thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / 3) * 2) / clientFovMultiplier ); if (CRTP != 'simplistic') { ctx.strokeRect( -thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, ((-(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / 3) * 2) / clientFovMultiplier, thisBarrel.barrelWidth / clientFovMultiplier, (((thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / 3) * 2) / clientFovMultiplier ); }; ctx.beginPath(); ctx.moveTo( -thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, ((-(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / 3) * 2) / clientFovMultiplier ); ctx.lineTo( -thisBarrel.barrelWidth / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier ); ctx.lineTo( thisBarrel.barrelWidth / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier ); ctx.lineTo( thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, ((-(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / 3) * 2) / clientFovMultiplier ); ctx.fill(); if (CRTP != 'simplistic') { ctx.stroke(); }; } //mine barrel else if (thisBarrel.barrelType == "mine") { ctx.fillRect( -thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, ((-(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / 3) * 2) / clientFovMultiplier, thisBarrel.barrelWidth / clientFovMultiplier, (((thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / 3) * 2) / clientFovMultiplier ); if (CRTP != 'simplistic') { ctx.strokeRect( -thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, ((-(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / 3) * 2) / clientFovMultiplier, thisBarrel.barrelWidth / clientFovMultiplier, (((thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / 3) * 2) / clientFovMultiplier ); }; ctx.beginPath(); ctx.moveTo( -thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, ((-(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / 3) * 2) / clientFovMultiplier ); ctx.lineTo( -thisBarrel.barrelWidth / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier ); ctx.lineTo( thisBarrel.barrelWidth / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier ); ctx.lineTo( thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, ((-(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / 3) * 2) / clientFovMultiplier ); ctx.fill(); if (CRTP != 'simplistic') { ctx.stroke(); }; } //minion barrel else if (thisBarrel.barrelType == "minion") { ctx.fillRect( -thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier, thisBarrel.barrelWidth / clientFovMultiplier, (thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier ); if (CRTP != 'simplistic') { ctx.strokeRect( -thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier, thisBarrel.barrelWidth / clientFovMultiplier, (thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier ); }; ctx.fillRect( (-thisBarrel.barrelWidth * 1.5) / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / 1.5 / clientFovMultiplier, (thisBarrel.barrelWidth / clientFovMultiplier) * 1.5, (thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / 1.5 / clientFovMultiplier ); if (CRTP != 'simplistic') { ctx.strokeRect( (-thisBarrel.barrelWidth * 1.5) / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / 1.5 / clientFovMultiplier, (thisBarrel.barrelWidth / clientFovMultiplier) * 1.5, (thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / 1.5 / clientFovMultiplier ); }; ctx.fillRect( (-thisBarrel.barrelWidth * 1.5) / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier, (thisBarrel.barrelWidth / clientFovMultiplier) * 1.5, (thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) /5/ clientFovMultiplier ); if (CRTP != 'simplistic') { ctx.strokeRect( (-thisBarrel.barrelWidth * 1.5) / 2 / clientFovMultiplier + thisBarrel.x / clientFovMultiplier, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier, (thisBarrel.barrelWidth / clientFovMultiplier) * 1.5, (thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) /5 /clientFovMultiplier ); }; } ctx.rotate((-(thisBarrel.additionalAngle + 90) * Math.PI) / 180); //rotate back }); } if (object.name=="Cluster"){ //draw the spawning barrels let barrelwidth = object.width*0.7; let barrelheight = object.width*1.2; ctx.fillStyle = bodyColors.barrel.col; ctx.strokeStyle = bodyColors.barrel.outline; ctx.save(); ctx.rotate(90 * Math.PI / 180); for (let i = 0; i < 5; i++){ if (i!=0){ ctx.rotate(72 * Math.PI / 180); //rotate 72 for each barrel } ctx.beginPath(); ctx.moveTo( -barrelwidth / 5 / clientFovMultiplier, 0 ); ctx.lineTo( -barrelwidth / clientFovMultiplier, -barrelheight / clientFovMultiplier ); ctx.lineTo( barrelwidth / clientFovMultiplier, -barrelheight / clientFovMultiplier ); ctx.lineTo( barrelwidth / 5 / clientFovMultiplier, 0 ); ctx.fill(); if (CRTP != 'simplistic') { ctx.stroke(); }; } ctx.restore(); } else if (object.name=="Infestor"){ //draw the spawning barrels let barrelwidth = object.width*0.7; let barrelheight = object.width*1.2; ctx.fillStyle = bodyColors.barrel.col; ctx.strokeStyle = bodyColors.barrel.outline; ctx.save(); for (let i = 0; i < 4; i++){//normal barrels if (i!=0){ ctx.rotate(90 * Math.PI / 180); } ctx.fillRect( -barrelwidth / 2 / clientFovMultiplier, -barrelheight / clientFovMultiplier, barrelwidth / clientFovMultiplier, barrelheight / clientFovMultiplier ); if (CRTP != 'simplistic') { ctx.strokeRect( -barrelwidth / 2 / clientFovMultiplier, -barrelheight / clientFovMultiplier, barrelwidth / clientFovMultiplier, barrelheight / clientFovMultiplier ); }; } ctx.restore(); ctx.save(); ctx.rotate(45 * Math.PI / 180); barrelwidth = object.width*0.6; barrelheight = object.width*2; for (let i = 0; i < 4; i++){//traplike barrels if (i!=0){ ctx.rotate(90 * Math.PI / 180); } ctx.fillRect( -barrelwidth / 2 / clientFovMultiplier, -barrelheight * 0.55 / clientFovMultiplier, barrelwidth / clientFovMultiplier, barrelheight * 0.5 / clientFovMultiplier ); if (CRTP != 'simplistic') { ctx.strokeRect( -barrelwidth / 2 / clientFovMultiplier, -barrelheight * 0.55 / clientFovMultiplier, barrelwidth / clientFovMultiplier, barrelheight * 0.5 / clientFovMultiplier ); }; ctx.beginPath(); ctx.moveTo( -barrelwidth / 2 / clientFovMultiplier, -barrelheight * 0.55 / clientFovMultiplier ); ctx.lineTo( -barrelwidth/1.7 / clientFovMultiplier, -barrelheight * 0.65 / clientFovMultiplier ); ctx.lineTo( barrelwidth/1.7 / clientFovMultiplier, -barrelheight * 0.65 / clientFovMultiplier ); ctx.lineTo( barrelwidth / 2 / clientFovMultiplier, -barrelheight * 0.55 / clientFovMultiplier ); ctx.fill(); if (CRTP != 'simplistic') { ctx.stroke(); }; } ctx.restore(); } else if (object.name=="Champion"){ //draw spikes var numberOfSpikes = 5; var outerRadius = object.width / clientFovMultiplier * 1.3; var innerRadius = object.width / clientFovMultiplier /1.3; var rot = (Math.PI / 2) * 3;//dont change this, or else will have strange extra lines var x = 0; var y = 0; ctx.fillStyle = bodyColors.barrel.col; ctx.strokeStyle = bodyColors.barrel.outline; ctx.save(); ctx.rotate(90 * Math.PI / 180); ctx.beginPath(); ctx.moveTo(0, 0 - outerRadius); for (i = 0; i < numberOfSpikes; i++) { x = 0 + Math.cos(rot) * outerRadius; y = 0 + Math.sin(rot) * outerRadius; ctx.lineTo(x, y); rot += Math.PI / numberOfSpikes; x = 0 + Math.cos(rot) * innerRadius; y = 0 + Math.sin(rot) * innerRadius; ctx.lineTo(x, y); rot += Math.PI / numberOfSpikes; } ctx.lineTo(0, 0 - outerRadius); ctx.closePath(); ctx.fill(); if (CRTP != 'simplistic') { ctx.stroke(); }; ctx.restore(); } var chooseflash = 3; if (object.hit > 0) { //if shape is hit, choose whether it's color is white or original color to create flashing effect chooseflash = Math.floor(Math.random() * 3); //random number 0, 1 or 2 } if (chooseflash == 0) { ctx.fillStyle = "white"; } else if (chooseflash == 1) { ctx.fillStyle = "pink"; } else { ctx.fillStyle = botcolors[object.name].color; } ctx.strokeStyle = botcolors[object.name].outline; //draw body if (object.side==0) { //draw circle ctx.beginPath(); ctx.arc(0, 0, object.width / clientFovMultiplier, 0, 2 * Math.PI); ctx.fill(); ctx.stroke(); } else if (object.side>=0) { if (object.hasOwnProperty('randomPointsArrayX')){ //draw for rock and boulder //POLYGON WITH IRREGULAR SIDES ctx.rotate(-object.angle); //rotate back so that rock wont rotate to face you var rockSides = object.side; ctx.beginPath(); ctx.moveTo( 0 + (object.width / clientFovMultiplier) * Math.cos(0), 0 + (object.width / clientFovMultiplier) * Math.sin(0) ); for (var i = 1; i <= rockSides; i += 1) { var XRandom = object.randomPointsArrayX[i - 1]; var YRandom = object.randomPointsArrayY[i - 1]; ctx.lineTo(XRandom + (object.width / clientFovMultiplier) * Math.cos((i * 2 * Math.PI) / rockSides), YRandom + (object.width / clientFovMultiplier) * Math.sin((i * 2 * Math.PI) / rockSides) ); } ctx.fill(); ctx.stroke(); } else{//normal spawner if (object.name=="Cluster"||object.name=="Pursuer"||object.name=="Champion"||object.name=="Infestor"){ //need to rotate 72/2 degrees so that pentagon not facing vertex towards player ctx.rotate(Math.PI/object.side);//2 PI / sides / 2 } ctx.beginPath(); ctx.moveTo((object.width / clientFovMultiplier), 0); for (var i = 1; i <= object.side + 1; i += 1) { ctx.lineTo( (object.width / clientFovMultiplier) * Math.cos((i * 2 * Math.PI) / object.side), (object.width / clientFovMultiplier) * Math.sin((i * 2 * Math.PI) / object.side) ); } ctx.fill(); if (CRTP != 'simplistic') { ctx.stroke(); }; if (object.name=="Cluster"||object.name=="Pursuer"){ ctx.rotate(-Math.PI/object.side);//rotate back //draw circle on top ctx.fillStyle = bodyColors.barrel.col;//light grey ctx.strokeStyle = bodyColors.barrel.outline; ctx.beginPath(); ctx.arc(0, 0, object.width/2 / clientFovMultiplier, 0, 2 * Math.PI); ctx.fill(); if (CRTP != 'simplistic') { ctx.stroke(); }; } else if (object.name=="Champion"){ ctx.rotate(-Math.PI/object.side);//rotate back //draw circle on top ctx.fillStyle = "grey";//darker grey ctx.strokeStyle = "#5e5e5e"; ctx.beginPath(); ctx.arc(0, 0, object.width/2.5 / clientFovMultiplier, 0, 2 * Math.PI); ctx.fill(); if (CRTP != 'simplistic') { ctx.stroke(); }; } else if (object.name=="Infestor"){ ctx.rotate(-Math.PI/object.side);//rotate back //draw circle on top ctx.fillStyle = bodyColors.barrel.col;//light grey ctx.strokeStyle = bodyColors.barrel.outline; ctx.beginPath(); ctx.arc(0, 0, object.width/5 / clientFovMultiplier, 0, 2 * Math.PI); ctx.fill(); if (CRTP != 'simplistic') { ctx.stroke(); }; } else if (object.name=="Leech"){ //draw circle on top ctx.fillStyle = bodyColors.barrel.col;//light grey ctx.strokeStyle = bodyColors.barrel.outline; ctx.beginPath(); ctx.arc(0, 0, object.width/2 / clientFovMultiplier, 0, 2 * Math.PI); ctx.fill(); if (CRTP != 'simplistic') { ctx.stroke(); }; } else if (object.name=="Pillbox"){//pillbox's barrel is visually a turret ctx.lineJoin = "round"; //make nice round corners ctx.rotate(90 * Math.PI / 180); Object.keys(object.barrels).forEach((barrel) => { //note that you must use [barrel] instead of .barrel, if not there will be an error let thisBarrel = object.barrels[barrel]; ctx.fillStyle = bodyColors.barrel.col; ctx.strokeStyle = bodyColors.barrel.outline; ctx.fillRect( -thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier, thisBarrel.barrelWidth / clientFovMultiplier, (thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier ); if (CRTP != 'simplistic') { ctx.strokeRect( -thisBarrel.barrelWidth / 2 / clientFovMultiplier + thisBarrel.x, -(thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier, thisBarrel.barrelWidth / clientFovMultiplier, (thisBarrel.barrelHeight - thisBarrel.barrelHeightChange) / clientFovMultiplier ); }; }); ctx.rotate(-90 * Math.PI / 180); //draw turret base ctx.beginPath(); ctx.arc( 0, 0, (object.width / clientFovMultiplier) * 0.6, 0, 2 * Math.PI ); ctx.fill(); if (CRTP != 'simplistic') { ctx.stroke(); }; ctx.lineJoin = "miter"; //change back } } } else{//negative sides, draw a star! (cactus) var numberOfSpikes = -object.side; var outerRadius = object.width / clientFovMultiplier * 1.5; var innerRadius = object.width / clientFovMultiplier; var rot = (Math.PI / 2) * 3;//dont change this, or else will have strange extra lines var x = 0; var y = 0; ctx.rotate(-object.angle); //rotate back so that rock wont rotate to face you ctx.beginPath(); ctx.moveTo(0, 0 - outerRadius); for (i = 0; i < numberOfSpikes; i++) { x = 0 + Math.cos(rot) * outerRadius; y = 0 + Math.sin(rot) * outerRadius; ctx.lineTo(x, y); rot += Math.PI / numberOfSpikes; x = 0 + Math.cos(rot) * innerRadius; y = 0 + Math.sin(rot) * innerRadius; ctx.lineTo(x, y); rot += Math.PI / numberOfSpikes; } ctx.lineTo(0, 0 - outerRadius); ctx.closePath(); ctx.fill(); if (CRTP != 'simplistic') { ctx.stroke(); }; } ctx.restore(); if (object.health < object.maxhealth) { //draw health bar background var w = (object.width * 2) / clientFovMultiplier; var h = 7 / clientFovMultiplier; var r = h / 2; var x = drawingX - object.width / clientFovMultiplier; var y = drawingY + object.width / clientFovMultiplier + 10; ctx.fillStyle = "black"; ctx.strokeStyle = "black"; ctx.lineWidth = 2.5 / clientFovMultiplier; ctx.beginPath(); ctx.moveTo(x + r, y); ctx.arcTo(x + w, y, x + w, y + h, r); ctx.arcTo(x + w, y + h, x, y + h, r); ctx.arcTo(x, y + h, x, y, r); ctx.arcTo(x, y, x + w, y, r); ctx.closePath(); ctx.fill(); ctx.stroke(); //draw health bar if (object.health > 0) { w = (w / object.maxhealth) * object.health; if (r * 2 > w) { //prevent weird shape when radius more than width r = w / 2; y += (h - w) / 2; //move health bar so that it is centered vertically in black bar h = w; } ctx.fillStyle = botcolors[object.name].color; ctx.beginPath(); ctx.moveTo(x + r, y); ctx.arcTo(x + w, y, x + w, y + h, r); ctx.arcTo(x + w, y + h, x, y + h, r); ctx.arcTo(x, y + h, x, y, r); ctx.arcTo(x, y, x + w, y, r); ctx.closePath(); ctx.fill(); ctx.stroke(); } } ctx.fillStyle = "white"; ctx.strokeStyle = "black"; ctx.lineWidth = 5 / clientFovMultiplier; ctx.font = "700 " + 20 / clientFovMultiplier + "px Roboto"; ctx.textAlign = "center"; ctx.lineJoin = "round"; //prevent spikes above the capital letter "M" //note: if you stroke then fill, the words will be thicker and nicer. If you fill then stroke, the words are thinner. if ((showStaticMobName == "yes"||botcolors[object.name].static=="no") && (showMinionMobName == "yes"||botcolors[object.name].minion=="no")){//settings for showing static and minion names if (botcolors[object.name].specialty != "") { var specialtyText = " (" + botcolors[object.name].specialty + ")"; } else { var specialtyText = ""; } ctx.strokeText( object.name + specialtyText, drawingX, drawingY - object.width / clientFovMultiplier - 10 ); ctx.fillText( object.name + specialtyText, drawingX, drawingY - object.width / clientFovMultiplier - 10 ); } ctx.lineJoin = "miter"; //prevent spikes above the capital letter "M" if (object.hasOwnProperty("deadOpacity")) { //if this is an animation of a dead object ctx.globalAlpha = 1.0; //reset opacity } if (showHitBox == "yes") { //draw hitbox ctx.strokeStyle = "blue"; ctx.lineWidth = 3; ctx.beginPath(); ctx.arc( drawingX, drawingY, object.width / clientFovMultiplier, 0, 2 * Math.PI ); ctx.stroke(); } } else if (object.type == "shape") { if (object.hasOwnProperty("deadOpacity")) { //if this is an animation of a dead object ctx.globalAlpha = object.deadOpacity; } var radiantAuraSize = document.getElementById("sizevalue").innerHTML * auraWidth; //aura size determined by settings, but default is 5 //draw shape ctx.save(); ctx.translate(drawingX, drawingY); ctx.rotate((object.angle * Math.PI) / 180); if (object.hasOwnProperty("radtier")) { //radiant shape if (!radiantShapes.hasOwnProperty(id)) { var randomstate = Math.floor(Math.random() * 3); //randomly choose a color state for the radiant shape to start (if not when you spawn in cavern, all shapes same color) var randomtype = Math.floor(Math.random() * 2) + 1; //choose animation color type (1 or 2) if (randomtype == 1) { if (randomstate == 0) { radiantShapes[id] = { red: 255, blue: 0, green: 0, rgbstate: 1, radtype: randomtype, }; //keep track of radiant shape colors (done in client code) } else if (randomstate == 1) { radiantShapes[id] = { red: 199, blue: 0, green: 150, rgbstate: 2, radtype: randomtype, }; } else if (randomstate == 2) { radiantShapes[id] = { red: -1, blue: 200, green: 0, rgbstate: 3, radtype: randomtype, }; } } else { if (randomstate == 0) { radiantShapes[id] = { red: 118, blue: 168, green: 151, rgbstate: 1, radtype: randomtype, }; } else if (randomstate == 1) { radiantShapes[id] = { red: 209, blue: 230, green: 222, rgbstate: 2, radtype: randomtype, }; } else if (randomstate == 2) { radiantShapes[id] = { red: 234, blue: 240, green: 180, rgbstate: 3, radtype: randomtype, }; } } } object.red = radiantShapes[id].red; object.blue = radiantShapes[id].blue; object.green = radiantShapes[id].green; } if (object.hasOwnProperty("red")) { //calculate color of spikes, which would be 20 higher than actual rgb value if (object.red + 150 <= 255) { var spikeRed = object.red + 150; } else { var spikeRed = 255; } if (object.blue + 150 <= 255) { var spikeBlue = object.blue + 150; } else { var spikeBlue = 255; } if (object.green + 150 <= 255) { var spikeGreen = object.green + 150; } else { var spikeGreen = 255; } if (object.radtier == 3) { //for high rarity radiant shapes, draw spikes ctx.rotate((extraSpikeRotate * Math.PI) / 180); ctx.fillStyle = "rgba(" + spikeRed + ", " + spikeGreen + ", " + spikeBlue + ", 0.7)"; ctx.strokeStyle = "rgba(" + spikeRed + ", " + spikeGreen + ", " + spikeBlue + ", 0.3)"; var numberOfSpikes = 6; var outerRadius = ((object.width * radiantAuraSize * 3) / clientFovMultiplier) * 0.75; var innerRadius = (object.width / clientFovMultiplier) * 0.75; var rot = (Math.PI / 2) * 3; var x = 0; var y = 0; ctx.beginPath(); ctx.moveTo(0, 0 - outerRadius); for (i = 0; i < numberOfSpikes; i++) { x = 0 + Math.cos(rot) * outerRadius; y = 0 + Math.sin(rot) * outerRadius; ctx.lineTo(x, y); rot += Math.PI / numberOfSpikes; x = 0 + Math.cos(rot) * innerRadius; y = 0 + Math.sin(rot) * innerRadius; ctx.lineTo(x, y); rot += Math.PI / numberOfSpikes; } ctx.lineTo(0, 0 - outerRadius); ctx.closePath(); ctx.lineWidth = 3 / clientFovMultiplier; ctx.fill(); ctx.stroke(); ctx.rotate((-extraSpikeRotate * Math.PI) / 180); } else if (object.radtier == 4) { //for high rarity radiant shapes, draw spikes ctx.rotate((extraSpikeRotate1 * Math.PI) / 180); ctx.fillStyle = "rgba(" + spikeRed + ", " + spikeGreen + ", " + spikeBlue + ", 0.7)"; ctx.strokeStyle = "rgba(" + spikeRed + ", " + spikeGreen + ", " + spikeBlue + ", 0.3)"; var numberOfSpikes = 3; var outerRadius = (object.width * radiantAuraSize * 3) / clientFovMultiplier; var innerRadius = (object.width / clientFovMultiplier) * 0.5; var rot = (Math.PI / 2) * 3; var x = 0; var y = 0; ctx.beginPath(); ctx.moveTo(0, 0 - outerRadius); for (i = 0; i < numberOfSpikes; i++) { x = 0 + Math.cos(rot) * outerRadius; y = 0 + Math.sin(rot) * outerRadius; ctx.lineTo(x, y); rot += Math.PI / numberOfSpikes; x = 0 + Math.cos(rot) * innerRadius; y = 0 + Math.sin(rot) * innerRadius; ctx.lineTo(x, y); rot += Math.PI / numberOfSpikes; } ctx.lineTo(0, 0 - outerRadius); ctx.closePath(); ctx.lineWidth = 3 / clientFovMultiplier; ctx.fill(); ctx.stroke(); ctx.rotate((-extraSpikeRotate1 * Math.PI) / 180); ctx.rotate((extraSpikeRotate2 * Math.PI) / 180); var numberOfSpikes = 6; var outerRadius = ((object.width * radiantAuraSize * 3) / clientFovMultiplier) * 0.5; var innerRadius = (object.width / clientFovMultiplier) * 0.5; var rot = (Math.PI / 2) * 3; var x = 0; var y = 0; ctx.beginPath(); ctx.moveTo(0, 0 - outerRadius); for (i = 0; i < numberOfSpikes; i++) { x = 0 + Math.cos(rot) * outerRadius; y = 0 + Math.sin(rot) * outerRadius; ctx.lineTo(x, y); rot += Math.PI / numberOfSpikes; x = 0 + Math.cos(rot) * innerRadius; y = 0 + Math.sin(rot) * innerRadius; ctx.lineTo(x, y); rot += Math.PI / numberOfSpikes; } ctx.lineTo(0, 0 - outerRadius); ctx.closePath(); ctx.lineWidth = 3 / clientFovMultiplier; ctx.fill(); ctx.stroke(); ctx.rotate((-extraSpikeRotate2 * Math.PI) / 180); } else if (object.radtier == 5) { //for high rarity radiant shapes, draw spikes ctx.rotate((extraSpikeRotate1 * Math.PI) / 180); ctx.fillStyle = "rgba(" + spikeRed + ", " + spikeGreen + ", " + spikeBlue + ", 0.7)"; ctx.strokeStyle = "rgba(" + spikeRed + ", " + spikeGreen + ", " + spikeBlue + ", 0.3)"; var numberOfSpikes = 3; var outerRadius = ((object.width * radiantAuraSize * 3) / clientFovMultiplier) * 1.5; var innerRadius = (object.width / clientFovMultiplier) * 0.5; var rot = (Math.PI / 2) * 3; var x = 0; var y = 0; ctx.beginPath(); ctx.moveTo(0, 0 - outerRadius); for (i = 0; i < numberOfSpikes; i++) { x = 0 + Math.cos(rot) * outerRadius; y = 0 + Math.sin(rot) * outerRadius; ctx.lineTo(x, y); rot += Math.PI / numberOfSpikes; x = 0 + Math.cos(rot) * innerRadius; y = 0 + Math.sin(rot) * innerRadius; ctx.lineTo(x, y); rot += Math.PI / numberOfSpikes; } ctx.lineTo(0, 0 - outerRadius); ctx.closePath(); ctx.lineWidth = 3 / clientFovMultiplier; ctx.fill(); ctx.stroke(); ctx.rotate((-extraSpikeRotate1 * Math.PI) / 180); ctx.rotate((extraSpikeRotate2 * Math.PI) / 180); var numberOfSpikes = 3; var outerRadius = ((object.width * radiantAuraSize * 3) / clientFovMultiplier) * 0.5; var innerRadius = (object.width / clientFovMultiplier) * 0.5; var rot = (Math.PI / 2) * 3; var x = 0; var y = 0; ctx.beginPath(); ctx.moveTo(0, 0 - outerRadius); for (i = 0; i < numberOfSpikes; i++) { x = 0 + Math.cos(rot) * outerRadius; y = 0 + Math.sin(rot) * outerRadius; ctx.lineTo(x, y); rot += Math.PI / numberOfSpikes; x = 0 + Math.cos(rot) * innerRadius; y = 0 + Math.sin(rot) * innerRadius; ctx.lineTo(x, y); rot += Math.PI / numberOfSpikes; } ctx.lineTo(0, 0 - outerRadius); ctx.closePath(); ctx.lineWidth = 3 / clientFovMultiplier; ctx.fill(); ctx.stroke(); ctx.rotate((-extraSpikeRotate2 * Math.PI) / 180); } //if shape is radiant //draw aura //old code where aura was a gradient /* const gradient = ctx.createRadialGradient(0, 0, object.width/clientFovMultiplier, 0, 0, object.width/clientFovMultiplier*radiantAuraSize); gradient.addColorStop(0, 'rgba(' + object.red + ', ' + object.green + ', ' + object.blue + ', 0.3)'); gradient.addColorStop(0.5, 'rgba(' + object.red + ', ' + object.green + ', ' + object.blue + ', 0.1)'); gradient.addColorStop(1, 'rgba(' + object.red + ', ' + object.green + ', ' + object.blue + ', 0.0)'); ctx.fillStyle = gradient; ctx.beginPath(); */ //old code where aura have shape ctx.fillStyle = "rgba(" + object.red + ", " + object.green + ", " + object.blue + ", 0.3)"; ctx.strokeStyle = "rgba(" + object.red + ", " + object.green + ", " + object.blue + ", 0.3)"; ctx.lineWidth = 3 / clientFovMultiplier; ctx.beginPath(); var shapeaurasize = object.radtier; if (shapeaurasize > 3) { shapeaurasize = 3; //prevent huge auras } ctx.moveTo( 0 + ((object.width * radiantAuraSize * shapeaurasize) / clientFovMultiplier) * Math.cos(0), 0 + ((object.width * radiantAuraSize * shapeaurasize) / clientFovMultiplier) * Math.sin(0) ); for (var i = 1; i <= object.sides + 1; i += 1) { ctx.lineTo( 0 + ((object.width * radiantAuraSize * shapeaurasize) / clientFovMultiplier) * Math.cos((i * 2 * Math.PI) / object.sides), 0 + ((object.width * radiantAuraSize * shapeaurasize) / clientFovMultiplier) * Math.sin((i * 2 * Math.PI) / object.sides) ); } //ctx.arc(0, 0, object.width/clientFovMultiplier*radiantAuraSize, 0, 2 * Math.PI); ctx.fill(); ctx.stroke(); var shadeFactor = 3 / 4; //smaller the value, darker the shade ctx.strokeStyle = "rgb(" + object.red * shadeFactor + ", " + object.green * shadeFactor + ", " + object.blue * shadeFactor + ")"; ctx.fillStyle = "rgb(" + object.red + ", " + object.green + ", " + object.blue + ")"; if (object.hit > 0) { //if shape is hit ctx.strokeStyle = "rgb(" + (object.red * shadeFactor + 20) + ", " + (object.green * shadeFactor + 20) + ", " + (object.blue * shadeFactor + 20) + ")"; ctx.fillStyle = "rgb(" + (object.red + 20) + ", " + (object.green + 20) + ", " + (object.blue + 20) + ")"; } //choose whether a particle would spawn //particle spawn chance based on number of sides the shape has, so square has less particles if (spawnradparticle == "yes"){ var chooseValue = 20 - object.sides * 2; //lower the number means more particles spawned if (chooseValue < 5) { //5 refers to mimimum particle spawn chance chooseValue = 5; } var choosing = Math.floor(Math.random() * chooseValue); //choose if particle spawn if (choosing == 1) { //spawn a particle var angleDegrees = Math.floor(Math.random() * 360); //choose angle in degrees var angleRadians = (angleDegrees * Math.PI) / 180; //convert to radians var randomDistFromCenter = Math.floor(Math.random() * object.width * 2) - object.width; radparticles[particleID] = { angle: angleRadians, x: object.x + randomDistFromCenter * Math.cos(angleRadians), y: object.y + randomDistFromCenter * Math.sin(angleRadians), width: 5, height: 5, speed: 1, timer: 50, maxtimer: 50, color: "rgba(" + object.red + "," + object.green + "," + object.blue + ",.5)", outline: "rgba(" + (object.red* shadeFactor + 20) + "," + (object.green* shadeFactor + 20) + "," + (object.blue* shadeFactor + 20) + ",.5)", type: "particle", }; particleID++; } } } else { //if not radiant //get shape colors in client code based on theme ctx.fillStyle = shapecolors[object.sides][colortheme].color; ctx.strokeStyle = shapecolors[object.sides][colortheme].outline; if (object.hit > 0) { //if shape is hit ctx.fillStyle = shapecolors[object.sides][colortheme].hitcolor; ctx.strokeStyle = shapecolors[object.sides][colortheme].hitoutline; } } ctx.lineJoin = "round"; //make corners of shape round if (object.sides == "star") { //draw a star var numberOfSpikes = 5; var outerRadius = object.width / clientFovMultiplier; var innerRadius = (object.width / clientFovMultiplier / 3) * 2; var rot = (Math.PI / 2) * 3; var x = 0; var y = 0; ctx.beginPath(); ctx.moveTo(0, 0 - outerRadius); for (i = 0; i < numberOfSpikes; i++) { x = 0 + Math.cos(rot) * outerRadius; y = 0 + Math.sin(rot) * outerRadius; ctx.lineTo(x, y); rot += Math.PI / numberOfSpikes; x = 0 + Math.cos(rot) * innerRadius; y = 0 + Math.sin(rot) * innerRadius; ctx.lineTo(x, y); rot += Math.PI / numberOfSpikes; } ctx.lineTo(0, 0 - outerRadius); ctx.closePath(); ctx.lineWidth = 4 / clientFovMultiplier; ctx.fill(); ctx.stroke(); } else { ctx.lineWidth = 4 / clientFovMultiplier; ctx.beginPath(); ctx.moveTo( 0 + (object.width / clientFovMultiplier) * Math.cos(0), 0 + (object.width / clientFovMultiplier) * Math.sin(0) ); for (var i = 1; i <= object.sides + 1; i += 1) { ctx.lineTo( 0 + (object.width / clientFovMultiplier) * Math.cos((i * 2 * Math.PI) / object.sides), 0 + (object.width / clientFovMultiplier) * Math.sin((i * 2 * Math.PI) / object.sides) ); } ctx.fill(); ctx.stroke(); } ctx.lineJoin = "miter"; //change back to default ctx.restore(); //must restore to reset angle rotation so health bar wont be rotated sideways //draw shape's health bar if (object.health < object.maxhealth) { //draw health bar background var w = (object.width / clientFovMultiplier) * 2; var h = 7 / clientFovMultiplier; var r = h / 2; var x = drawingX - object.width / clientFovMultiplier; var y = drawingY + object.width / clientFovMultiplier + 10; ctx.fillStyle = "black"; ctx.strokeStyle = "black"; ctx.lineWidth = 2.5 / clientFovMultiplier;//determines with of black area ctx.beginPath(); ctx.moveTo(x + r, y); ctx.arcTo(x + w, y, x + w, y + h, r); ctx.arcTo(x + w, y + h, x, y + h, r); ctx.arcTo(x, y + h, x, y, r); ctx.arcTo(x, y, x + w, y, r); ctx.closePath(); ctx.fill(); ctx.stroke(); //draw health bar if (object.health > 0) { //dont draw health bar if negative health w = (w / object.maxhealth) * object.health; if (r * 2 > w) { //prevent weird shape when radius more than width r = w / 2; y += (h - w) / 2; //move health bar so that it is centered vertically in black bar h = w; } if (object.hasOwnProperty("red")) { //if shape is radiant ctx.fillStyle = "rgb(" + object.red + ", " + object.green + ", " + object.blue + ")"; } else { ctx.fillStyle = shapecolors[object.sides][colortheme].color; if (object.sides==10||object.sides==11||object.sides==14){//these shapes are very dark, cannot see health bar ctx.fillStyle = shapecolors[12][colortheme].color;//use ddecagon's grey color for health bar } } ctx.beginPath(); ctx.moveTo(x + r, y); ctx.arcTo(x + w, y, x + w, y + h, r); ctx.arcTo(x + w, y + h, x, y + h, r); ctx.arcTo(x, y + h, x, y, r); ctx.arcTo(x, y, x + w, y, r); ctx.closePath(); ctx.fill(); ctx.stroke(); } } if (object.hasOwnProperty("deadOpacity")) { //if this is an animation of a dead object ctx.globalAlpha = 1.0; //reset opacity } if (showHitBox == "yes") { //draw hitbox ctx.strokeStyle = "blue"; ctx.lineWidth = 3; ctx.beginPath(); ctx.arc( drawingX, drawingY, object.width / clientFovMultiplier, 0, 2 * Math.PI ); ctx.stroke(); } } else if (object.type == "spawner") { //spawner in sanctuary ctx.save(); ctx.translate(drawingX, drawingY); ctx.rotate(object.angle); ctx.lineJoin = "round"; //make corners of shape round //actual body ctx.fillStyle = object.baseColor; ctx.strokeStyle = object.baseOutline; ctx.beginPath(); ctx.moveTo( 0 + (object.basewidth6 / clientFovMultiplier) * Math.cos(0), 0 + (object.basewidth6 / clientFovMultiplier) * Math.sin(0) ); for (var i = 1; i <= object.sides + 1; i += 1) { ctx.lineTo( 0 + (object.basewidth6 / clientFovMultiplier) * Math.cos((i * 2 * Math.PI) / object.sides), 0 + (object.basewidth6 / clientFovMultiplier) * Math.sin((i * 2 * Math.PI) / object.sides) ); } ctx.fill(); if (CRTP != 'simplistic') { ctx.stroke(); }; ctx.fillStyle = object.color; ctx.strokeStyle = object.outline; ctx.beginPath(); ctx.moveTo( 0 + (object.width / clientFovMultiplier) * Math.cos(0), 0 + (object.width / clientFovMultiplier) * Math.sin(0) ); for (var i = 1; i <= object.sides + 1; i += 1) { ctx.lineTo( 0 + (object.width / clientFovMultiplier) * Math.cos((i * 2 * Math.PI) / object.sides), 0 + (object.width / clientFovMultiplier) * Math.sin((i * 2 * Math.PI) / object.sides) ); } ctx.fill(); if (CRTP != 'simplistic') { ctx.stroke(); }; ctx.fillStyle = object.baseColor; ctx.strokeStyle = object.baseOutline; ctx.beginPath(); ctx.moveTo( 0 + (object.basewidth4 / clientFovMultiplier) * Math.cos(0), 0 + (object.basewidth4 / clientFovMultiplier) * Math.sin(0) ); for (var i = 1; i <= object.sides + 1; i += 1) { ctx.lineTo( 0 + (object.basewidth4 / clientFovMultiplier) * Math.cos((i * 2 * Math.PI) / object.sides), 0 + (object.basewidth4 / clientFovMultiplier) * Math.sin((i * 2 * Math.PI) / object.sides) ); } ctx.fill(); if (CRTP != 'simplistic') { ctx.stroke(); }; ctx.fillStyle = object.color; ctx.strokeStyle = object.outline; ctx.lineWidth = 4 / clientFovMultiplier; ctx.beginPath(); ctx.moveTo( 0 + (object.basewidth5 / clientFovMultiplier) * Math.cos(0), 0 + (object.basewidth5 / clientFovMultiplier) * Math.sin(0) ); for (var i = 1; i <= object.sides + 1; i += 1) { ctx.lineTo( 0 + (object.basewidth5 / clientFovMultiplier) * Math.cos((i * 2 * Math.PI) / object.sides), 0 + (object.basewidth5 / clientFovMultiplier) * Math.sin((i * 2 * Math.PI) / object.sides) ); } ctx.fill(); if (CRTP != 'simplistic') { ctx.stroke(); }; ctx.fillStyle = object.baseColor; ctx.strokeStyle = object.baseOutline; ctx.beginPath(); ctx.moveTo( 0 + (object.basewidth1 / clientFovMultiplier) * Math.cos(0), 0 + (object.basewidth1 / clientFovMultiplier) * Math.sin(0) ); for (var i = 1; i <= object.sides + 1; i += 1) { ctx.lineTo( 0 + (object.basewidth1 / clientFovMultiplier) * Math.cos((i * 2 * Math.PI) / object.sides), 0 + (object.basewidth1 / clientFovMultiplier) * Math.sin((i * 2 * Math.PI) / object.sides) ); } ctx.fill(); if (CRTP != 'simplistic') { ctx.stroke(); }; ctx.fillStyle = object.barrelColor; ctx.strokeStyle = object.barrelOutline; ctx.beginPath(); ctx.moveTo( 0 + (object.basewidth2 / clientFovMultiplier) * Math.cos(0), 0 + (object.basewidth2 / clientFovMultiplier) * Math.sin(0) ); for (var i = 1; i <= object.sides + 1; i += 1) { ctx.lineTo( 0 + (object.basewidth2 / clientFovMultiplier) * Math.cos((i * 2 * Math.PI) / object.sides), 0 + (object.basewidth2 / clientFovMultiplier) * Math.sin((i * 2 * Math.PI) / object.sides) ); } ctx.fill(); if (CRTP != 'simplistic') { ctx.stroke(); }; ctx.fillStyle = object.color; ctx.strokeStyle = object.outline; ctx.lineWidth = 4 / clientFovMultiplier; ctx.beginPath(); ctx.moveTo( 0 + (object.basewidth3 / clientFovMultiplier) * Math.cos(0), 0 + (object.basewidth3 / clientFovMultiplier) * Math.sin(0) ); for (var i = 1; i <= object.sides + 1; i += 1) { ctx.lineTo( 0 + (object.basewidth3 / clientFovMultiplier) * Math.cos((i * 2 * Math.PI) / object.sides), 0 + (object.basewidth3 / clientFovMultiplier) * Math.sin((i * 2 * Math.PI) / object.sides) ); } ctx.fill(); if (CRTP != 'simplistic') { ctx.stroke(); }; //draw barrels ctx.fillStyle = object.barrelColor; ctx.strokeStyle = object.barrelOutline; //trapezoid at the tip var barrelwidth = 140; var barrelheight = 28; //rectangle var barrelwidth2 = 180; var barrelheight2 = 28; //base trapezoid var barrelwidth3 = 140; var barrelheight3 = 80; //note that trapezoids and rectangles are drawn differently var barrelDistanceFromCenter = (object.width * (Math.cos(Math.PI/object.sides)));//width of middle of polygon (less than width of circle) function drawSancBarrel(barNum){ var barAngle = 360/object.sides*(barNum+0.5);//half of a side, cuz barrel is in between sides var barrelX = Math.cos((barAngle * Math.PI) / 180) * (barrelDistanceFromCenter+ barrelheight+ barrelheight2+ barrelheight3);//object.width * 0.9 var barrelY = Math.sin((barAngle * Math.PI) / 180) * (barrelDistanceFromCenter+ barrelheight+ barrelheight2+ barrelheight3); var barrelX2 = Math.cos((barAngle * Math.PI) / 180) * (barrelDistanceFromCenter + barrelheight2 + barrelheight3); //move rectangle barrel downwards var barrelY2 = Math.sin((barAngle * Math.PI) / 180) * (barrelDistanceFromCenter + barrelheight2 + barrelheight3); var barrelX3 = Math.cos((barAngle * Math.PI) / 180) * (barrelDistanceFromCenter + barrelheight3); //move base trapezoid barrel downwards var barrelY3 = Math.sin((barAngle * Math.PI) / 180) * (barrelDistanceFromCenter + barrelheight3); //base trapezoid ctx.save(); ctx.translate( barrelX3 / clientFovMultiplier, barrelY3 / clientFovMultiplier ); ctx.rotate(((barAngle - 90) * Math.PI) / 180); ctx.beginPath(); ctx.moveTo( ((-barrelwidth3 / 3) * 2) / clientFovMultiplier, -barrelheight3 / clientFovMultiplier ); ctx.lineTo(-barrelwidth3 / clientFovMultiplier, 0); ctx.lineTo(barrelwidth3 / clientFovMultiplier, 0); ctx.lineTo( ((barrelwidth3 / 3) * 2) / clientFovMultiplier, -barrelheight3 / clientFovMultiplier ); ctx.lineTo( ((-barrelwidth3 / 3) * 2) / clientFovMultiplier, -barrelheight3 / clientFovMultiplier ); ctx.fill(); if (CRTP != 'simplistic') { ctx.stroke(); }; ctx.restore(); //rectangle ctx.save(); ctx.translate( barrelX2 / clientFovMultiplier, barrelY2 / clientFovMultiplier ); ctx.rotate(((barAngle - 90) * Math.PI) / 180); ctx.fillRect( -barrelwidth2 / 2 / clientFovMultiplier, -barrelheight2 / clientFovMultiplier, barrelwidth2 / clientFovMultiplier, barrelheight2 / clientFovMultiplier ); if (CRTP != 'simplistic') { ctx.strokeRect( -barrelwidth2 / 2 / clientFovMultiplier, -barrelheight2 / clientFovMultiplier, barrelwidth2 / clientFovMultiplier, barrelheight2 / clientFovMultiplier ); }; ctx.restore(); //trapezium at the tip ctx.save(); ctx.translate( barrelX / clientFovMultiplier, barrelY / clientFovMultiplier ); ctx.rotate(((barAngle - 90) * Math.PI) / 180); ctx.beginPath(); ctx.moveTo(-barrelwidth / 2 / clientFovMultiplier, 0); ctx.lineTo( -barrelwidth / clientFovMultiplier, -barrelheight / clientFovMultiplier ); ctx.lineTo( barrelwidth / clientFovMultiplier, -barrelheight / clientFovMultiplier ); ctx.lineTo(barrelwidth / 2 / clientFovMultiplier, 0); ctx.lineTo(-barrelwidth / 2 / clientFovMultiplier, 0); ctx.fill(); if (CRTP != 'simplistic') { ctx.stroke(); }; ctx.restore(); } for (let i = 0; i < object.sides; i++) { drawSancBarrel(i); } //draw aura ctx.fillStyle = object.auraColor; ctx.lineWidth = 4 / clientFovMultiplier; ctx.beginPath(); ctx.moveTo( 0 + (object.auraWidth / clientFovMultiplier) * Math.cos(0), 0 + (object.auraWidth / clientFovMultiplier) * Math.sin(0) ); for (var i = 1; i <= object.sides + 1; i += 1) { ctx.lineTo( 0 + (object.auraWidth / clientFovMultiplier) * Math.cos((i * 2 * Math.PI) / object.sides), 0 + (object.auraWidth / clientFovMultiplier) * Math.sin((i * 2 * Math.PI) / object.sides) ); } ctx.fill(); ctx.lineJoin = "miter"; //change back ctx.restore(); if (showHitBox == "yes") { //draw hitbox ctx.strokeStyle = "blue"; ctx.lineWidth = 3; ctx.beginPath(); ctx.arc( drawingX, drawingY, object.width / clientFovMultiplier, 0, 2 * Math.PI ); ctx.stroke(); } } else if (object.type == "player") { var spawnProtectionFlashDuration = 3; //higher number indicates longer duration between flashes. if (object.hasOwnProperty("deadOpacity")) { //if this is an animation of a dead object ctx.globalAlpha = object.deadOpacity; } //draw players ctx.save(); //save so later can restore //translate canvas to location of player so that the player is at 0,0 coordinates, allowing rotation around the center of player's body ctx.translate(drawingX, drawingY); let objectangle = object.angle; if ( id == playerstring && object.autorotate != "yes" && object.fastautorotate != "yes" ) { //if this player is the tank that the client is controlling objectangle = clientAngle; ctx.rotate(clientAngle); //instead of using client's actual tank angle, use the angle to the mouse. this reduces lag effect } else { ctx.rotate(object.angle); } let spawnProtect = "no"; if (object.spawnProtection < object.spawnProtectionDuration && object.spawnProtection % spawnProtectionFlashDuration == 0) { spawnProtect = "yes"; } let playercolor = "undefined"; let playeroutline = "undefined"; let eternal = "no"; if (object.team == "none") { if (id == playerstring) { playercolor = bodyColors.blue.col; playeroutline = bodyColors.blue.outline; if (object.hit > 0 || spawnProtect == "yes") { playercolor = bodyColors.blue.hitCol playeroutline = bodyColors.blue.hitOutline } } else{ playercolor = bodyColors.red.col; playeroutline = bodyColors.red.outline; if (object.hit > 0 || spawnProtect == "yes") { playercolor = bodyColors.red.hitCol playeroutline = bodyColors.red.hitOutline } } } else if (object.team == "blue" || object.team == "green" || object.team == "red" || object.team == "purple" || object.team == "eternal" || object.team == "magenta" || object.team == "fallen" || object.team == "celestial") { playercolor = bodyColors[object.team].col; playeroutline = bodyColors[object.team].outline; if (object.hit > 0 || spawnProtect == "yes") { playercolor = bodyColors[object.team].hitCol; playeroutline = bodyColors[object.team].hitOutline; } if (object.team == "eternal"){ eternal = "yes"; } } if (object.developer == "yes") { //if a developer playercolor = object.color; playeroutline = object.outline; } //store player color for upgrade buttons if (id == playerstring){ playerBodyCol = playercolor; playerBodyOutline = playeroutline; } drawPlayer(ctx, object, clientFovMultiplier, spawnProtect, playercolor, playeroutline, eternal, objectangle)//draw barrel and body ctx.restore(); //restore coordinates to saved //write player name if not the client's tank if (id != playerstring) { ctx.fillStyle = "white"; ctx.strokeStyle = "black"; ctx.lineWidth = 8 / clientFovMultiplier; ctx.font = "700 " + 35 / clientFovMultiplier + "px Roboto"; ctx.textAlign = "center"; ctx.miterLimit = 2;//prevent text spikes, alternative to linejoin round //ctx.lineJoin = "round"; //prevent spikes above the capital letter "M" //note: if you stroke then fill, the words will be thicker and nicer. If you fill then stroke, the words are thinner. if (object.name == "unnamed"){ //this guy is unnamed, add a 3 digit identifier let thisID = id.substr(id.length - 3);//last 3 digits of ID object.name += (" #" + thisID); } ctx.strokeText( object.name, drawingX, drawingY - (object.width + 40) / clientFovMultiplier ); ctx.fillText( object.name, drawingX, drawingY - (object.width + 40) / clientFovMultiplier ); //write player level ctx.font = "700 " + 18 / clientFovMultiplier + "px Roboto"; ctx.strokeText( "Lvl " + object.level + " " + object.tankType + "-" + object.bodyType, drawingX, drawingY - (object.width + 10) / clientFovMultiplier ); ctx.fillText( "Lvl " + object.level + " " + object.tankType + "-" + object.bodyType, drawingX, drawingY - (object.width + 10) / clientFovMultiplier ); ctx.lineJoin = "miter"; //change it back } //draw player health if (object.health < object.maxhealth) { //draw health bar background var w = (object.width / clientFovMultiplier) * 2; var h = 7 / clientFovMultiplier; var r = h / 2; var x = drawingX - object.width / clientFovMultiplier; var y = drawingY + object.width / clientFovMultiplier + 10; ctx.fillStyle = "black"; ctx.strokeStyle = "black"; ctx.lineWidth = 2.5 / clientFovMultiplier; ctx.beginPath(); ctx.moveTo(x + r, y); ctx.arcTo(x + w, y, x + w, y + h, r); ctx.arcTo(x + w, y + h, x, y + h, r); ctx.arcTo(x, y + h, x, y, r); ctx.arcTo(x, y, x + w, y, r); ctx.closePath(); ctx.fill(); ctx.stroke(); //draw health bar if (object.health > 0) { w = (w / object.maxhealth) * object.health; //if (id == playerstring) { //if this player is the tank that the client is controlling if (object.team == "none") { if (id == playerstring) { ctx.fillStyle = bodyColors.blue.col; } else{ ctx.fillStyle = bodyColors.red.col; } } else if (object.team == "blue" || object.team == "red" || object.team == "purple" || object.team == "green" || object.team == "eternal" || object.team == "magenta" || object.team == "fallen" || object.team == "celestial") { ctx.fillStyle = bodyColors[object.team].col; } if (r * 2 > w) { //prevent weird shape when radius more than width r = w / 2; y += (h - w) / 2; //move health bar so that it is centered vertically in black bar h = w; } ctx.beginPath(); ctx.moveTo(x + r, y); ctx.arcTo(x + w, y, x + w, y + h, r); ctx.arcTo(x + w, y + h, x, y + h, r); ctx.arcTo(x, y + h, x, y, r); ctx.arcTo(x, y, x + w, y, r); ctx.closePath(); ctx.fill(); ctx.stroke(); } } //write chats if (chatstate) { //write chats if (id != playerstring) { var firstChatY = object.width / clientFovMultiplier /5*4 + 55 / clientFovMultiplier; } else{ var firstChatY = object.width / clientFovMultiplier /5*4;//chat nearer to player body if no need to display name } ctx.font = "700 25px Roboto"; ctx.textAlign = "center"; ctx.lineJoin = "round"; //prevent spikes above the capital letter "M" var xpadding = 15; var ypadding = 10; var lineheight = 30; var timeWhenChatRemove = 200;//when change on server code, remember to change here too if (!(chatlist[id])){//used for animating chat positions chatlist[id] = JSON.parse(JSON.stringify(object.chats)); } else{ let tempArray = []; let messages = {};//prevent bug when multiple chats have same message object.chats.forEach(function (item, index) { let occurence = 0;//prevent bug when multiple chats have same message let foundit = 0; for (var i = 0; i < chatlist[id].length; i++) {//check if oldchats hae this message, to preserve the position for animation if (chatlist[id][i].chat == item.chat){ if (messages[item.chat]){//saw a chat with the exact same message before! if (messages[item.chat] <= occurence){//this is a different chat let k = JSON.parse(JSON.stringify(chatlist[id][i])); k.time = item.time; tempArray.push(k); messages[chatlist[id][i].chat]++; foundit = 1; break } else{//this is the same chat that you saw before, continue hunting for the chat occurence++; } } else{ let k = JSON.parse(JSON.stringify(chatlist[id][i])); k.time = item.time; tempArray.push(k); messages[chatlist[id][i].chat] = 1; foundit = 1; break } } } if (foundit == 0){//new chat message let k = JSON.parse(JSON.stringify(item)); k.opacity = 0; tempArray.push(k); } }); chatlist[id] = tempArray; } object.chats.slice().reverse().forEach((chatObj, index) => {//slice and reverse to loop though array backwards (so older messages are above) ctx.fillStyle = "rgba(69,69,69,.7)"; var longestLine = 0; //multiline chat const wrapText = function(ctx, text, x, y, maxWidth, lineHeight) { // First, start by splitting all of our text into words, but splitting it into an array split by spaces let words = text.split(' '); let line = ''; // This will store the text of the current line let testLine = ''; // This will store the text when we add a word, to test if it's too long let lineArray = []; // This is an array of lines, which the function will return // Lets iterate over each word for(var n = 0; n < words.length; n++) { // Create a test line, and measure it.. testLine += `${words[n]} `; let metrics = ctx.measureText(testLine); let testWidth = metrics.width; // If the width of this test line is more than the max width if (testWidth > maxWidth && n > 0) { // Then the line is finished, push the current line into "lineArray" line = line.slice(0, -1);//remove space at the end of the line lineArray.push([line, x, y]); let thislinewidth = ctx.measureText(line).width; if (thislinewidth > longestLine){ longestLine = thislinewidth; } // Increase the line height, so a new line is started y += lineHeight; // Update line and test line to use this word as the first word on the next line line = `${words[n]} `; testLine = `${words[n]} `; } else { // If the test line is still less than the max width, then add the word to the current line line += `${words[n]} `; } // If we never reach the full max width, then there is only one line.. so push it into the lineArray so we return something if(n === words.length - 1) { line = line.slice(0, -1);//remove space at the end of the line lineArray.push([line, x, y]); let thislinewidth = ctx.measureText(line).width; if (thislinewidth > longestLine){ longestLine = thislinewidth; } } } // Return the line array return lineArray; } let wrappedText = wrapText(ctx, chatObj.chat, drawingX, drawingY - firstChatY, 900, lineheight);//split message into multiline text //draw rect var w = longestLine + xpadding * 2; var h = lineheight * wrappedText.length + ypadding * 2; if (wrappedText.length == 1){//remove spacing between text for single-line text h = 25 + ypadding * 2; } var r = 15; var x = drawingX - longestLine / 2 - xpadding; var y = drawingY - firstChatY - ypadding - h - 20;//the actual y location of this chat message //aniamte towards this y position //remember that the loop is reversed, so indexes are reversed here too let thischat = chatlist[id][chatlist[id].length - 1 - index]; let diffpos = 0; if (!thischat.y){ thischat.y = y; } else{ if (y > thischat.y){ thischat.y+=(y - thischat.y)/2*deltaTime; if (y < thischat.y){ thischat.y = y; } } else if (y < thischat.y){ thischat.y-=(thischat.y - y)/2*deltaTime; if (y > thischat.y){ thischat.y = y; } } if (Math.abs(y - thischat.y)<0.1){//small difference between current position and actual position thischat.y = y; } diffpos = y - thischat.y; y = thischat.y; } if (thischat.opacity < 1){ thischat.opacity+=0.1; } ctx.globalAlpha = thischat.opacity; ctx.beginPath(); ctx.moveTo(x + r, y); ctx.arcTo(x + w, y, x + w, y + h, r); ctx.arcTo(x + w, y + h, x, y + h, r); ctx.arcTo(x, y + h, x, y, r); ctx.arcTo(x, y, x + w, y, r); ctx.closePath(); ctx.fill(); if (index == 0){ //if this is first chat message, draw triangle let trianglewidth = 20; let triangleheight = 10; ctx.beginPath(); ctx.moveTo(x + w/2 - trianglewidth/2, y + h); ctx.lineTo(x + w/2 + trianglewidth/2, y + h); ctx.lineTo(x + w/2, y + h + triangleheight); ctx.fill(); } //write words ctx.fillStyle = "white"; wrappedText.forEach(function(item) { ctx.fillText(item[0], item[1], item[2]-h-diffpos);//write text }) ctx.globalAlpha = 1.0; firstChatY += (h + 10); //height of chat plus space between chats }); ctx.lineJoin = "miter"; //change it back } if (object.hasOwnProperty("deadOpacity")) { //if this is an animation of a dead object ctx.globalAlpha = 1.0; //reset opacity } if (showHitBox == "yes") { //draw hitbox ctx.strokeStyle = "blue"; ctx.lineWidth = 3; ctx.beginPath(); ctx.arc( drawingX, drawingY, object.width / clientFovMultiplier, 0, 2 * Math.PI ); ctx.stroke(); } } else if (object.type == "portal") { //draw the aura below the portal var auraSpeed = 75; //higher number means slower speed var auraWidth = 4; //reative to portal size var portalAuraSize = object.timer % auraSpeed; var portalwidth = portalwidths[id]; //use this for portal width. it keeps track size changes when players touch portal var portalsizeincrease = portalwidths[id] / object.width; //increase in width when someone touch it (needed for the spikes) //first aura var opacityCalculation = 1 - ((auraWidth / auraSpeed) * portalAuraSize) / auraWidth; //goes from 0 to 0.3 if (opacityCalculation > 0.3) { //max opacity for portal aura opacityCalculation = 0.3; } if (object.hasOwnProperty("red")) { //if portal is radiant ctx.fillStyle = "rgba(" + object.red + ", " + object.green + ", " + object.blue + "," + opacityCalculation + ")"; } else { ctx.fillStyle = "rgba(" + object.color + "," + opacityCalculation + ")"; } ctx.beginPath(); ctx.arc( drawingX, drawingY, (portalwidth * ((auraWidth / auraSpeed) * portalAuraSize)) / clientFovMultiplier, 0, 2 * Math.PI ); ctx.fill(); //second smaller aura portalAuraSize = (object.timer - auraSpeed / 2) % auraSpeed; if (portalAuraSize > 0) { var opacityCalculation = 1 - ((auraWidth / auraSpeed) * portalAuraSize) / auraWidth; if (opacityCalculation > 0.3) { //max opacity for portal aura opacityCalculation = 0.3; } if (object.hasOwnProperty("red")) { //if portal is radiant ctx.fillStyle = "rgba(" + object.red + ", " + object.green + ", " + object.blue + "," + opacityCalculation + ")"; } else { ctx.fillStyle = "rgba(" + object.color + "," + opacityCalculation + ")"; } ctx.beginPath(); ctx.arc( drawingX, drawingY, (portalwidth * ((auraWidth / auraSpeed) * portalAuraSize)) / clientFovMultiplier, 0, 2 * Math.PI ); ctx.fill(); } if (object.hasOwnProperty("deadOpacity")) { //if this is an animation of a dead object ctx.globalAlpha = object.deadOpacity; } //drawing portals //create gradient //const gradient = ctx.createRadialGradient(drawingX, drawingY, object.width/3/clientFovMultiplier, drawingX, drawingY, object.width/clientFovMultiplier); // Add two color stops //caluclate color of outline of portal based on time until it die var portalColorCalc = object.timer / object.maxtimer; var portalColor = 255 - portalColorCalc * 255; var portalRGB = "rgb(" + portalColor + "," + portalColor + "," + portalColor + ")"; var portalRGBoutline = "rgb(" + (portalColor - 20) + "," + (portalColor - 20) + "," + (portalColor - 20) + ")"; if (object.ruptured == 1) { //portal is ruptured! //draw the stars ctx.save(); //save so later can restore ctx.translate(drawingX, drawingY); ctx.fillStyle = "white"; ctx.strokeStyle = "lightgrey"; ctx.lineWidth = 3 / clientFovMultiplier; ctx.lineJoin = "round"; //first star: 3 spikes ctx.rotate((extraSpikeRotate * Math.PI) / 180); var numberOfSpikes = 3; var outerRadius = ((object.width * 3) / clientFovMultiplier) * portalsizeincrease; var innerRadius = (object.width / 3 / clientFovMultiplier) * portalsizeincrease; var rot = (Math.PI / 2) * 3; var x = 0; var y = 0; ctx.beginPath(); ctx.moveTo(0, 0 - outerRadius); for (i = 0; i < numberOfSpikes; i++) { x = 0 + Math.cos(rot) * outerRadius; y = 0 + Math.sin(rot) * outerRadius; ctx.lineTo(x, y); rot += Math.PI / numberOfSpikes; x = 0 + Math.cos(rot) * innerRadius; y = 0 + Math.sin(rot) * innerRadius; ctx.lineTo(x, y); rot += Math.PI / numberOfSpikes; } ctx.lineTo(0, 0 - outerRadius); ctx.closePath(); ctx.fill(); ctx.stroke(); ctx.rotate((-extraSpikeRotate * Math.PI) / 180); //second star: 6 spikes in opposite direction ctx.rotate(((360 - extraSpikeRotate) * 2 * Math.PI) / 180); var numberOfSpikes = 6; var outerRadius = ((object.width * 1.5) / clientFovMultiplier) * portalsizeincrease; var innerRadius = (object.width / 1.2 / clientFovMultiplier) * portalsizeincrease; var rot = (Math.PI / 2) * 3; var x = 0; var y = 0; ctx.beginPath(); ctx.moveTo(0, 0 - outerRadius); for (i = 0; i < numberOfSpikes; i++) { x = 0 + Math.cos(rot) * outerRadius; y = 0 + Math.sin(rot) * outerRadius; ctx.lineTo(x, y); rot += Math.PI / numberOfSpikes; x = 0 + Math.cos(rot) * innerRadius; y = 0 + Math.sin(rot) * innerRadius; ctx.lineTo(x, y); rot += Math.PI / numberOfSpikes; } ctx.lineTo(0, 0 - outerRadius); ctx.closePath(); ctx.fill(); ctx.stroke(); ctx.rotate((-(360 - extraSpikeRotate) * 2 * Math.PI) / 180); //third star: 6 spikes ctx.rotate((extraSpikeRotate * 2 * Math.PI) / 180); var numberOfSpikes = 6; var outerRadius = ((object.width * 1.5) / clientFovMultiplier) * portalsizeincrease; var innerRadius = (object.width / 1.2 / clientFovMultiplier) * portalsizeincrease; var rot = (Math.PI / 2) * 3; var x = 0; var y = 0; ctx.beginPath(); ctx.moveTo(0, 0 - outerRadius); for (i = 0; i < numberOfSpikes; i++) { x = 0 + Math.cos(rot) * outerRadius; y = 0 + Math.sin(rot) * outerRadius; ctx.lineTo(x, y); rot += Math.PI / numberOfSpikes; x = 0 + Math.cos(rot) * innerRadius; y = 0 + Math.sin(rot) * innerRadius; ctx.lineTo(x, y); rot += Math.PI / numberOfSpikes; } ctx.lineTo(0, 0 - outerRadius); ctx.closePath(); ctx.fill(); ctx.stroke(); ctx.rotate((-extraSpikeRotate * 2 * Math.PI) / 180); //fourth star: 6 dark spikes in opposite direction ctx.fillStyle = portalRGB; ctx.strokeStyle = portalRGBoutline; ctx.rotate(((360 - extraSpikeRotate) * 3 * Math.PI) / 180); //times 2 to make it faster var numberOfSpikes = 6; var outerRadius = ((object.width * 1.5) / clientFovMultiplier) * portalsizeincrease; var innerRadius = (object.width / 2 / clientFovMultiplier) * portalsizeincrease; var rot = (Math.PI / 2) * 3; var x = 0; var y = 0; ctx.beginPath(); ctx.moveTo(0, 0 - outerRadius); for (i = 0; i < numberOfSpikes; i++) { x = 0 + Math.cos(rot) * outerRadius; y = 0 + Math.sin(rot) * outerRadius; ctx.lineTo(x, y); rot += Math.PI / numberOfSpikes; x = 0 + Math.cos(rot) * innerRadius; y = 0 + Math.sin(rot) * innerRadius; ctx.lineTo(x, y); rot += Math.PI / numberOfSpikes; } ctx.lineTo(0, 0 - outerRadius); ctx.closePath(); ctx.fill(); ctx.stroke(); ctx.rotate((-(360 - extraSpikeRotate) * 3 * Math.PI) / 180); //fifth star: tiny black spikes ctx.rotate((extraSpikeRotate * 3 * Math.PI) / 180); //times 2 to make it faster var numberOfSpikes = 6; var outerRadius = ((object.width * 1.25) / clientFovMultiplier) * portalsizeincrease; var innerRadius = (object.width / 4 / clientFovMultiplier) * portalsizeincrease; var rot = (Math.PI / 2) * 3; var x = 0; var y = 0; ctx.beginPath(); ctx.moveTo(0, 0 - outerRadius); for (i = 0; i < numberOfSpikes; i++) { x = 0 + Math.cos(rot) * outerRadius; y = 0 + Math.sin(rot) * outerRadius; ctx.lineTo(x, y); rot += Math.PI / numberOfSpikes; x = 0 + Math.cos(rot) * innerRadius; y = 0 + Math.sin(rot) * innerRadius; ctx.lineTo(x, y); rot += Math.PI / numberOfSpikes; } ctx.lineTo(0, 0 - outerRadius); ctx.closePath(); ctx.fill(); ctx.stroke(); ctx.rotate((-extraSpikeRotate * 3 * Math.PI) / 180); ctx.restore(); ctx.lineJoin = "miter"; } ctx.fillStyle = portalRGB; ctx.strokeStyle = portalRGBoutline; ctx.lineWidth = 3 / clientFovMultiplier; ctx.beginPath(); ctx.arc( drawingX, drawingY, portalwidth / clientFovMultiplier, 0, 2 * Math.PI ); ctx.fill(); ctx.stroke(); if (object.hasOwnProperty("deadOpacity")) { //if this is an animation of a dead object ctx.globalAlpha = 1.0; //reset opacity } //spawn particles var choosing = Math.floor(Math.random() * 3); //choose if particle spawn. Lower number means more particles if (choosing == 1) { var angleDegrees = Math.floor(Math.random() * 360); //choose angle in degrees var angleRadians = (angleDegrees * Math.PI) / 180; //convert to radians portalparticles[particleID] = { angle: angleRadians, x: object.x, y: object.y, width: 50, height: 50, speed: 10, timer: 30, maxtimer: 15, //difference between timer and maxtimer is the opacity change of the particle. Larger difference means more or less transparent color: "white", outline: "lightgrey", type: "particle", }; particleID++; } if (showHitBox == "yes") { //draw hitbox ctx.strokeStyle = "blue"; ctx.lineWidth = 3; ctx.beginPath(); ctx.arc( drawingX, drawingY, object.width / clientFovMultiplier, 0, 2 * Math.PI ); ctx.stroke(); } } else if (object.type == "Fixedportal") { //drawing rectangular fixed portals, e.g. the portal at top left corner of dune ctx.save(); //save so later can restore ctx.translate(drawingX, drawingY); //translate so white portal is at 0,0 coordinates so can rotate around center of portal ctx.rotate((object.angleDegrees * Math.PI) / 180); //rotate portal ctx.fillStyle = object.color; ctx.strokeStyle = object.outline; ctx.fillRect( -object.width / 2 / clientFovMultiplier, -object.height / 2 / clientFovMultiplier, object.width / clientFovMultiplier, object.height / clientFovMultiplier ); ctx.strokeRect( -object.width / 2 / clientFovMultiplier, -object.height / 2 / clientFovMultiplier, object.width / clientFovMultiplier, object.height / clientFovMultiplier ); ctx.globalAlpha = 0.7; //transparency ctx.fillStyle = object.color2; ctx.fillRect( -object.width / clientFovMultiplier, -object.height / clientFovMultiplier, (object.width * 2) / clientFovMultiplier, (object.height * 2) / clientFovMultiplier ); ctx.strokeRect( -object.width / clientFovMultiplier, -object.height / clientFovMultiplier, (object.width * 2) / clientFovMultiplier, (object.height * 2) / clientFovMultiplier ); ctx.globalAlpha = 1.0; //reset transparency ctx.restore(); //restore after translating if (showHitBox == "yes") { //draw hitbox ctx.strokeStyle = "blue"; ctx.lineWidth = 3; ctx.beginPath(); ctx.arc( drawingX, drawingY, object.width / 2 / clientFovMultiplier, 0, 2 * Math.PI ); ctx.stroke(); } } else if (object.type == "particle") { //draw particles if (object.timer <= 10){ ctx.globalAlpha = object.timer / 10; } //ctx.globalAlpha = object.timer / object.maxtimer; ctx.fillStyle = object.color; ctx.strokeStyle = object.outline; ctx.lineWidth = 3 / clientFovMultiplier; ctx.beginPath(); ctx.arc( drawingX, drawingY, object.width / clientFovMultiplier, 0, 2 * Math.PI ); ctx.fill(); ctx.stroke(); ctx.globalAlpha = 1.0; } else if (object.type == "wall") { //ctx.fillStyle = "#232323"; ctx.fillStyle = "rgba(15, 15, 15, .5)"; ctx.fillRect( drawingX, drawingY, object.w / clientFovMultiplier, object.h / clientFovMultiplier ); if (showHitBox == "yes") { //draw hitbox ctx.strokeStyle = "blue"; ctx.lineWidth = 3; ctx.strokeRect( drawingX, drawingY, object.w / clientFovMultiplier, object.h / clientFovMultiplier ); } } else if (object.type == "gate") { //ctx.fillStyle = "#232323"; ctx.save(); ctx.translate(drawingX, drawingY); ctx.rotate(object.angle/180*Math.PI); //draw white rectangle below ctx.fillStyle = "rgba(255,255,255,.7)"; ctx.strokeStyle = "white"; //FIRST WHITE RECTANGLE ctx.globalAlpha = 1.0 * (endGate - gateTimer) / (endGate - 1 - startGate);//gateTimer increases from 0.5 to 9, this equation makes the opacity decrease from 1 to 0 ctx.fillRect( -(object.height / clientFovMultiplier * gateTimer)/2 + object.height / clientFovMultiplier/2, -object.width/2/clientFovMultiplier, object.height / clientFovMultiplier * gateTimer, object.width / clientFovMultiplier ); ctx.strokeRect( -(object.height / clientFovMultiplier * gateTimer)/2 + object.height / clientFovMultiplier/2, -object.width/2/clientFovMultiplier, object.height / clientFovMultiplier * gateTimer, object.width / clientFovMultiplier ); ctx.globalAlpha = 1.0; //SECOND WHITE RECTANGLE let gateTimer2 = gateTimer - endGate/2; if (gateTimer2 < startGate){ gateTimer2 = endGate - (startGate - gateTimer2) } ctx.globalAlpha = 1.0 * (endGate - gateTimer2) / (endGate - 1 - startGate);//gateTimer increases from 1 to 7, this equation makes the opacity decrease from 1 to 0 ctx.fillRect( -(object.height / clientFovMultiplier * gateTimer2)/2 + object.height / clientFovMultiplier/2, -object.width/2/clientFovMultiplier, object.height / clientFovMultiplier * gateTimer2, object.width / clientFovMultiplier ); ctx.strokeRect( -(object.height / clientFovMultiplier * gateTimer2)/2 + object.height / clientFovMultiplier/2, -object.width/2/clientFovMultiplier, object.height / clientFovMultiplier * gateTimer2, object.width / clientFovMultiplier ); ctx.globalAlpha = 1.0; //draw actual black gate ctx.fillStyle = "black"; ctx.fillRect(0, -object.width/2/clientFovMultiplier, object.height / clientFovMultiplier, object.width / clientFovMultiplier ); if (showHitBox == "yes") { //draw hitbox ctx.strokeStyle = "blue"; ctx.lineWidth = 3; ctx.strokeRect(0, -object.width/2/clientFovMultiplier, object.height / clientFovMultiplier, object.width / clientFovMultiplier ); } ctx.restore(); //spawn particles var choosing = Math.floor(Math.random() * 3); //choose if particle spawn. Lower number means more particles if (choosing == 1) { var dir = Math.floor(Math.random() * 2); //choose angle in degrees if (dir == 0){ var angleRadians = (object.angle) * Math.PI / 180; //convert to radians } else{ var angleRadians = (object.angle - 180) * Math.PI / 180; } let randX = 0; let randY = 0; //code currently does not support particles for gates that are tilted //i dont see a need to add that in the near future if (object.angle == 0 || object.angle == 180 || object.angle == 360){ randY = Math.floor(Math.random() * object.width) - object.width/2; } else if (object.angle == 90 || object.angle == 270){ randX = Math.floor(Math.random() * object.width) - object.width/2; } portalparticles[particleID] = { angle: angleRadians, x: object.x + randX, y: object.y + randY, width: 50, height: 50, speed: 10, timer: 30, maxtimer: 15, //difference between timer and maxtimer is the opacity change of the particle. Larger difference means more or less transparent color: "white", outline: "lightgrey", type: "particle", }; particleID++; } } else if (object.type == "def") { //base defender in 2tdm ctx.save(); ctx.translate(drawingX, drawingY); ctx.rotate(object.angle); ctx.lineJoin = "round"; //make corners of shape round ctx.lineWidth = 4 / clientFovMultiplier; //draw octagon base var octagonWidth = object.width/5*6; ctx.fillStyle = bodyColors.asset.col; ctx.strokeStyle = bodyColors.asset.outline; ctx.beginPath(); ctx.moveTo( 0 + (octagonWidth / clientFovMultiplier) * Math.cos(0), 0 + (octagonWidth / clientFovMultiplier) * Math.sin(0) ); for (var i = 1; i <= 8 + 1; i += 1) { ctx.lineTo( 0 + (octagonWidth / clientFovMultiplier) * Math.cos((i * 2 * Math.PI) / 8), 0 + (octagonWidth / clientFovMultiplier) * Math.sin((i * 2 * Math.PI) / 8) ); } ctx.fill(); if (CRTP != 'simplistic') { ctx.stroke(); }; //draw barrels ctx.fillStyle = bodyColors.barrel.col; ctx.strokeStyle = bodyColors.barrel.outline; //trapezoid at the tip var barrelwidth = 70; var barrelheight = 20; //rectangle var barrelwidth2 = 90; var barrelheight2 = 20; //base trapezoid var barrelwidth3 = 70; var barrelheight3 = 60; //note that trapezoids and rectangles are drawn differently for (let i = 0; i < 4; i++) {//draw 4 barrels var barrelAngle = 360/4*i; var barrelX = Math.cos((barrelAngle * Math.PI) / 180) * object.width * 1.4; var barrelY = Math.sin((barrelAngle * Math.PI) / 180) * object.width * 1.4; var barrelX2 = Math.cos((barrelAngle * Math.PI) / 180) * (object.width * 1.4 - barrelheight); //move rectangle barrel downwards var barrelY2 = Math.sin((barrelAngle * Math.PI) / 180) * (object.width * 1.4 - barrelheight); var barrelX3 = Math.cos((barrelAngle * Math.PI) / 180) * (object.width * 1.4 - barrelheight - barrelheight2); //move base trapezoid barrel downwards var barrelY3 = Math.sin((barrelAngle * Math.PI) / 180) * (object.width * 1.4 - barrelheight - barrelheight2); //base trapezoid ctx.save(); ctx.translate( barrelX3 / clientFovMultiplier, barrelY3 / clientFovMultiplier ); ctx.rotate(((barrelAngle - 90) * Math.PI) / 180); ctx.beginPath(); ctx.moveTo( ((-barrelwidth3 / 3) * 2) / clientFovMultiplier, -barrelheight3 / clientFovMultiplier ); ctx.lineTo(-barrelwidth3 / clientFovMultiplier, 0); ctx.lineTo(barrelwidth3 / clientFovMultiplier, 0); ctx.lineTo( ((barrelwidth3 / 3) * 2) / clientFovMultiplier, -barrelheight3 / clientFovMultiplier ); ctx.lineTo( ((-barrelwidth3 / 3) * 2) / clientFovMultiplier, -barrelheight3 / clientFovMultiplier ); ctx.fill(); if (CRTP != 'simplistic') { ctx.stroke(); }; ctx.restore(); //rectangle ctx.save(); ctx.translate( barrelX2 / clientFovMultiplier, barrelY2 / clientFovMultiplier ); ctx.rotate(((barrelAngle - 90) * Math.PI) / 180); ctx.fillRect( -barrelwidth2 / 2 / clientFovMultiplier, -barrelheight2 / clientFovMultiplier, barrelwidth2 / clientFovMultiplier, barrelheight2 / clientFovMultiplier ); if (CRTP != 'simplistic') { ctx.strokeRect( -barrelwidth2 / 2 / clientFovMultiplier, -barrelheight2 / clientFovMultiplier, barrelwidth2 / clientFovMultiplier, barrelheight2 / clientFovMultiplier ); }; ctx.restore(); //trapezium at the tip ctx.save(); ctx.translate( barrelX / clientFovMultiplier, barrelY / clientFovMultiplier ); ctx.rotate(((barrelAngle - 90) * Math.PI) / 180); ctx.beginPath(); ctx.moveTo(-barrelwidth / 2 / clientFovMultiplier, 0); ctx.lineTo( -barrelwidth / clientFovMultiplier, -barrelheight / clientFovMultiplier ); ctx.lineTo( barrelwidth / clientFovMultiplier, -barrelheight / clientFovMultiplier ); ctx.lineTo(barrelwidth / 2 / clientFovMultiplier, 0); ctx.lineTo(-barrelwidth / 2 / clientFovMultiplier, 0); ctx.fill(); if (CRTP != 'simplistic') { ctx.stroke(); }; ctx.restore(); } //draw body ctx.fillStyle = object.color; ctx.strokeStyle = object.outline; ctx.beginPath(); ctx.arc( 0, 0, object.width / clientFovMultiplier, 0, 2 * Math.PI ); ctx.fill(); if (CRTP != 'simplistic') { ctx.stroke(); }; var octagonWidth = object.width/5*4; ctx.fillStyle = bodyColors.asset.col; ctx.strokeStyle = bodyColors.asset.outline; ctx.beginPath(); ctx.moveTo( 0 + (octagonWidth / clientFovMultiplier) * Math.cos(0), 0 + (octagonWidth / clientFovMultiplier) * Math.sin(0) ); for (var i = 1; i <= 8 + 1; i += 1) { ctx.lineTo( 0 + (octagonWidth / clientFovMultiplier) * Math.cos((i * 2 * Math.PI) / 8), 0 + (octagonWidth / clientFovMultiplier) * Math.sin((i * 2 * Math.PI) / 8) ); } ctx.fill(); if (CRTP != 'simplistic') { ctx.stroke(); }; ctx.fillStyle = object.color; ctx.strokeStyle = object.outline; ctx.beginPath(); ctx.arc( 0, 0, object.width/2 / clientFovMultiplier, 0, 2 * Math.PI ); ctx.fill(); if (CRTP != 'simplistic') { ctx.stroke(); }; ctx.lineJoin = "miter"; //change back ctx.restore(); if (showHitBox == "yes") { //draw hitbox ctx.strokeStyle = "blue"; ctx.lineWidth = 3; ctx.beginPath(); ctx.arc( drawingX, drawingY, object.width / clientFovMultiplier, 0, 2 * Math.PI ); if (CRTP != 'simplistic') { ctx.stroke(); }; } } }; function newbulletbarrel(canvas, x,width,height,shootChange, fov){//shootchange is change in barrel height when shooting canvas.fillRect( (x - width / 2) / fov, -(height - shootChange) / fov, width / fov, (height - shootChange) / fov ); if (document.getElementById('theme').value != 'simplistic') { canvas.strokeRect( (x - width / 2) / fov, -(height - shootChange) / fov, width / fov, (height - shootChange) / fov ); }; }; function newdronebarrel(canvas, x,width,height,shootChange, fov){ canvas.beginPath(); canvas.moveTo( -width / 2 / fov + x / fov, 0 ); canvas.lineTo( -width / fov + x / fov, -(height - shootChange) / fov ); canvas.lineTo( width / fov + (x * 2) / fov, -(height - shootChange) / fov ); canvas.lineTo( width / 2 / fov + (x * 2) / fov, 0 ); canvas.fill(); if (document.getElementById('theme').value != 'simplistic') { canvas.stroke(); }; }; function newtrapbarrel(canvas, x,width,height,shootChange, fov){ canvas.fillRect( (x - width / 2) / fov, -(height - shootChange) * 0.67 / fov, width / fov, (height - shootChange) * 0.67 / fov ); if (document.getElementById('theme').value != 'simplistic') { canvas.strokeRect( (x - width / 2) / fov, -(height - shootChange) * 0.67 / fov, width / fov, (height - shootChange) * 0.67 / fov ); }; canvas.beginPath(); canvas.moveTo( (x - width / 2) / fov, -(height - shootChange) * 0.67 / fov ); canvas.lineTo( (x - width) / fov, -(height - shootChange) / fov ); canvas.lineTo( (x + width) / fov, -(height - shootChange) / fov ); canvas.lineTo( (x + width / 2) / fov, -(height - shootChange) * 0.67 / fov ); canvas.fill(); if (document.getElementById('theme').value != 'simplistic') { canvas.stroke(); }; }; function newminebarrel(canvas, x,width,height,shootChange, fov){ canvas.fillRect( (x - width / 2) / fov, -(height - shootChange) / fov, width / fov, (height - shootChange) / fov ); if (document.getElementById('theme').value != 'simplistic') { canvas.strokeRect( (x - width / 2) / fov, -(height - shootChange) / fov, width / fov, (height - shootChange) / fov ); }; canvas.fillRect( (-width * 1.5) / 2 / fov + x / fov, -(height - shootChange) * 0.67 / fov, (width / fov) * 1.5, (height - shootChange) * 0.67 / fov ); if (document.getElementById('theme').value != 'simplistic') { canvas.strokeRect( (-width * 1.5) / 2 / fov + x / fov, -(height - shootChange) * 0.67 / fov, (width / fov) * 1.5, (height - shootChange) * 0.67 / fov ); }; }; function newminionbarrel(canvas, x,width,height,shootChange, fov){ canvas.fillRect( (x - width / 2) / fov, -(height - shootChange) / fov, width / fov, (height - shootChange) / fov ); if (document.getElementById('theme').value != 'simplistic') { canvas.strokeRect( (x - width / 2) / fov, -(height - shootChange) / fov, width / fov, (height - shootChange) / fov ); }; canvas.fillRect( (x - width * 0.75) / fov, -(height - shootChange) / 1.5 / fov, (width / fov) * 1.5, (height - shootChange) / 1.5 / fov ); if (document.getElementById('theme').value != 'simplistic') { canvas.strokeRect( (x - width * 0.75) / fov, -(height - shootChange) / 1.5 / fov, (width / fov) * 1.5, (height - shootChange) / 1.5 / fov ); }; canvas.fillRect( (x - width * 0.75) / fov, -(height - shootChange) / fov, (width / fov) * 1.5, (height - shootChange) / 5 / fov ); if (document.getElementById('theme').value != 'simplistic') { canvas.strokeRect( (x - width * 0.75) / fov, -(height - shootChange) / fov, (width / fov) * 1.5, (height - shootChange) / 5 /fov ); }; }; drawobjects = newdraw; drawPlayer = newdrawplayer; drawBulletBarrel = newbulletbarrel; drawDroneBarrel = newdronebarrel; drawTrapBarrel = newtrapbarrel; drawMineBarrel = newminebarrel; drawMinionBarrel = newminionbarrel; let pd = false; const editloop = () => { if (player.health <= 1 && !pd && gameStart == -1) { if (autorespawn) { document.getElementById('continue').click(); document.getElementById('play').click(); }; pd = true; } else if (player.health > 1) { pd = false; }; requestAnimationFrame(editloop); }; editloop(); })();