Number.parseInt=parseInt;(function(arr){arr.forEach(function(item){if(item.hasOwnProperty('remove')){return;}
Object.defineProperty(item,'remove',{configurable:true,enumerable:true,writable:true,value:function remove(){this.parentNode.removeChild(this);}});});})([Element.prototype,CharacterData.prototype,DocumentType.prototype]);function log(msg){if(DEBUG_MODE_ENABLED){var func=arguments.callee.caller.name;msg=msg||'';console.log(arguments.callee.caller.name+"() --> "+msg);}}
function getURLParameter(name){return decodeURIComponent((new RegExp('[?|&]'+name+'='+'([^&;]+?)(&|#|;|$)').exec(location.search)||[null,''])[1].replace(/\+/g,'%20'))||null;}
var util={get:function(id){return document.getElementById(id)},getClass:function(className){return document.getElementsByClassName(className);},html:function(id,val){var e=document.getElementById(id);if(val)return e.innerHTML=val;else return this.getElementById},size:function(id,val){var e=document.getElementById(id);if(val){e.style.width=val.x+'px';e.style.height=val.y+'px';}
else return{x:e.offsetWidth,y:e.offsetHeight}},randomArray:function(items){if(!items||!Array.isArray(items)){return null;}
return items[~~(items.length*Math.random())];},uniqueId:function(){return Math.random().toString(36).substring(2)
+(new Date()).getTime().toString(36);}}
const TANKS_VERSION="0.72";const DEBUG_MODE_ENABLED=false;var difficulty=1,ratio=1,startingMoney=100,winPayout=500,hitPayout=250,cheatsEnabled=false;soundEnabled=true;particle_WeatherEnabled=false,tankMax=4,tankPlayers=4,tankNo=0,showCompassQ=true,tanks=[],aiOnlyTurns=0,clrs=[["Blue",'#0066FF'],["Red",'#FF0000'],["Orange",'#ff7700'],["Purple",'#9155ff']],windForce=0,maxWindForce=.015,gravityForce=.03,ters=[['images/bg/basic.svg','#578641',[0.40,0.6,0.3,0.1,0.05,0.02,0.001,0.001,0],0.2,'Grassland','grass-texture',0.03],['images/bg/desert.svg','#bea276',[0.08,0.04,0.03,0.02,0.01,0.002,0.0001,0.0001,0],0.01,'Desert','desert-texture',0.03],['images/bg/snow.svg','#fafaff',[0.0,0.0,0.5,0.15,0.0,0.02,0.002,0.001,0],0.05,'Snow','snow-texture',0.03],['images/bg/forest.svg','rgb(50,150,16)',[0.4,0.6,0.3,0.1,0.05,0.02,0.001,0.001,0],0.06,'Forest','forest-texture',0.03],['images/bg/hills.svg','#359539',[0.4,0.6,0.3,0.1,0.05,0.02,0.001,0.001,0],0.06,'Hills','hills-texture',0.03],['images/bg/moon.svg','#888',[0.40,0.6,0.03,0.1,0.05,0.02,0.001,0.001,0],.3,'Moon','moon-texture',0.011],['images/bg/city.svg','#578641',[.2,0,0,0,0,0,0,0,0],.3,'City','grass-texture',0.03],['images/bg/city-night2.svg','#888',[.2,0,0,0,0,0,0,0,0],.5,'City-Night','moon-texture',0.03],['images/bg/beach.svg','#bea276',[.2,.2,.2,0,0,0,0,0,0],.01,'Beach','desert-texture',0.03]],terPts=[],terMax=9,terNo=0,terBottomOffset=18,terTopOffset=75;var costMap={'Fuel':50,'Health':75,'Shield':150,'Targeting':200,'Medium Shell':50,'Large Shell':200,'Cannon Ball':300,'EMP':500,'Atomic Shell':750,'Air Strike':1000,'Napalm':1000,'Sniper Shell':500,'Flak Cannon':500}
var tanksTimesClicked=0;var newRound=false;var titleMute=true;var timeouts=[];var demoModeEnabled=false;var skipAiRound=false;var resolution={x:Number(getURLParameter('width'))||window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth,y:Number(getURLParameter('height'))||window.innerHeight||document.documentElement.clientHeight||document.body.clientHeight}
if(resolution.y>resolution.x){var tmp=resolution.x;resolution.x=resolution.y;resolution.y=tmp;}
if(resolution.x<800){resolution.x*=1.25;resolution.y*=1.25;}
function tanksMain(){log('<==== tanksMain ====>')
window.addEventListener('load',function(){document.getElementById('load-screen').onclick=function(){this.style.display='none';document.getElementById('game').style.display='block';}
var text=document.getElementById('load-screen').children[0];text.innerHTML="OK!";text.style.background="white";text.style.transform="rotate(-3deg);"
window.oncontextmenu=function(event){log("prevent context menu");event.preventDefault();event.stopPropagation();return false;};});window.addEventListener('resize',screenResized);if(!soundEnabled)document.getElementById('mute-control-checkbox').checked=true;if(cheatsEnabled)document.getElementById('cheats').style.display="block";setVersion(TANKS_VERSION);initRendering();setTerrain(0);updateParticles();showHud(false);showMainMenu(true);bindButtonHandlers();popPlayerSelect(tankPlayers);setBackground(ters[0][0]);drawGrid();toggleGrid();demoMode();}
function toggleFullScreen(){var doc=window.document;var docEl=doc.documentElement;var requestFullScreen=docEl.requestFullscreen||docEl.mozRequestFullScreen||docEl.webkitRequestFullScreen||docEl.msRequestFullscreen;var cancelFullScreen=doc.exitFullscreen||doc.mozCancelFullScreen||doc.webkitExitFullscreen||doc.msExitFullscreen;if(!doc.fullscreenElement&&!doc.mozFullScreenElement&&!doc.webkitFullscreenElement&&!doc.msFullscreenElement){requestFullScreen.call(docEl);}
else{cancelFullScreen.call(doc);}
screenResized();}
function screenResized(){log();var scale={x:document.body.offsetWidth/resolution.x,y:document.body.offsetHeight/resolution.y}
ratio=Math.min(scale.x,scale.y)
var dim={x:(resolution.x*ratio),y:(resolution.y*ratio)}
util.size('game',dim);var cans=document.getElementsByTagName('canvas');var x=cans.length;for(var i=0;i';var selected=i==0?0:1;s+=getDropdownHTML(['Human','Computer'],'funcy','playerType'+i,selected);s+='';}
elem.innerHTML=s;log("Player selection panels created.");}
function buy(name){log("Buy: "+name);var tank=tanks[tankNo];var cost=costMap[name];if(tank.money90?180-tank.dangle:tank.dangle)+'°';force.innerHTML=tank.force;gas.innerHTML=tank.fuel;money.innerHTML=tank.money;blueScore.innerHTML=tanks[0].kills;redScore.innerHTML=tanks[1].kills;orangeScore.innerHTML=tanks[2].kills;purpleScore.innerHTML=tanks[3].kills;for(i=0;iBullet initial velocity:
("+vX.toFixed(1)+" , "+vY.toFixed(1)+")
";s+="Gravity acceleration:
"+gravityForce+"
";s+="Your position:
("+pX.toFixed(1)+" , "+pY.toFixed(1)+")
";s+="Bullet position after 1 second:
("+(pX+vX).toFixed(1)+" , "+(pY+vY-gravityForce).toFixed(1)+")
";s+=""
infoPanel.innerHTML=s;}
function payToPlot(){if(tanks[tankNo].money<50){flashMessage('Not Enough Money',2000,'red');return;}
else{flashMessage("GRAPHING ACTION!",2500,'orange');}
tanks[tankNo].money-=50;updateHud();drawGrid();var points=[];var tank=tanks[tankNo];var a=tank.dangle*(Math.PI/180);var g=document.getElementById('grid-canvas').getContext('2d');var m=.5,n=500,int=5;var p={x:tank.barrelX,y:tank.barrelY},v={x:Math.cos(a)*tank.force/5,y:Math.sin(a)*tank.force/5}
console.log(p,v);for(var i=0;i0){points.push([p.x,p.y]);}else break;}
console.log(points);drawParabola(g,tank.clr,points,int);}
function createTanks(){for(var i in tanks){tanks[i].cleanupAndRemove();tanks[i]=null;}
tanks=[];for(var i=0;it.x/resolution.x)?1:-1;aimove();}}
function aimove(){var t=tanks[tankNo];if(!t.aiq)return;if(t.fuel>0){move(t.aiDirn);}
else{log("ai tank out of fuel");}
if(Math.random()>0.25){timeouts.push(setTimeout(aimove,200));}else{timeouts.push(setTimeout(aiplay,200));}}
function aiequip(){var t=tanks[tankNo];if(!t.aiq)return;for(var i=t.weapons.length-1;i>-1;i--){if(t.weapons[i].ammo>0){t.currentWeapon=i;log("AI tank equips "+t.weapons[i].name);return;}}
t.currentWeapon=0;}
function aishop(){var t=tanks[tankNo];if(!t.aiq)return;var chanceToBuy;if(difficulty==0)chanceToBuy=.1;else if(difficulty==1)chanceToBuy=.3;else if(difficulty==2)chanceToBuy=.6;else if(difficulty>=3)chanceToBuy=.8;if(Math.random()>chanceToBuy)return;function tryBuy(n){if(t.money>=costMap[n]){buy(n);}}
var buyRounds=0;while((buyRoundsMath.max(Math.min(1000,Math.random()*t.money)),t.money/2)){buyRounds++;if(t.health<50){tryBuy('Health');}
if(t.fuel==0){tryBuy('Fuel');}
if(Math.random()>.5&&t.shields<3){tryBuy('Shield')}
tryBuy('Napalm');tryBuy('EMP');tryBuy('Atomic Shell');tryBuy('Cannon Ball');tryBuy('Large Shell');tryBuy('Medium Shell');tryBuy('Sniper Shell');tryBuy('Targeting');}}
function aiplay(){var t=tanks[tankNo];if(!t.aiq)return;var tries=10-(2-difficulty);var triesData=[];var dmax=1e11;var tanksLeft=0,tanksRight=0;for(var i=0;i0){if(tanks[i].xt.x)tanksRight++;}}
if(t.dangle>90&&tanksLeft==0)t.dangle=45;else if(t.dangle<90&&tanksRight==0)t.dangle=135;for(var i=0;i0){f+=getRandomInt(-5,5);a+=getRandomInt(-25,25);}
var d=t.aifire(f,a);triesData.push([d,f,a]);}
triesData.sort(function(a,b){if(a[0]b[0])return 1;return 0;});var chosenTry=triesData[Math.max(0,2-difficulty)];if(typeof t.lastShotDistance=="undefined"){t.lastShotDistance=1e11;}
log(triesData);if(t.lastShotDistance>chosenTry[0]||t.lastShotOutOfBounds){log('New shot setup: '+chosenTry);t.lastShotDistance=chosenTry[0];t.force=chosenTry[1];t.dangle=chosenTry[2];t.draw();}
else{log("Using last shot setup");}
t.fire();}
function shakeScreen(){var shakeTime=.82;var gameEl=document.getElementById('game');gameEl.style.animation="shake "+shakeTime+"s cubic-bezier(.36,.07,.19,.97) both"
setTimeout(function(){gameEl.style.animation=""},shakeTime*1000);}
function setBackground(image){log("Set background: "+image);var div=document.getElementById('bg');div.style.backgroundImage="url('"+image+"')";}
function setGravity(n){gravityForce=n;}
function setTerrain(n){log();terNo=n;setBackground(ters[n][0]);setGravity(ters[n][6])
terPts=terrain(resolution.x,resolution.y+20,ters[n][2],ters[n][3]);drawTerrain();}
function nextTerrain(){log("Choosing next terrain");terNo=(++terNo)%terMax;setTerrain(terNo);}
function randomTerrain(){terNo=getRandomInt(0,terMax-1);log("Choosing random terrain: "+terNo);setTerrain(terNo);}
function newGame(id){log("newGame id="+id);flashMessage("START!",1250);newRound=true;tankNo=0;for(var i in timeouts){window.clearTimeout(timeouts[i]);}
if(document.getElementById('wind-control-checkbox').checked){randomWind();}
else{windForce=0;}
updateDifficulty();initPlayers();overQ=false;showCompassQ=true;showMainMenu(false);showHud(true);var terSelect=document.getElementById('terrain-select-box');if(terSelect.selectedIndex==0){randomTerrain();}
else{terNo=terSelect.selectedIndex-1;setTerrain(terNo);}
particle_WeatherEnabled=Math.random()>.5;particles=[];resetTanks();drawTanks();updateHud();if(tanks[tankNo].aiq){aistt();}}
function newMatch(){demoModeEnabled=false;util.get('skip-ai-match-button').style.display="none";for(var i=0;i=.5)windForce*=-1;log('randomWind = '+windForce);}
function resetTanks(){log('Resetting tanks');var w=resolution.x;var range=w/3,tankStts=[[0,45],[w-range,135],[w*.25,135],[w*.75,45]];for(var i=0;i1)tank.force-=0.1;tank.force=Number(tank.force.toFixed(1));tank.drawUI();document.getElementById('force-range-control').value=tank.force;}
function angleDecrement(n){n=n||1;playSound('aim');var tank=tanks[tankNo];if(tank.dangle+n<200)tank.dangle+=n;tank.drawUI();document.getElementById('angle-range-control').value=tank.dangle;}
function angleIncrement(n){n=n||1;playSound('aim');var tank=tanks[tankNo];if(tank.dangle-n>-20)tank.dangle-=n;tank.drawUI();document.getElementById('angle-range-control').value=tank.dangle;}
function key(ev){var mainMenuButton=document.getElementById('main-menu-button');mainMenuButton.focus();mainMenuButton.blur();var tank=tanks[tankNo];if(!tank.loaded||tank.aiq)return;log("Handling key event ",ev)
var tank=tanks[tankNo];var keyCode=ev.keyCode;var yesq=false;switch(keyCode){case 37:angleDecrement(1);yesq=true;break;case 39:angleIncrement(1);yesq=true;break;case 38:forceUp();yesq=true;break;case 40:forceDown();yesq=true;break;case 65:move(-1);yesq=true;break;case 68:move(1);yesq=true;break;default:break;}
if(yesq){ev.preventDefault();}
if(keyCode==9||keyCode==13||keyCode==32){fire();ev.preventDefault();}
updateHud();}
function move(d){log("move",d);var tank=tanks[tankNo];var newPosition=tank.x+(tank.moveIncrement*d);if(newPosition<0||newPosition>resolution.x){flashMessage('Out of bounds');return;}
if(tank.fuel>0){tank.move(d);playSound('move');}
else{flashMessage('Out of Fuel');}}
function drawTerrain(){var canvas=document.getElementById('terrain-canvas');var ctx=canvas.getContext('2d');log("drawing terrain");ctx.clearRect(0,0,resolution.x,resolution.y);ctx.beginPath();var pattern=ctx.createPattern(document.getElementById(ters[terNo][5]),'repeat');ctx.fillStyle=pattern;ctx.strokeStyle="rgba(0,0,0,.3)";ctx.lineWidth=2;ctx.moveTo(0,terPts[0]);for(var t=1;t0){flashMessage(tanks[i].name+" Victory!",1500,tanks[i].clr,newGame);}}});}
else{fromTank.kills++;flashMessage(fromTank.name+' Destroyed '+toTank.name+'!',1500,fromTank.clr,function(){payTank(fromTank,winPayout);if(overQ)flashMessage(fromTank.name+" Victory!",1500,fromTank.clr,newGame);});}
updateHud();}
function fire(){newRound=false;showHud(false);tanks[tankNo].fire();}
function hideTitle(){newMatch();document.getElementById('main-menu-exit-button').style.display="block";titleMute=false;}
function showMainMenu(v){if(v==null)v=true;log("Show Main Menu: "+v);var el=document.getElementById("main-menu");el.style.right=v?"0":"3000px";showStoreMenu(false);showHud(!v);el.blur();}
function updateStoreCounts(){log('update store counts');var tank=tanks[tankNo];var valMap={'health-item':tank.health,'fuel-item':tank.fuel,'shield-item':tank.shields,'medium-shell-item':tank.weapons[1].ammo,'large-shell-item':tank.weapons[2].ammo,'atomic-shell-item':tank.weapons[3].ammo,'cannon-ball-item':tank.weapons[4].ammo,'air-strike-item':tank.weapons[5].ammo,'emp-item':tank.weapons[6].ammo}
for(var i in valMap){var el=document.getElementById(i);if(el){var cnt=el.getElementsByClassName('item-count')[0];if(cnt)cnt.innerHTML=valMap[i];}}}
function showStoreMenu(v){if(v==null)v=true;log("Show Items Menu: "+v);var el=document.getElementById("store-menu");el.style.bottom=v?"0":"200%";if(v)updateStoreCounts();showHud(!v);}
function showHud(v){if(v==null)v=true;log('Show Hud: '+v);var h=document.getElementById('hud');h.style.opacity=v?".75":"0";var d=document.getElementById('disabler-div');d.style.display=v?"none":"block";}
function randomWinner(){log("pick random winner");console.log('pick random winner');var winner=null;while(!winner){var t=util.randomArray(tanks);if(t.health>0)winner=t;}
console.log('winner is ',winner);for(var i in tanks){if(tanks[i]!==winner){var data={victim:tanks[i],aggressor:winner,type:"Napalm",damage:300}
doDamage(data);}}}
function nextTurn(){log('Next Turn');var humans=0;for(var i in tanks){if(!tanks[i].aiq&&tanks[i].health>0){humans++;}};if(humans<1&&!demoModeEnabled&&!skipAiRound){util.get('skip-ai-match-button').style.display='block';difficulty=25;}
if(skipAiRound){console.log('skip AI Round');skipAiRound=false;randomWinner();}
if(newRound){return;}
do{tankNo=(++tankNo)%tankPlayers;}
while(tanks[tankNo].health<=0)
showCompassQ=true;tanks[tankNo].drawUI();if(!overQ){showHud();var tank=tanks[tankNo];tank.loaded=true;if(tank.aiq)aistt();}
else{showHud(false);}
updateHud();}
function terrain(width,height,hts,smooth){log('Creating terrain');var pts=[],power=Math.pow(2,Math.ceil(Math.log(width)/(Math.log(2))));var htN=0;var displace=height*hts[htN];pts[0]=height/2+(Math.random()*displace*2)-displace;pts[power]=height/2+(Math.random()*displace*2)-displace;for(var i=1;icurrSlope)currSlope=Math.min(slope,currSlope+smooth);if(slope';for(var i=0;i'+opts[i]+'';}
s+='';return s;}
function toggleGridInfo(){var c=document.getElementById('grid-info-panel');if(c.style.top=="0px"){c.style.top="-250px";c.style.opacity=".3";}
else{c.style.top="0px";c.style.opacity="1";}}
function toggleGrid(){var info=document.getElementById("grid-info-panel");var c=document.getElementById('grid-canvas');if(c.style.display=="none"){c.style.display="block";}
else{c.style.display="none";}
info.style.display=c.style.display;}
function drawGrid(){var c=document.getElementById('grid-canvas');var ctx=c.getContext('2d');var w=resolution.x,h=resolution.y;ctx.clearRect(0,0,w,h);var minor=50;var major=100;for(var i=0;i0&&shellX0){}else{best=1e10;worst=1e10;for(var j=0;j0){if(t==this){worst=Math.min(worst,Math.abs(xPos-t.x));}else{best=Math.min(best,Math.abs(xPos-t.x));}}}
movingq=false;}}else{movingq=false;}}while(movingq);var selfDmgDist=60;if(worst=this.fireanim_step){this.shellPoints.push([this.shellX,this.shellY]);this.drawProjectiles();this.fireanim_acc=0;}
if(this.shellX>0&&this.shellX0&&touchingTanks.length<=0){requestAnimationFrame(this.fireAnim.bind(this));if(weaponName=='Napalm'){if(Math.random()>.6){var p=particleFactory.napalm(this);p.position.x=this.shellX;p.position.y=this.shellY;p.velocity.x=this.vX;p.velocity.y=0;}}}
else{log(weaponName+' projectile impact');if(weaponName=='Cannon Ball'){if(!this.bombOnGround){log("Cannon ball hit ground")
this.bombOnGround=true;this.bombStartTime=ts;this.bombTimer=2500;requestAnimationFrame(this.fireAnim.bind(this));}
else{this.shellY=yPos;this.vY=0;this.vX*=.98;var nextPoint=this.shellX+this.vX;var nextY=terPts[nextPoint<<0];var uphill=nextY0){var dx=Math.abs(tanks[i].x-this.shellX);var dy=Math.abs(tanks[i].y-this.shellY);if(dxthis.bombTimer||bombTouchingTank){log("cannon ball exploded");this.loaded=true;this.bang(this.shellX,this.shellY);this.bombOnGround=false;}
else{requestAnimationFrame(this.fireAnim.bind(this));}}}
else{log('this thing should blow up now');this.bang(this.shellX,this.shellY);}}}
else{log("projectile out of bounds");this.lastShotOutOfBounds=true;log('time to end turn');this.endTurn()}};Tank.prototype.explode=function(from){if(overQ)return;playSound('explode');var e=document.getElementById('explosion');var offsetX=this.effectCanvas.offsetLeft;var offsetY=this.effectCanvas.offsetTop;e.style.top=(ratio*this.y-20+offsetX)+"px";e.style.left=(ratio*this.x-20+offsetY)+"px";e.src="images/sprites/explode.gif";log("tank explode");frag(from,this);};Tank.prototype.muzzle=function(){log('muzzle');this.muzzleAnim();};Tank.prototype.muzzleAnim=function(){log('muzzleAnim');var fireNow=Date.now();var g=this.effectCanvas.getContext('2d');g.clearRect(0,0,resolution.x,resolution.y);if(fireNow<500){g.fillStyle='#ee0';g.beginPath();g.arc(this.barrelX,this.barrelY,fireNow/70,0,2*Math.PI);g.closePath();g.fill();requestAnimationFrame(this.muzzleAnim.bind(this));}};Tank.prototype.bang=function(x,y){log('bang');this.shellX=-1000;this.shellY=-1000;this.bangX=x;this.bangY=y;this.bangStt=Date.now();this.lastFiredWeapon=this.currentWeapon;var sz=this.weapons[this.currentWeapon].damage;var xi=x<<0;var yHt=terPts[xi]+sz*0.5;var min=Math.max(0,xi-sz*3)<<0;var max=Math.min(resolution.x,xi+sz*3)<<0;if(this.weapons[this.currentWeapon].name!="EMP"&&this.weapons[this.currentWeapon].name!="Sniper Shell"){for(var i=min;i=0&&(d0){var r=(this.shields+15);var grd=g.createRadialGradient(this.x,this.y-20,r/4,this.x,this.y,r*2);grd.addColorStop(0,'rgba(0,189,240,.2)');grd.addColorStop(0.8,'rgba(0,200,255,.7)');grd.addColorStop(.9,'rgba(0,189,240,0)');grd.addColorStop(1,'rgba(0,0,0,0)');g.fillStyle=grd;g.fillRect(this.x-100,this.y-100,200,200);}}
Tank.prototype.drawProjectiles=function(){var g=this.effectCanvas.getContext('2d');g.clearRect(0,0,resolution.x,resolution.y);if(this.shellPoints.length>0){drawParabola(g,this.color,this.shellPoints,2);}
var ht=terPts[Math.round(this.shellX)]-this.shellY;if(ht>0){g.fillStyle=this.clr;g.lineWidth=1;g.strokeStyle='rgba(0,0,0,.1)';g.beginPath();var r=this.weapons[this.currentWeapon].size;g.arc(this.shellX,this.shellY,r,0,2*Math.PI);g.closePath();g.fill();g.stroke();}}
Tank.prototype.drawUI=function(){var g=this.uiCanvas.getContext('2d');g.clearRect(0,0,resolution.x,resolution.y);var sz=12,barrelOffset={x:0,y:-sz*0.8},barrelLength=sz*1.5,barrelWidth=sz*0.2,angle=this.dangle*(Math.PI/180);if(this.id==tankNo&&showCompassQ){var userAng=this.dangle;if(userAng>90)userAng=180-userAng;drawVector(g,this.x+barrelOffset.x,this.y+barrelOffset.y/2,this.dangle,this.force);g.textAlign='center';g.font='16px uiFont';g.fillStyle=this.clr;g.fillText(userAng+'\u00B0',this.x,this.y-55);g.font='14px uiFont';g.fillText(this.force,this.x,this.y+20);drawCompass(g,this.x+barrelOffset.x,this.y+barrelOffset.y/2,25);var points=[];var tank=this;var a=tank.dangle*(Math.PI/180);var m=.5,n=50*tank.targeting,int=5;var p={x:tank.barrelX,y:tank.barrelY},v={x:Math.cos(a)*tank.force/5,y:Math.sin(a)*tank.force/5}
for(var i=0;i0){points.push([p.x,p.y]);}else break;}
drawParabola(g,tank.clr,points,int);}
if(this.health>0){g.fillStyle="lime";g.fillRect(this.x-12,this.y+5,this.health/100*24,2);g.fillStyle=this.clr;g.strokeStyle=this.clr;g.lineWidth=barrelWidth;g.lineCap="butt";g.beginPath();g.moveTo(this.x+barrelOffset.x,this.y+barrelOffset.y);this.barrelX=this.x+Math.cos(angle)*barrelLength;this.barrelY=this.y-8-Math.sin(angle)*barrelLength;g.lineTo(this.barrelX,this.barrelY);g.stroke();}}
Tank.prototype.draw=function(){this.drawSprite()
this.drawUI();};var particles=[];var particles_pool=[];var particlesToRemove=[];var particleFrame=0;var particleAcc=0;var particleStep=28
var weatherAcc=0;var particleBounds=getBounds();function clearParticleCanvas(){var c=util.get('particle-canvas');var ctx=c.getContext('2d');ctx.clearRect(0,0,resolution.x,resolution.y);}
function getNewParticle(owner){if(particles_pool.length>0){var p=particles_pool[0];particles_pool.splice(0,1);p.reset();p.owner=owner;return p;}
return new Particle(owner);}
function getBounds(arr){if(!arr||!Array.isArray(arr)||arr.length<1)return{x:0,y:0,w:0,h:0}
var minX=arr[0].x,minY=arr[0].y,maxX=minX+arr[0].w,maxY=minY+arr[0].h;arr.map(function(){minX=Math.min(arr[i].x,minX);minY=Math.min(arr[i].y,minY);maxX=Math.max(arr[i].x+arr[i].w,maxX);maxY=Math.max(arr[i].y+arr[i].h,maxY);});return{x:minX,y:minY,w:maxX-minX,h:maxY-minY}}
function removeDeadParticles(){if(particlesToRemove.length>0){particlesToRemove.forEach(function(e){particles_pool.push(e);var idx=particles.indexOf(e);if(idx>-1)particles.splice(idx,1);})
particlesToRemove=[];}}
function updateParticles(ts){var ctx=util.get('particle-canvas').getContext('2d');var dt=(ts-particleFrame)||0;particleAcc+=dt;particleFrame=ts;weatherAcc+=dt;var sfx_enabled=util.get('fx-control-checkbox').checked;if(weatherAcc>300&&particle_WeatherEnabled&&sfx_enabled){for(var i=0;i<3;i++){weatherAcc=0;var x=Math.floor(Math.random()*resolution.x);var p;if(terNo==2){p=particleFactory.snow();p.position.y=0;p.position.x=x;}}}
while(particleAcc>=particleStep){particleAcc-=particleStep;ctx.clearRect(particleBounds.x,particleBounds.y,particleBounds.w,particleBounds.h);removeDeadParticles();if(particles.length>0){var r=particles[0].getBounds();var minX=r.x,minY=r.y,maxX=minX+r.w,maxY=minY+r.h;for(var i=0;i20){for(var i=0;i<10;i++){var p=particleFactory.dirt();p.position.x=x+(Math.random()*5)-(2.5);p.position.y=terPts[Math.round(x)]-3;p.velocity.y=-Math.random()*100;p.velocity.x+=Math.random()*30-15}}
drawTerrain();drawTanks();}
function Particle(owner){this.reset();this.owner=owner;}
Particle.prototype.getBounds=function(){var s=this.size*2;var x=this.position.x;var y=this.position.y;var r={x:0,y:0,w:s,h:s};if(this.type=="ball"){r.x=x-r.w/2-1;r.y=y-r.h/2;}
else if(this.type=="block"){r.x=x-1;r.y=y-1;}
return r;}
Particle.prototype.reset=function(){this.disabled=false;this.corrosive=false;this.owner=null;this.damage=0;this.size=25;this.time=0;this.maxTime=0;this.position={x:0,y:0};this.velocity={x:0,y:0};this.bombTime=0;this.bombAcc=0;this.type=Math.random()>.5?"ball":"block";this.color="purple";this.physical=true;this.hasMass=true;this.hasWindResistance=false;this.onUpdate=null;this.image=null;}
Particle.prototype.launch=function(x,y,vx,vy,drift){drift=drift||0;this.position.x=x+(Math.random()*(drift/2))-drift/4;this.position.y=y+(Math.random()*(drift/2))-drift/4;this.velocity.x=vx+(Math.random()*drift)-drift/2;this.velocity.y=vy+(Math.random()*drift)-drift/2;}
Particle.prototype.getAltitude=function(){return terPts[Math.round(this.position.x)]-this.position.y;}
Particle.prototype.update=function(deltaTime){this.position.x+=this.velocity.x*deltaTime;this.position.y+=this.velocity.y*deltaTime;if(this.hasMass){this.velocity.y+=gravityForce*100;}
if(this.hasWindResistance){this.velocity.x-=this.velocity.x*.01;}
if(this.maxTime>0){this.time+=deltaTime;if(this.time>=this.maxTime)removeParticle(this);}
if(this.position.x<0||this.position.x+this.size>resolution.x||(this.position.y<-100)||this.position.y+this.size>resolution.y){removeParticle(this);}
if(this.corrosive){if(this.owner){var arr=getTanksTouching(this.position.x,this.position.y,this.size*2);for(var i in arr){var data={victim:arr[i],aggressor:this.owner,type:"Napalm",damage:this.damage}
doDamage(data);removeParticle(this);}}}
if(this.physical){var h=this.getAltitude();if(h<=0){if(this.corrosive){holeInTheGround(this.position.x,this.size,this.size)
drawTerrain();drawTanks();removeParticle(this)}
else{this.position.y=terPts[Math.round(this.position.x)];this.velocity.y=10;}}}}
Particle.prototype.render=function(){var ctx=util.get('particle-canvas').getContext('2d');ctx.strokeWidth=0;ctx.strokeStyle=this.color;ctx.fillStyle=this.color;if(this.type=="block"){ctx.fillRect(this.position.x,this.position.y,this.size,this.size);}
else if(this.type=="ball"){ctx.beginPath();ctx.arc(this.position.x,this.position.y,this.size/2,0,2*Math.PI)
ctx.fill();}
if(this.image){ctx.drawImage(this.image,this.position.x,this.position.y,this.size,this.size);}}
var particleFactory={bullet:function(owner){var p=getNewParticle(owner);p.corrosive=true;p.physical=true;p.hasMass=true;p.damage=15;p.size=5;p.time=0;p.maxTime=2000;p.velocity.x=10;p.velocity.y=-10;p.color='black';particles.push(p);return p;},napalm:function(owner){var p=getNewParticle(owner);p.corrosive=true;p.physical=true;p.hasMass=true;p.hasWindResistance=true;p.damage=10;p.size=Math.random()*3+2;p.time=0;p.maxTime=Math.random()*6+4;p.velocity.x=Math.random()*250-125;p.velocity.y=-Math.random()*150-75;p.color='#fbe658';var r=Math.random();if(r<.3)p.color='#4b4044';else if(r<.6)p.color='#aa2316';else if(r<.9)p.color='#fa5429';particles.push(p);return p;},snow:function(owner){var p=getNewParticle(owner);p.size=Math.random()*5+2;p.hasMass=false;p.time=0;p.velocity.y=Math.random()*100+50;p.maxTime=Math.random()*20;p.color='white';particles.push(p);return p;},dirt:function(owner){var p=getNewParticle(owner);p.size=Math.random()*3+2;p.time=0;p.velocity.x=Math.random()*40-20;p.velocity.y=Math.random()*40-20;p.maxTime=Math.random()*2;p.color=ters[terNo][1];particles.push(p);return p;},shrapnel:function(owner){var p=getNewParticle();p.size=Math.random()*4+2;p.velocity.x=200*Math.random()-100
p.velocity.y=200*Math.random()-100;p.time=0;p.type='ball'
var r=Math.random();p.maxTime=r;p.velocity.x=Math.random()*30-15;p.velocity.y=Math.random()*30-15;if(r<.8)p.color="rgba(255,0,0,.3)";else p.color="rgba(200,100,0,.2)";particles.push(p);return p;},smoke:function(owner){var p=getNewParticle(owner);var r=Math.random();if(r>.3)p.color='rgba(0,0,0,.5)';else p.color='rgba(255,0,0,.5)';p.physical=false;p.hasMass=false;p.time=0;p.maxTime=r<.6?Math.random()*2.5:r*1.8;p.size=Math.random()*3+1
p.velocity.x=30*Math.random()-15
p.velocity.y=Math.random()*-50;particles.push(p)
return p;},plane:function(owner){var p=getNewParticle(owner);p.color="rgba(0,0,0,0)";p.image=util.get('plane-img');p.size=40;p.position.x=0;p.position.y=10+(Math.random()*30);p.physical=false;p.hasMass=false;p.time=0;p.maxTime=5000;p.velocity.x=100+(Math.random()*200);p.velocity.y=0;p.bombTime=500;p.bombAcc=p.bombTime;p.onUpdate=function(dt){p.bombAcc+=dt;if(p.bombAcc>=p.bombTime){p.bombAcc=0;var dist=99999;if(p.owner){dist=Math.abs((p.owner.x+13)-(p.position.x+p.size/2));if(p.position.x60){var b=particleFactory.bomb(p.owner);b.position.x=p.position.x+p.size/2;b.position.y=p.position.y+p.size;b.velocity.x=p.velocity.x*.1;b.velocity.y=10;}}}
particles.push(p);return p;},bomb:function(owner){var p=getNewParticle(owner);p.color="rgba(0,0,0,0)";p.image=util.get('bomb-img');p.size=25;p.physical=true;p.hasMass=true;p.corrosive=true;p.hasWindResistance=true;p.damage=35;p.time=0;p.maxTime=5000;particles.push(p);return p;}}
function ParticleEmitter(func,delay){this.delay=100;this.acc=0;this.particleFunc=func;this.position={x:0,y:0};this.velocity={x:0,y:0};}
ParticleEmitter.prototype.update=function(dt){this.acc+=dt;if(this.acc>this.delay){this.acc=0;this.position.x+=this.velocity.x*dt;this.position.y+=this.velocity.y*dt;if(this.particleFunc)this.particleFunc();}}