Deathshadow's Madness
Madness and you, perfect together

JavaScript Source Code

/* canvas game library */

var
	paintInterval=30; /* roughly 30fps after 'overhead' */
	timeReport=document.getElementById('timeReport'),
	upSize=document.getElementById('upSize'),
	cCanvas=document.createElement('canvas'),
	frameControl=0,
	frameAdjust=1,
	mouseX=0,
	mouseY=0,

	bobbing1=0,
	bobbing2=0.5,
	bobbing1dir=0.03,
	bobbing2dir=0.04,

	resX=640,    resY=400,
	aspect=resY/resX;
	maxX=resX-1, maxY=resY-1,
	renderScale=1,

	throttleCount=0,
	throttleTime=0,

	skyGradient=0,

	waterLines=[],
	destroyers=[],
	subs=[],
	oceanOffset=maxY-72;

	landGradient=0,
	landStartX=resX/4
	landEndX=landStartX*3,
	landOffsetY=oceanOffset-3,
	cities=[],

	hexRadians=Math.PI/16;

function cityScape(offsetX,offsetY) {
	this.buildingHeight=[];
	this.buildingX=[];
	this.buildingColor=[];
	this.offsetY=offsetY;
	for (var n=0; n<16; n++) {
		this.buildingHeight[n]=10+Math.floor(Math.random()*14)*Math.sin(n*hexRadians);
		this.buildingX[n]=n*4+offsetX;
		var cc=128+Math.floor(Math.random()*96);
		this.buildingColor[n]='rgb('+cc+','+cc+','+cc+')';
	}
	for (var n=0; n<8; n++) {
		this.buildingHeight[n+16]=6+Math.floor(Math.random()*8)*Math.sin((n*2)*hexRadians);
		this.buildingX[n+16]=n*8+offsetX+2;
		var cc=96+Math.floor(Math.random()*64);
		this.buildingColor[n+16]='rgb('+cc+','+cc+','+cc+')';
	}

	this.paint=function() {
		for (var n=0; n<24; n++) {
			cContext.fillStyle=this.buildingColor[n];
			cContext.fillRect(this.buildingX[n],this.offsetY-this.buildingHeight[n],4,this.buildingHeight[n]);
		}
	}
} // cityScape

function waterLine(count,dirSpeed,maxY,startColor,startY,endColor,endY) {
	this.x=[];
	this.y=[];
	this.dir=[];
	this.count=count;
	this.inc=Math.ceil(resX/count);
	this.randomSkew=this.inc*0.5;
	this.offsetX=(this.inc-this.randomSkew)/2;
	this.half=Math.floor(this.inc/2);
	this.count+=2;
	this.maxY=-maxY; // n-1
	this.startY=startY;
	this.endY=endY;
	this.dirSpeed=dirSpeed;
	this.gradient=cContext.createLinearGradient(0,startY,0,endY);
	this.gradient.addColorStop(0,startColor);
	this.gradient.addColorStop(1,endColor);
	for (var t=0; t=0) {
				x[t]=cpx+half+Math.floor((Math.random()*randomSkew-offsetX));
				dir[t]=-(0.1+Math.random()/dirSpeed);
			} else if (y[t]3) || (tb<0)) {
			this.bobRate=-this.bobRate;
		} else this.bob=tb;

		with (cContext) {

			save();
			translate(this.x,this.y+this.bob);
			scale(this.direction,1);

			save();
				translate(-10.5,-1.5);
				rotate(this.aim);
				fillStyle='#248';
				fillRect(-0.5,-4,0.5,4);
			restore();

			fillStyle='#888';
			fillRect(-3,-9,1,5);

			fillStyle='#AAA';
			beginPath();
			moveTo(-6,-1);
			lineTo(-5,-5);
			lineTo(-1,-5);
			lineTo(0,-2);
			lineTo(1,-2);
			lineTo(1,-4);
			lineTo(3,-4);
			lineTo(4,-1);
			closePath();
			fill();

			beginPath();
			moveTo(4.5,-1);
			lineTo(4.5,-3);
			lineTo(7,-3);
			lineTo(8,-2);
			lineTo(10,-2);
			lineTo(11,-1);
			closePath();
			fill();

			fillStyle='#BBB';
			beginPath();
			moveTo(-8,-1);
			lineTo(-7,-2);
			lineTo(-5,-2);
			lineTo(-4,-4);
			lineTo(-2,-4);
			lineTo(-2,-3);
			lineTo(1,-3);
			lineTo(1,-1);
			closePath();
			fill();
			fillStyle='#666';
			fillRect(-5,-5.5,4,0.5);
			fillRect(-4,-4.5,2,0.5);
			fillRect(1,-4.5,2,0.5);
			fillRect(4.5,-3.5,2.5,0.5);
			fillRect(4.5,-2.5,5.5,0.5);

			fillStyle='#999';
			fillRect(6,-1.5,1,0.5);
			fillRect(8,-1.5,1,0.5);
			fillRect(-7,-1.5,1,0.5);
			fillRect(-5,-1.5,1,0.5);
			fillRect(-3,-1.5,1,0.5);
			fillRect(-1,-1.5,1,0.5);

			desGradient=createLinearGradient(0,-3,0,2);
			with (desGradient) {
				addColorStop(0,'#888');
				addColorStop(0.7,'#CCC');
			}
			fillStyle=desGradient;
			beginPath()
			moveTo(-16,2);
			quadraticCurveTo(-18,-1,-22,-2.5);
			quadraticCurveTo(-18,-1,-10,-1);
			lineTo(21,-1);
			lineTo(21,0);
			lineTo(20,0);
			lineTo(19,2);
			closePath();
			fill();

			desRadial=createRadialGradient(-11.7,-2,0.1,-11,-0.5,3);
			with (desRadial) {
				addColorStop(0,'#FFF');
				addColorStop(1,'#666');
			}
			fillStyle=desRadial;
			beginPath();
			moveTo(-9,-1);
			quadraticCurveTo(-9,-2.5,-10.5,-2.5);
			quadraticCurveTo(-12,-2.5,-12,-1);
			closePath();
			fill();

			restore();
		}
	}
} // destroyer

function submarine(x,y,rotate) {
	this.x=x;
	this.y=y;
	this.rotate=rotate;
	this.bob=0;
	this.bobRate=-0.05+Math.random()*0.05;

	this.paint=function() {

		var tb=this.bob+this.bobRate;
		if ((tb>1.5) || (tb<0)) {
			this.bobRate=-this.bobRate;
		} else this.bob=tb;

		with (cContext) {

			subGradient=createLinearGradient(0,-3,0,2);
			with (subGradient) {
				addColorStop(0,'#8AD');
				addColorStop(0.5,'#78B');
				addColorStop(1,'#346');
			}

			save();
			translate(this.x,this.y+this.bob);

			if (this.rotate==0) {
				fillStyle='#579';
				fillRect(-0.5,-8,1,6);
			} else {
				save();
				scale(this.rotate,1);
				fillStyle='#579';
				fillRect(15,-3,4,4.5);
				beginPath();
				moveTo(-16,-7);
				lineTo(-12,-7);
				lineTo(-9,-3);
				lineTo(-16,-3);
				fill();
				fillStyle='#67A';
				fillRect(-16,-5,3,1);
				fillStyle=subGradient;
				beginPath();
				moveTo(-19,2);
				quadraticCurveTo(-24,2,-24,0);
				quadraticCurveTo(-24,-3,-20,-3);
				lineTo(-9,-3);
				quadraticCurveTo(6,-3,24,-1);
				quadraticCurveTo(6,2,0,2)
				closePath();
				fill();
				restore(); // scale
			}

			fillStyle=subGradient;
			beginPath();
			arc(0,-0.5,2.5,0,Math.PI*2,false);
			fill();

			var plane=Math.abs(1-this.rotate)*2;
			fillStyle='#67A';
			fillRect(-13*this.rotate-3,-5,3+plane,1);

			if (!rotate==0) {
				save();
				scale(this.rotate,1);

				fillStyle='#346';
				fillRect(-15,-10,1,3);
				fillStyle='#45B';
				fillRect(-22,-1,2,1);
				fillRect(-8,-3,2,1);
				fillRect(-5,-3,2,1);
				fillRect(-2,-3,2,1);
				fillRect(1,-3,2,1);
				fillStyle='#89A';
				fillRect(-22,0,2,1);
				fillRect(-22,-2,2,1);

				restore(); // scale
			}

			restore(); // translate
		}
	}
}


function world_prepare() {

	var skyBreak=(oceanOffset+4)/(maxY-32);
	skyGradient=cContext.createLinearGradient(0,0,0,maxY-32);
	with (skyGradient) {
		addColorStop(0,'#0AF');
		addColorStop(skyBreak-0.01,'#DEF');
		addColorStop(skyBreak,'#6BF');
		addColorStop(skyBreak+0.02,'#08F');
	}

	landGradient=cContext.createLinearGradient(0,landOffsetY,0,landOffsetY+22);
	with (landGradient) {
		addColorStop(0,'#4B2');
		addColorStop(0.4,'#0C0');
		addColorStop(0.8,'#FF8');
	}

	waterLine[0]=new waterLine(48,6,2,'#08F',oceanOffset+8, '#06F',oceanOffset+30);
	waterLine[1]=new waterLine(32,5,3,'#05F',oceanOffset+16,'#08F',oceanOffset+35);
	waterLine[2]=new waterLine(24,4,4,'#008',oceanOffset+32,'#002',maxY);

	cities[0]=new cityScape(18,landOffsetY+13);
	cities[1]=new cityScape(190,landOffsetY+13);
	cities[2]=new cityScape(380,landOffsetY+13);
	cities[3]=new cityScape(552,landOffsetY+13);

	destroyers[0]=new destroyer(50,oceanOffset+24,-1);
	destroyers[1]=new destroyer(maxX-50,oceanOffset+24,1);

	subs[0]=new submarine(135,oceanOffset+47,1);
	subs[1]=new submarine(maxX-135,oceanOffset+47,-1);
}

function canvas_landMasses() {
	with (cContext) {
		fillStyle=landGradient;
		beginPath();
		moveTo(-20,landOffsetY+20);
		quadraticCurveTo(60,landOffsetY,120,landOffsetY+20);
		fill();
		beginPath();
		moveTo(140,landOffsetY+20);
		quadraticCurveTo(220,landOffsetY+5,260,landOffsetY+5);
		quadraticCurveTo(300,landOffsetY+15,320,landOffsetY+7);
		quadraticCurveTo(360,landOffsetY+5,380,landOffsetY+10);
		quadraticCurveTo(440,landOffsetY+5,maxX-140,landOffsetY+20);
		fill();
		beginPath();
		moveTo(maxX-120,landOffsetY+20);
		quadraticCurveTo(maxX-60,landOffsetY,maxX+20,landOffsetY+20);
		fill();
	}
}

function canvas_paint() {

	with (cContext) {
		clearRect(0,0,maxX,maxY);
		fillStyle=skyGradient;
		fillRect(0,0,maxX,maxY);
	}

	for (var n=0; n<3; n++) {
		switch (n) {
			case 0:
				// aircraft go here
			break;
			case 1:
				canvas_landMasses();
				for (var t=0; t=10) {
		throttleCount=1;
		throttleTime=throttleAverage;
	}
	frameAdjust=paintInterval/throttleAverage;
	timeReport.innerHTML=Math.floor(1000/throttleAverage)+' fps - '+mouseX+':'+mouseY;
}

function canvas_onLoad() {
	var d=new Date();
	oldTime=d.getTime();
	frameControl=setInterval(canvas_paint,paintInterval);
}

function canvas_fixAspect() {
	with (document) {
		var calcWidth=body.clientWidth-32;
		var testHeight=body.clientHeight-60;
		var container=getElementById('canvasHolder');
	}
	if (calcWidth<256) calcWidth=256;
	if (!upSize.checked) {
		if (resX>calcWidth) {
			var calcHeight=Math.floor(calcWidth*aspect);
		} else {
			calcWidth=resX;
			var calcHeight=resY;
		}
	} else {
		var calcHeight=Math.floor(calcWidth*aspect);
	}
	if (calcHeight>testHeight) {
		calcHeight=testHeight;
		calcWidth=Math.floor(calcHeight/aspect);
	}
	cCanvas.style.width=calcWidth+'px';
	cCanvas.style.height=calcHeight+'px';
	renderScale=resX/(calcWidth);
}

function canvas_mouseMove(nonIE) {
	if (nonIE) {
		mouseX=nonIE.clientX;
		mouseY=nonIE.clientY;
	} else {
		mouseX=event.clientX;
		mouseY=event.clientY;
	}
	mouseX=Math.floor((mouseX-cCanvas.offsetLeft)*renderScale);
	mouseY=Math.floor((mouseY-cCanvas.offsetTop)*renderScale);
}

if (cCanvas.getContext) {
	var container=document.getElementById('canvasHolder');
	container.replaceChild(cCanvas,container.firstChild);
	cCanvas.width=maxX;
	cCanvas.height=maxY;
	cCanvas.onmousemove=canvas_mouseMove;
	var cContext=cCanvas.getContext('2d');
	world_prepare();
	if (window.addEventListener){
		window.addEventListener('resize',canvas_fixAspect,false);
		window.addEventListener('load',canvas_onLoad,false);
	} else if (window.attachEvent){
		window.attachEvent("onresize",canvas_fixAspect);
		window.attachEvent("onload",canvas_onLoad);
	} else {
		window.onresize=canvas_fixAspect;
		window.onload=canvas_onLoad;
	}

	upSize.onchange=canvas_fixAspect;

	canvas_fixAspect();
}