window.onload = function(){
	canvas = document.getElementById('game');
	context = canvas.getContext('2d');
	canvas.style.display = 'block'; // Set up canvas
	canvas.style.border = '1px solid #ddd';
	canvas.style.background = '#fff'; // Set canvas style
	canvas.style.margin = (window.innerHeight > 360 ? window.innerHeight / 2 - 180 + 'px auto' : '10px auto');
	start();
};

window.requestAnimFrame = (function(){
	return  window.requestAnimationFrame	|| 
		window.webkitRequestAnimationFrame	|| 
		window.mozRequestAnimationFrame		|| 
		window.oRequestAnimationFrame		|| 
		window.msRequestAnimationFrame		|| 
		function(callback, element){
			window.setTimeout(callback, 1000 / 60);
		};
})();

function start(){
	reset();
}

// Get mouse position
function getMouse(evt) {
        var rect = canvas.getBoundingClientRect();
        return {
          x: evt.clientX - rect.left,
          y: evt.clientY - rect.top,
		  click: false
        };
      }

// Set up variables
function reset(){
	// Create arrays
	actors = [];
	controllers = [];
	particles =  [];
	camera = [];
	ais = [];
	keys = [];
	test = [];
	level = ['','','','','','','','','','','','','','','','','','','',''];
	partsInserted = [];
	optionvars = [50, 50];
	mouse = {
		x: 0,
		y: 0,
		down: false,
		click: false
	};
	slow = false;
	sound = {
		shoot1: new Audio('sfx.wav'),
		jump: new Audio('Funk.mp3'),
		lol: new Audio('lol.mp3')
	}
	game = 'menu';
	ui = {
		select : 0,
		area : 0
	}
	menu = [
		[
			['Singleplayer', 2, true],
			['Multiplayer', 3, true],
			['Options', 1, true],
			['Credits', 4, true]
		],
		[
			['Music', 's', 0, 0, 100, false],
			['Sound', 's', 1, 0, 100, false],
			['Back', 0, true]
		],
		['r', 'play'],
		['r', 'play'],
		['t', 'Sint', '', 'Programming and graphics by Asraelite', 'Sound from a source that does not deserve credit']
	]
	lastspeed = 0;
	
	
	//controllers[1] = new Controller(actors[2], [[39, 'moveRight'], [37, 'moveLeft'], [38, 'jump'], [88, 'camera'], [78, 'bounce', 100]]);
	
	// type, affiliation, lifespan, xpos, ypos, xvel, yvel
	particles[0] = new Particle('mouse', 0, 10000000000, 0, 0, 0, 0);
	defineLevels(); // Call function to create level variables
	//level = 2 // Set level
	spritesheet = new Image(); // Define spritesheet
	spritesheet.src = 'actors.png';
	document.addEventListener('keydown', keyDown, true); // Add key events
	document.addEventListener('keyup', keyUp, true);
	document.addEventListener('mousemove', function(evt){mouse.x = getMouse(evt).x; mouse.y = getMouse(evt).y}, false);
	document.addEventListener('mousedown', function(evt){mouse.down = true}, false);
	document.addEventListener('mouseup', function(evt){mouse.down = false}, false);
	animate();
}

function play(){
	// Create player and its key controller
	actors[0] = new Actor(0, 'player', 200, 3, 128, 64, 16, 16);
	controllers[0] = new Controller(actors[0], [[68, 'moveRight'], [65, 'moveLeft'], [87, 'jump'], [67, 'camera'], /*[69, 'stream', 100]*/, [81, 'suicide']]);
	
	actors[1] = new Actor(6, 'all', 200, 3, 256, 64, 16, 16);
	ais[0] = new Ai(1, 'pace');
	
	camera = [actors[0]]; // Set camera.
}

function animate() {
	requestAnimFrame(animate);
	loopGame();
}

// Modified from W3C
function readFile() {  
  var file = document.getElementById('file').files[0];
  if(file){
    getAsText(file);
  }
}

function getAsText(readFile) {
        
  var reader = new FileReader();
  
  // Read file into memory as UTF-16      
  reader.readAsText(readFile, "UTF-16");
  
  // Handle progress, success, and errors
  reader.onprogress = updateProgress;
  reader.onload = loaded;
  reader.onerror = errorHandler;
}

// Round a number.
function r(num){
	return Math.round(num);
}

function setStrChar(string , index, letter) {
    if(index > string.length-1){
		return string;
	}
    return string.substr(0, index) + letter + string.substr(index + 1);
}

// Generate random number from seed (not used)
function seed(num){
	return ((num * 467 + ((num * 6) % 9)) % 1000) / 1000;
}

// Add key pressed to key list.
function keyDown(e){
	var keyPress;
	if (typeof event !== 'undefined') {
		keyPress = event.keyCode;
	}else if(e){
		keyPress = e.which;
	}
	if(keys.indexOf(keyPress) == -1){
		keys.push(keyPress);
	}
}

// Remove key from key list.
function keyUp(e){
	var keyPress;
	if (typeof event !== 'undefined') {
		keyPress = event.keyCode;
	}else if(e){
		keyPress = e.which;
	}
	keys.splice(keys.indexOf(keyPress), 1);
}

// Define objects.

function Controller(object, actions){
	this.actor = object;
	this.checkKeys = function(){
		for(i in actions){
			if(keys.indexOf(actions[i][0]) > -1){
				this.actor.action(actions[i][1]);
			}
			if(mouse.click && actions[i][0] == 'c'){
				this.actor.action(actions[i][1]);
			}
		}
		this.actor.refreshActions();
	}
}

function Ai(index, ai){
	this.index = index;
	this.actor = actors[index];
	this.aivars = [0, 0, 0];
	this.action = function(act){
		this.actor.action(act);
	}
	this.run = function(){
		this.actor = actors[index];
		switch(ai){
			case 'alphaBot': // Work in progress following melee AI
				var playerIndex = -1;
				var topDistance = 400;
				var distanceAway = Math.abs(actors[0].x - this.actor.x);
				if((this.aivars[0] == 0 ? distanceAway > 150 : distanceAway < 200)){
					if(actors[0].x > this.actor.x){
						this.action((this.aivars[0] == 0 ? 'moveRight' : 'moveLeft'));
					}else{
						this.action((this.aivars[0] == 0 ? 'moveLeft' : 'moveRight'));
					}
					if(actors[index].xvel < 0.1){
						this.action('jump');
					}
					actors[index].xvel *= Math.pow(0.995, speed);
				}else{
				
				}
				if(Math.random() < 0.03 || this.aivars[2] > 0){
					if(this.aivars[0] == 0){
						this.aivars[2] += 1;
						this.action('dark');
					}else{
						this.aivars[0] -= 1;
					}
				}
				if(this.aivars[2] == 75){
					this.action('jump');
				}
				if(this.aivars[2] > 75 && actors[index].yvel >= 0){
					actors[index].vars = [false, (actors[0].x - this.actor.x) / 15, (actors[0].y - this.actor.y) / 10];
					this.action('shoot');
				}
				if(this.aivars[2] >= 95){
					this.aivars[0] = 10;
					this.aivars[1] = 0;
					this.aivars[2] = 0;
					actors[index].vars = [false, false, false];
				}
				break;
			case 'pace': // Walking back and forth
				if(this.actor.xvel == 0){
					this.aivars[0] = (1 - this.aivars[0]);
				}
				this.action(this.aivars[0] == 0 ? 'moveRight' : 'moveLeft');
				break;
			case 'still':
				break;
			case 'test': // Jumping AI
				this.action('jump');
				break;
		}
	}
}

// Actor class for all solid cubes
function Actor(image, type, health, power, xpos, ypos, width, height){
	this.image = image;
	this.group = type;
	this.health = health;
	this.power = power;
	this.yvel = 0;
	this.xvel = 0;
	this.imageLoad = 2;
	this.right = this.up = this.down = false;
	this.left = false;
	this.x = xpos;
	this.y = ypos;
	this.w = width;
	this.h = height;
	//this.box = new Box(this.x, this.y, this.w, this.h, this.xvel, this.yvel, ['player', 'pacer'], true); // Set physics class for this actor
	this.box = new Box(this.x, this.y, this.w, this.h, this.xvel, this.yvel, [], true);
	this.oneactions = [];
	this.actionsturn = [];
	this.index = actors.length;
	this.vars = [false, false, false]; // for use by AIs to control particles
	
	this.refreshActions = function(){
		this.oneactions = [];
		for(i in this.actionsturn){
			this.oneactions.push(this.actionsturn[i]);
		}
	}
	
	// Actions to call from controllers
	this.action = function(type){
		switch(type){
			case 'moveLeft':
				this.xvel -= (0.08 * speed);
				break;
			case 'moveRight':
				this.xvel += (0.08 * speed);
				break;
			case 'jump':
				this.box.y += 1;
				if(this.box.collide() || this.box.inlava){
					this.yvel = (-4 - this.power) * (this.box.inlava ? 0.2 : 1);
					distanceToSound = Math.abs(this.x - lookx - 250);
					if(Math.abs(this.x - lookx) < 300){
						sound.jump.volume = r(((optionvars[1]) / 100) / (distanceToSound < 100 ? 1 : distanceToSound / 50));
						sound.jump.play();
					}
				}
				this.box.y -= 1;
				break;
			case 'melee':
				this.yvel = 10;
				break;
			case 'camera':
				camera = [this];
				break;
			case 'stream':
				var angle = Math.atan2((this.y) - mouse.y, mouse.x - (this.x - lookx));
				particles.push(new Particle(0, 0, 9000, this.x + 8, this.y - 8, Math.sin(angle) * 15, Math.cos(angle) * 15));
				sound.shoot1.volume = r(optionvars[1]) / 100;
				sound.shoot1.play();
				break;
			case 'bounce':
				particles.push(new Particle(1, 0, 5000, this.x, this.y - 1, this.xvel * 2 + ((Math.random() - 0.5) * 5), 1));
				break;
			case 'flo':
				particles.push(new Particle(2, 0, 100000, this.x, this.y - 16, this.xvel * 4 + ((Math.random() - 0.5) * 10), -10));
				break;
			case 'dark':
				particles.push(new Particle(3, this.index, 3000, this.x + (Math.random() * 16), this.y - (Math.random() * 16), this.xvel, this.yvel));
				this.vars = [false, false, false]
				break;
			case 'shoot':
				this.vars = [true, this.vars[1], this.vars[2]];
				break;
			case 'suicide':
				this.health = (this.y > -50 ? 0 : this.health);
				break;
		}
		this.actionsturn.push(type);
	}
	
	this.simulate = function(){
		this.box.xvel = this.xvel;
		this.box.yvel = this.yvel;
		this.box.x = this.x;
		this.box.y = this.y;
		this.box.health = this.health;
		this.box.run();
		this.x = this.box.x;
		this.y = this.box.y;
		this.xvel = this.box.xvel;
		this.yvel = this.box.yvel;
		this.health = this.box.health;
		if(this.health <= 0){
			this.health = 200;
			for(i = 0; i < 64; i++){
				particles.push(new Particle(0, 0, Math.random() * 500 + 2500, this.x + ((i % 8) * 2), this.y - ((i % 8) * 2), (Math.random() - 0.5) * 10, (Math.random() - 0.8) * 10));
			}
			this.y = -500;
		}
		//this.xvel *= Math.pow(0.992, speed);
	}
	
	this.draw = function(){
		var reflect = 100; // Depth reflection goes before fading completely
		var drawx = r(this.x - lookx + this.xvel);
		var drawy = 200;
		context.drawImage(spritesheet, this.image * 16, 16, 16, 16, drawx, r(this.y - 16 - looky), this.w, this.h);
		context.globalAlpha = 1;
		//context.drawImage(spritesheet, this.image * 16, 16, 16, 16, drawx, r((216 - (this.y - 216)) - looky), 16, 16);
		// StartX, StartY, EndX, EndY
		var gradient = context.createLinearGradient(drawx, r((216 - this.y + 216) - looky - 5), drawx, r((214 - (this.y - 216)) - looky) + 16);
		gradient.addColorStop(0.1, 'rgba(255, 255, 255, ' + (this.y < 120 ? 1 : ((200 - this.y) / 35) + 0.2) +')');
		gradient.addColorStop(0.9, 'rgba(255, 255, 255, 1)');
		context.fillStyle = gradient;
		//context.fillRect(drawx, r((216 - (this.y - 216)) - looky), 16, 16);
	}
}

function Particle(type, affiliation, lifespan, xpos, ypos, xvel, yvel, gravity){
	this.gravity = typeof gravty !== 'undefined' ? gravity : true;
	this.x = xpos;
	this.y = ypos;
	this.xvel = xvel;
	this.yvel = yvel;
	this.type = type;
	this.life = lifespan;
	this.size = [3, 5, 7, 5][type];
	this.created = this.timeup = new Date();
	this.timeup = new Date(this.timeup.getTime() + lifespan);
	this.deleteme = false;
	this.aff = affiliation;
	this.vars = [false, false];
	var angle = Math.random() * 360;
	this.addx = Math.sin(angle) * ((particles.length + 200) / 5);
	this.addy = Math.cos(angle) * ((particles.length + 200) / 10);
	this.box = new Box(this.x, this.y, this.size, this.size, this.xvel, this.yvel, [], gravity);
	this.box.unstuck();
	
	this.draw = function(){
		//context.beginPath();
		//context.rect(this.x, this.y, 3, 3);
		if(this.x > lookx - 50 && this.x < lookx + 550 && this.y < 300 && this.y > -50){
			switch(this.type){
				case 'mouse':
					context.globalAlpha = 0.7;
					context.lineWidth = 2;
					context.strokeStyle = '#33d';
					context.strokeRect(mouse.x - this.vars[0] / 2, mouse.y - this.vars[0] / 2, this.vars[0], this.vars[0]);
					break;
				case 0:
					context.globalAlpha = 1;
					context.lineWidth = 1;
					context.strokeStyle = '#66b';
					context.strokeRect(r(this.x - lookx) + 0.5, r(this.y - looky) + 0.5, 2, 2);
					break;
				case 1:
					context.globalAlpha = 1;
					context.lineWidth = 2;
					context.strokeStyle = '#b79';
					context.strokeRect(r(this.x - lookx) + 0.5, r(this.y - looky) + 0.5, 4, 4);
					break;
				case 2:
					context.globalAlpha = 0.2;
					context.lineWidth = 1;
					context.strokeStyle = '#363';
					context.strokeRect(r(this.x - lookx) + 0.5, r(this.y - looky) + 0.5, 5, 5);
					break;
				case 3:
					context.globalAlpha = 0.5;
					context.lineWidth = 1;
					context.strokeStyle = '#000';
					context.strokeRect(r(this.x - lookx) + 0.5, r(this.y - looky) + 0.5, 4, 4);ha = 1;
			}
			context.globalAlpha = 1;
		}
	}
	
	this.onGround = function(){
		return false;
	}
	
	
	this.simulate = function(){
		switch(this.type){
			case 'mouse':
				if(this.vars[0] == false){
					this.vars[0] = 8;
				}
				if(this.vars[1] == true){
					this.vars[0] += 0.4;
					if(this.vars[0] >= 10){
						this.vars[1] = false;
					}
				}else{
					this.vars[0] -= 0.4;
					if(this.vars[0] <= 7){
						this.vars[1] = true;
					}
				}
				this.x = lookx;
				if(mouse.down){
					particles.push(new Particle(0, 0, 9000, lookx + mouse.x, mouse.y, (Math.random() - 0.5) * 5, (Math.random() - 0.5) * 5));
				}
				break;
			default:
				for(j in actors){
					if(Math.abs(this.x - (actors[j].x + 8)) < 20 && Math.abs(this.y - (actors[j].y + 8)) < 20){
						this.xvel += (20 - Math.abs(this.x - (actors[j].x + 8))) / (this.x > (actors[j].x + 8) ? 5 : -5);
						this.yvel += (20 - Math.abs(this.y - (actors[j].y + 8))) / (this.y > (actors[j].y + 8) ? 5 : -5);
					}
				}
				break;
		}
		if(thisLoop > this.timeup){
			this.deleteme = true;
		}
		this.box.xvel = this.xvel;
		this.box.yvel = this.yvel;
		this.box.x = this.x;
		this.box.y = this.y + 16;
		this.box.run();
		this.x = this.box.x;
		this.y = this.box.y - 16;
		this.xvel = this.box.xvel;
		this.yvel = this.box.yvel;
	}
}

// Collision detection class
function Box(x, y, w, h, xvel, yvel, colgroup, gravity){
	this.x = x;
	this.y = y;
	this.width = w;
	this.height = h;
	this.col = colgroup;
	this.right = false;
	this.left = false;
	this.up = false;
	this.down = false;
	this.gravity = gravity;
	this.health = 0;
	this.inlava = false;
	
	this.reset = function(){
		this.right = false;
		this.left = false;
		this.up = false;
		if(!this.inlava){
			this.down = false;
		}
	}
	
	this.collide = function(){
		// Check for collision with level
		var lv = level;
		var colareax = ((this.width - 2) >> 4) + 2;
		var colareay = ((this.height - 2) >> 4) + 2;
		var collision = false;
		var type = 'level';
		this.inlava = false;
		test = [];
		for(var hr = 0; hr < colareax; hr++){
			for(var vr = 0; vr < colareay; vr++){
				var xcol = (((this.x - (hr == colareax - 1 ? 1 + 16 - (((this.width - 1) % 16) + 1): 0)) >> 4) + hr);
				var ycol = (((this.y - (vr == colareay - 1 ? 1 + 16 - (((this.height - 1) % 16) + 1) : 0)) >> 4) + vr);
				if(ycol - 1 >= 0 && ycol <= lv.length){
					if(xcol >= 0 && xcol < lv[ycol].length){
						if(lv[ycol - 1][xcol] == '#'){
							collision = true;
						}else if(lv[ycol - 1][xcol] == 'x'){
							this.health -= 0.01 * speed;
							this.inlava = true;
							this.xvel *= Math.pow(0.997, speed);
							this.yvel *= Math.pow(0.997, speed);
						}else if(lv[ycol - 1][xcol] == 'w'){
							this.inlava = true;
							this.xvel *= Math.pow(0.999, speed);
							this.yvel *= Math.pow(0.999, speed);
						}
					}
				}
			}
		}
		
		for(j in actors){
			var obj = actors[j];
			if(this.y < obj.y + obj.h && this.y + obj.h > obj.y && this.x + obj.w > obj.x && this.x < obj.x + obj.w && obj.box != this){
				collision = true;
			}
		}
		
		return collision;
	}
	
	this.move = function(){
		if(!this.inlava){
			this.down = false;
		}
		var apparentVel = (this.xvel * speed) / (1000 / 60);
		var velToKill = Math.abs(apparentVel)
		var maxMove = Math.floor(this.width / 2);
		while(velToKill > 0){ // If velocity is more than half the box size, only move in increments of half box size to prevent clipping
			if(velToKill > maxMove){
				this.x += (this.xvel > 0 ? maxMove : -maxMove);
				velToKill -= maxMove;
			}else{
				this.x += (this.xvel > 0 ? velToKill : -velToKill);
				velToKill = 0;
			}
			if(this.collide() && Math.abs(this.xvel) > 0){
				this.x = ((this.x >> 4) << 4) + (this.xvel > 0 ? 16 - (((this.width - 1) % 16) + 1) : 16);
				this.xvel = 0;
				velToKill = 0;
			}
		}
		
		var apparentVel = (this.yvel * speed) / (1000 / 60);
		var velToKill = Math.abs(apparentVel);
		var maxMove = Math.floor(this.height / 2);
		while(velToKill > 0){
			if(velToKill > maxMove){
				this.y += (this.yvel > 0 ? maxMove : -maxMove);
				velToKill -= maxMove;
			}else{
				this.y += (this.yvel > 0 ? velToKill : velToKill * -1);
				velToKill = 0;
				
			}
			if(this.collide()){
				this.y = ((this.y >> 4) << 4) + (this.yvel > 0 ? 16 - (((this.height - 1) % 16) + 1) : 16);
				if(this.yvel < 0){
					this.down = true;
				}
				this.yvel = 0;
				velToKill = 0;
			}
		}
		
		if(this.collide()){
			this.unstuck(5000);
		}
		
		this.reset();
		
	}
	
	this.unstuck = function(limit){
		var j = 0;
		var originalx = this.x;
		var originaly = this.y;
		while(this.collide() && j < limit){
			this.x = r(originalx + (Math.sin(Math.PI * 2 * ((j % 16) / 16)) * (j / 4)));
			this.y = r(originaly + (Math.cos(Math.PI * 2 * ((j % 16) / 16)) * (j / 4)));
			j++;
		}
		if(j >= limit){
			this.x = originalx;
			this.y = originaly;
		}
	}
	
	this.run = function(){
		this.y += 1;
		if(this.collide() == false && this.gravity){
			this.yvel += 0.025 * speed;
		}
		this.y -= 1;
		this.xvel *= Math.pow(0.99, speed);
		if(!this.gravity){
			this.yvel *= Math.pow(0.99, speed);
		}
		this.move();
	}
}

// Run game.

var speed;
var lastLoop = new Date();
var thisLoop = lastLoop;
function loopGame(){
	canvas.style.margin = (window.innerHeight > 360 ? window.innerHeight / 2 - 180 + 'px auto' : '10px auto');
    lastLoop = thisLoop;
	thisLoop = new Date();
    speed = (thisLoop - lastLoop);
	speed = (speed > 50 ? 50 : speed);
	context.clearRect(0, 0, 500, 350);
	lookx = looky = 0;
	looky = -0;
	var maxx = 0;
	for(i in actors){
		if(actors[i].x > maxx){
			maxx = actors[i].x;
		}
	}
	maxx += 1;
	while(level[0].length < maxx){
		partIndex = Math.floor(Math.random() * (levelparts.length - 1)) + 1;
		partFound = false;
		if(partsInserted.length == 0){
			var toInsert = levelparts[0];
			partsInserted.push([false, '5n', 1, 1, 0]);
			partFound = true;
		}else{
			thisPart = levelparts[partIndex];
			if(thisPart[20] == partsInserted[partsInserted.length - 1][1] && (Math.random() * thisPart[24]) < 1){
				partsInserted.push([thisPart[20], thisPart[21], thisPart[22], thisPart[23], thisPart[24]]);
				toInsert = thisPart;
				partFound = true;
			}
		}
		if(partFound){
			for(i = 0; i < 20; i++){
				level[i] += toInsert[i];
			}
		}
	}
	for(i in controllers){
		controllers[i].checkKeys();
	}
	for(i in actors){
		actors[i].simulate();
	}
	for(i in camera){
		lookx += (camera[i] instanceof Array ? camera[i][0] : camera[i].x + camera[i].xvel * 1) - 250;
		// looky += (camera[i] == instanceof Array ? camera[i][1] : camera[i].y) - 175;
	}
	lookx /= camera.length;
	looky /= camera.length;
	
	context.globalAlpha = 1;
	context.lineWidth = 1;
	var lv = level;
	for(i = 0; i < lv.length; i++){ // Draw level
		for(j = (lookx > 300 ? r((lookx - 300) / 16) : 0); j < r((lookx + 600) / 16); j++){
			if(lv[i][j] == '#' || lv[i][j] == 'x' || lv[i][j] == 'w'){
				//#efefef
				var edgeTile = false;
				if((j < lv[i].length && j > 0 && i < lv.length - 1 && i > 0)){
					var edgeChecks = [[-1, 1], [0, 1], [1, 1], [1, 0], [1, -1], [0, -1], [-1, -1], [-1, 0]];
					for(k in edgeChecks){
						if(lv[i + edgeChecks[k][0]][j + edgeChecks[k][1]] != '#'){
							edgeTile = true;
						}
					}
					if(edgeTile){
						context.fillStyle = '#ddd';
					}else{
						context.fillStyle = '#eee';
					}
				}
				if(lv[i][j] == 'x'){
					context.fillStyle = '#d77';
				}
				if(lv[i][j] == 'w'){
					context.fillStyle = '#47d';
				}
				context.fillRect((j << 4) - r(lookx), i << 4, 16, 16);
			}else if(lv[i][j] == 'E'){
				actors[actors.length] = new Actor(6, 'all', 200, 3, j << 4, i << 4, 16, 16);
				ais[ais.length] = new Ai(actors.length - 1, 'pace');
				level[i] = setStrChar(level[i], j, '.');
			}
		}
	}
	context.fillStyle = 'rgba(255, 200, 200, 0.7)';
	for(i in test){
		context.fillRect((test[i][0] << 4) - lookx, test[i][1] << 4, 16, 16);
	}
	for(i in actors){
		if(actors[i].x < lookx + 550 && actors[i].x > lookx - 50){
			actors[i].draw();
		}
	}
	context.globalAlpha = 1;
	context.fillStyle = "#444";
	context.font = "10pt Arial";
	context.textAlign = 'left';
	if(game == 'playing'){
		context.fillText('Health: ' + r(camera[0].health), 10, 270);
		context.fillText('X: ' + r(camera[0].x), 10, 290);
		context.fillText('Y: ' + r(camera[0].y), 70, 290);
		context.fillText('Xvel: ' + r(camera[0].xvel * 10) / 10, 10, 310);
		context.fillText('Yvel: ' + r(camera[0].yvel * 10) / 10, 70, 310);
	}else{
		context.fillText('W and S to move', 10, 270);
		context.fillText('Enter to select', 10, 290);
		context.fillText('A and D to change slider value', 10, 310);
	}
	lastspeed = (new Date() % 10 == 0 ? r(1000 / speed) : lastspeed);
	context.fillText('FPS: ' + lastspeed, 10, 20);
	context.textAlign = 'right';
	context.fillText('Sint version α 0.4.2', 490, 310);
	context.fillText(test, 490, 290);
	if(game == 'playing'){
		context.fillText('Actors: ' + actors.length, 490, 20);
		context.fillText('Particles: ' + particles.length, 490, 40);
	}
	for(i in ais){
		if(Math.abs(ais[i].actor.x - lookx) < 2000){
			ais[i].run();
		}
	}
	for(i in particles){
		particles[i].simulate()
		particles[i]. draw()
		if(particles[i].deleteme || particles.length > 3000){
			particles.splice(i, 1);
			i--;
		}
	}
	if(game == 'menu'){
		if(keys.indexOf(83) > -1){
			if(menudown == false){
				menudown = true;
				ui.select += 1;
			}
		}else{
			menudown = false;
		}
		if(keys.indexOf(87) > -1){
			if(menuup == false){
				menuup = true;
				ui.select -= 1;
			}
		}else{
			menuup = false;
		}
		if(keys.indexOf(13) > -1){
			if(menuenter == false){
				menuenter = true;
				if(menu[ui.area][ui.select][2]){
					ui.area = menu[ui.area][ui.select][1];
					ui.select = 0;
				}else if(menu[ui.area][0] == 't'){
					ui.area = 0;
					ui.select = 0;
				}
			}
		}else{
			menuenter = false;
		}
		ui.select = (ui.select + menu[ui.area].length) % menu[ui.area].length;
		context.fillStyle = '69d';
		context.font = '40pt Helvetica';
		context.textAlign = 'center';
		context.shadowColor = '69d';
		context.shadowBlur = 10;
		context.fillText('Sint', 250, 100);
		context.shadowBlur = 0;
		// Main menu
		if(menu[ui.area][0] == 'r'){
			switch(menu[ui.area][1]){
				case 'play':
					play();
					game = 'playing';
					break;
				case 'fractal':
					game = 'test';
					break;
				default:
					ui.area = 0;
					break;
			}
		}else if(menu[ui.area][0] == 't'){
					context.fillStyle = '#78a';
					context.font = '12pt Helvetica';
					for(i = 1; i < menu[ui.area].length; i++){
						context.fillText(menu[ui.area][i], 250, 120 + (20 * i));
					}
					context.fillStyle = '#9bf';
					context.fillRect(150, 150 + (20 * i), 200, 25);
					context.font = '12pt Helvetica';
					context.fillStyle = '#fff';
					context.fillText('Back', 250, 168 + (20 * i));
		}else{
			for(i in menu[ui.area]){
				if(menu[ui.area][i][1] == 's'){
					context.fillStyle = (ui.select == i ? '#9bf' : '#cdf');
					context.fillRect(150, 150 + (30 * i), 80, 25);
					context.font = '12pt Helvetica';
					context.fillStyle = (ui.select == i ? '#fff' : '#eef');
					context.fillText(menu[ui.area][i][0], 190, 168 + (30 * i));
					context.fillStyle = '#eee';
					context.strokeStyle = (ui.select == i ? '#cdf' : '#ddf');
					context.fillRect(240, 160 + (30 * i), 110, 5);
					context.strokeRect(240, 160 + (30 * i), 110, 5);
					context.fillStyle = (ui.select == i ? '#9bf' : '#cdf');
					context.strokeStyle = (ui.select == i ? '#79f' : '#abf');
					var thisoption = menu[ui.area][i][2];
					var optionaddx = 100 * (optionvars[thisoption] / (menu[ui.area][i][4] - menu[ui.area][i][3]));
					context.strokeRect(240 + optionaddx, 155 + (30 * i), 10, 10);
					context.fillRect(240 + optionaddx, 155 + (30 * i), 10, 10);
					if(ui.select == i){
						if(keys.indexOf(65) > -1 && optionvars[thisoption] > menu[ui.area][i][3]){
							optionvars[thisoption] -= 0.05 * speed;
						}
						if(keys.indexOf(68) > -1 && optionvars[thisoption] < menu[ui.area][i][4]){
							optionvars[thisoption] += 0.05 * speed;
						}
					}
				}else{
					context.fillStyle = (ui.select == i ? '#9bf' : '#cdf');
					context.fillRect(150, 150 + (30 * i), 200, 25);
					context.font = '12pt Helvetica';
					context.fillStyle = (ui.select == i ? '#fff' : '#eef');
					context.fillText(menu[ui.area][i][0], 250, 168 + (30 * i));
				}
			}
		}
	}
	// Slow down game to test low framerates
	if(slow){
		for(var j=1; j < 10000000; j++){
			j = j;
		}
	}
}