player_BULLET_GREEN = { .8, 1, .8, 1 }
player_BULLET_RED = { 1, .8, .8, 1 }
player_BULLET_BLUE = { .8, .8, 1, 1 }

if not players then
	players = 
	{
		{
			x = 0,
			y = 350,
			sprite = nil,
			lives = 3,
			speed = 2,
			last_shot = 0,
			last_use = 0,
			reload_time = 500 * options.player_reload,
			size = 6 * options.player_size,
			mortal = true,
			score = 0,
			weapon_level = { 1, 0, 0 },
			color = { 1, 1, 1, 1 },
			last_x_movement = -1,
			options = {},
			energy = 0,
			energy_visuals = {},
			next_life = 50000
		},
		{
			x = 64,
			y = 350,
			sprite = CreateSprite( "sprite", 0-32, 400-32-20 ),
			lives = 3,
			speed = 2,
			last_shot = 0,
			last_use = 0,
			reload_time = 500 * options.player_reload,
			size = 6 * options.player_size,
			mortal = true,
			score = 0,
			weapon_level = { 1, 0, 0 },
			color = { 0.8, 0.8, 1, 1 },
			last_x_movement = -1,
			options = {},
			energy = 0,
			energy_visuals = {},
			next_life = 50000
		}
	}
end
	
keys_held = {}
old_keys_held = {}

function KeyDown( key )
	keys_held[ key ] = true
	return false
end

function KeyUp( key )
	keys_held[ key ] = false
	return false
end

function MouseKeyDown( key )
	keys_held[ "mouse"..key ] = true
	return false
end

function MouseKeyUp( key )
	keys_held[ "mouse"..key ] = false
	return false
end

GlobalSetKeyDownProc( KeyDown )
GlobalSetKeyReleaseProc( KeyUp )
GlobalSetMouseKeyReleaseProc( MouseKeyUp )
GlobalSetMouseKeyDownProc( MouseKeyDown )

Resume( NewGlobalThread( function()
	while true do
		mouse_x, mouse_y = GetMousePos()
		Wait(1)
	end
end ))

function PlayerHit( num, bullet )
	if players[num].shield then
		players[num].shield = players[num].shield - 1
		if players[num].shield == 0 then
			players[num].shield = nil
			SetObjDead( players[num].shield_sprite )
			players[num].shield_sprite = nil
			players[num].color[4] = 0.25
			players[num].mortal = false
			SetObjSpriteColor( players[num].sprite, players[num].color )
			Resume( NewThread( function()
				if players[num].lives >= 0 then
					Wait( 2000 )
					players[num].color[4] = 1
					SetObjSpriteColor( players[num].sprite, players[num].color )
					SetObjSpriteColor( players[num].sprite, {1,1,1,1}, 0 )
					players[num].mortal = true
				end
			end ))
		end
	else
		PlaySnd( "player_die.wav", true, players[num].x, players[num].y )
		players[num].mortal = false
		SetObjDead( players[num].sprite )
		if players[num].item_sprite then
			SetObjDead( players[num].item_sprite )
		end
		players[num].item = nil
		players[num].item_sprite = nil
		players[num].sprite = nil
		CreateBlueExplosion( players[num].x, players[num].y )
		Resume( NewThread( function()
				players[num].lives = players[num].lives - 1
				if players[num].lives >= 0 then
					Wait( 1000 )
					players[num].sprite = CreateSprite( "sprite", 0-32, 400-32-20 )
					players[num].x = 0
					players[num].y = 350
					players[num].color[4] = 0.25
					SetObjSpriteColor( players[num].sprite, players[num].color )
					players[num].weapon_level = { 1, 0, 0 }
					Wait( 6000 )
					players[num].color[4] = 1
					SetObjSpriteColor( players[num].sprite, players[num].color )
					SetObjSpriteColor( players[num].sprite, {1,1,1,1}, 0 )
					players[num].mortal = true
				else
					for k, v in pairs(players[num].energy_visuals) do
						delete( players[num].energy_visuals, k )
					end
				end
			end ))
		if players[num].options then
			for key, value in pairs( players[num].options ) do
				CreateParticleSystem( "pexplosion", value.x, value.y )
				SetObjDead( value.sprite )
			end
			players[num].options = nil
		end
	end
end

function PreparePlayers( num )
	dofile( "config/starstuff.lua" )
	if num == 1 then
		config.controls[1] = config.controls[0]
	end
	for i=1,num do
		players[i].name = config.players[i].name
		players[i].color = config.players[i].color
		players[i].lock_controls = false
		
		if players[i].superlaser then
			for key, value in pairs( players[i].superlaser.sprites ) do
				value.dead = true
				SetObjDead( value.sprite )
			end
			players[i].superlaser = nil
		end
		
		if players[i].energy > 0 then
			players[i].energy_visuals = {}
			for j=1,players[i].energy do
				local spr = CreateSprite( "sprite2", players[i].x, players[i].y )
				local tab = { x = players[i].x, y = players[i].y, sprite = spr }
				SetObjAnim( spr, 4, false )
				CreateLightSource( tab, {20/255, 124/255, 158/255, -0.25}, 8 )
				table.insert( players[i].energy_visuals, tab )
			end
		end
		
		if players[i].options then
			local opts = #players[i].options
			--[[
			for j=1,#players[i].options do
				local spr = CreateSprite( "sprite", players[i].x, players[i].y )
				SetObjAnim( spr, 26, false )
				players[i].options[j].sprite = spr
				players[i].options[j].x = players[i].x
				players[i].options[j].y = players[i].y
			end
			--]]
			players[i].options = {}
			for j=1, opts do
				OptionThingy_get( i )
			end
		end
		
		players[i].mortal = true
	end
	players[1].sprite = CreateSprite( "sprite", 0-32, 400-32-20 )
	SetObjSpriteColor( players[1].sprite, players[1].color )
	SetObjSpriteColor( players[1].sprite, {1, 1, 1, 1}, 0 )
	players[1].x = 0
	players[1].y = 350
	if num > 1 then
		players[2].sprite = CreateSprite( "sprite", 0-32+16, 400-32-20 )
		players[2].x = 64
		players[2].y = 350
		SetObjSpriteColor( players[2].sprite, players[2].color )
		SetObjSpriteColor( players[2].sprite, {1, 1, 1, 1}, 0 )
	end
end

function PlayerFire( num )
	local player = players[num]
	if (time - player.last_shot > 1.2*player.reload_time) or (time - player.last_press > 0.5*player.reload_time) then
		player.shot = ( player.shot or 0 ) + 1
		if player.shot > 100 then player.shot = 1 end
		PlaySnd( "shot2.wav", true, player.x, player.y )
		player.last_shot = time
		
		--GREEN: front
		if player.weapon_level[1] == 1 then
			CreateSimpleBullet( player.x, player.y, { 0, -4 }, { 1, 1, 1, 1 }, nil, num )
			--[[
			for i = 0, 2*math.pi, 0.1 do
				CreateSimpleBullet( player.x, player.y, 4, { 1, 1, 1, 1 }, i, num )
			end
			--]]
			
		elseif player.weapon_level[1] == 2 then
			CreateSimpleBullet( player.x-20, player.y, { 0, -4 }, player_BULLET_GREEN, nil, num )
			CreateSimpleBullet( player.x+20, player.y, { 0, -4 }, player_BULLET_GREEN, nil, num )
		elseif player.weapon_level[1] == 3 then
			CreateSimpleBullet( player.x-20, player.y, { 0, -4 }, player_BULLET_GREEN, nil, num )
			CreateSimpleBullet( player.x+20, player.y, { 0, -4 }, player_BULLET_GREEN, nil, num )
			CreateSimpleBullet( player.x, player.y-20, { 0, -4 }, player_BULLET_GREEN, nil, num )
		elseif player.weapon_level[1] > 3 then
			CreateSimpleBullet( player.x-20, player.y, { 0, -4 }, player_BULLET_GREEN, nil, num )
			CreateSimpleBullet( player.x+20, player.y, { 0, -4 }, player_BULLET_GREEN, nil, num )
			CreateSimpleBullet( player.x, player.y-20, { 0, -4 }, player_BULLET_GREEN, nil, num )
			CreateSimpleBullet( player.x-20, player.y, { -0.2, -3 }, player_BULLET_GREEN, nil, num )
			CreateSimpleBullet( player.x+20, player.y, {  0.2, -3 }, player_BULLET_GREEN, nil, num )
		end
		
		--RED: angled
		if player.weapon_level[2] == 1 then
			if player.shot % 3 == 0 then
				CreateSimpleBullet( player.x, player.y, 4, player_BULLET_RED, (5/8)*math.pi, num )
				CreateSimpleBullet( player.x, player.y, 4, player_BULLET_RED, (3/8)*math.pi, num )
			end
		elseif player.weapon_level[2] == 2 then
			if player.shot % 3 == 0 then
				CreateSimpleBullet( player.x, player.y, 4, player_BULLET_RED, (5/8)*math.pi, num )
				CreateSimpleBullet( player.x, player.y, 4, player_BULLET_RED, (3/8)*math.pi, num )
				CreateSimpleBullet( player.x, player.y, 4, player_BULLET_RED, (6/8)*math.pi, num )
				CreateSimpleBullet( player.x, player.y, 4, player_BULLET_RED, (2/8)*math.pi, num )
			end
		elseif player.weapon_level[2] == 3 then
			if player.shot % 3 == 0 then
				CreateSimpleBullet( player.x, player.y, 4, player_BULLET_RED, (5/8)*math.pi, num )
				CreateSimpleBullet( player.x, player.y, 4, player_BULLET_RED, (3/8)*math.pi, num )
				CreateSimpleBullet( player.x, player.y, 4, player_BULLET_RED, (6/8)*math.pi, num )
				CreateSimpleBullet( player.x, player.y, 4, player_BULLET_RED, (2/8)*math.pi, num )
				Resume( NewThread( function() 
					Wait(100)
					CreateSimpleBullet( player.x, player.y, 4, player_BULLET_RED, (5.5/8)*math.pi, num )
					CreateSimpleBullet( player.x, player.y, 4, player_BULLET_RED, (2.5/8)*math.pi, num )
				end ))
			end
		elseif player.weapon_level[2]  > 3 then
			if player.shot % 2 == 0 then
				CreateSimpleBullet( player.x, player.y, 4, player_BULLET_RED, (5/8)*math.pi, num )
				CreateSimpleBullet( player.x, player.y, 4, player_BULLET_RED, (3/8)*math.pi, num )
				CreateSimpleBullet( player.x, player.y, 4, player_BULLET_RED, (6/8)*math.pi, num )
				CreateSimpleBullet( player.x, player.y, 4, player_BULLET_RED, (2/8)*math.pi, num )
				Resume( NewThread( function() 
					Wait(100)
					CreateSimpleBullet( player.x, player.y, 4, player_BULLET_RED, (5.5/8)*math.pi, num )
					CreateSimpleBullet( player.x, player.y, 4, player_BULLET_RED, (2.5/8)*math.pi, num )
				end ))
				CreateSimpleBullet( player.x-10, player.y+10, {0, -4}, player_BULLET_RED, nil, num )
				CreateSimpleBullet( player.x+10, player.y+10, {0, -4}, player_BULLET_RED, nil, num )
			end
		end
		
		--BLUE: sideways
		local k = player.last_x_movement
		if player.weapon_level[3] == 1 then
			CreateSimpleBullet( player.x, player.y, {4*k, 0}, player_BULLET_BLUE, nil, num )
		elseif player.weapon_level[3] == 2 then
			CreateSimpleBullet( player.x, player.y-20, { 4*k, 0 }, player_BULLET_BLUE, nil, num )
			CreateSimpleBullet( player.x, player.y+20, { 4*k, 0 }, player_BULLET_BLUE, nil, num )
		elseif player.weapon_level[3] == 3 then
			CreateSimpleBullet( player.x, player.y-20, { 4*k, 0 }, player_BULLET_BLUE, nil, num )
			CreateSimpleBullet( player.x, player.y+20, { 4*k, 0 }, player_BULLET_BLUE, nil, num )
			CreateSimpleBullet( player.x+20*k, player.y, { 4*k, 0 }, player_BULLET_BLUE, nil, num )
		elseif player.weapon_level[3] > 3 then
			CreateSimpleBullet( player.x, player.y-20, { 4*k, 0 }, player_BULLET_BLUE, nil, num )
			CreateSimpleBullet( player.x, player.y+20, { 4*k, 0 }, player_BULLET_BLUE, nil, num )
			CreateSimpleBullet( player.x+20*k, player.y, { 4*k, 0 }, player_BULLET_BLUE, nil, num )
			CreateSimpleBullet( player.x, player.y-20, { 3*k, -0.2 }, player_BULLET_BLUE, nil, num )
			CreateSimpleBullet( player.x, player.y+20, { 3*k, 0.2 }, player_BULLET_BLUE, nil, num )
		end
		
		--OPTIONS
		if player.options then
			for k,v in pairs( player.options ) do
				if player.weapon_level[3] < 3 then
					CreateSimpleBullet( v.x, v.y, {0, -4}, player_BULLET_BLUE, nil, num )
				else
					CreateSimpleBullet( v.x-20, v.y, {0, -4}, player_BULLET_BLUE, nil, num )
					CreateSimpleBullet( v.x+20, v.y, {0, -4}, player_BULLET_BLUE, nil, num )
				end
			end
		end
	end
	player.last_press = time
end

mouse_x, mouse_y = nil, nil

function UpdateOptions( player )
	if not player.options or #player.options == 0 then
		return
	end
	local tx, ty, v
	local n = #player.options 
	for i=1,n do
		v = player.options[i]
		if i == 1 then
			tx, ty = player.x, player.y
		else
			tx, ty = player.options[i-1].x, player.options[i-1].y
		end
		if dist(v.x, v.y, tx, ty ) > 32 then
			local angle = math.atan2( ty-v.y, tx-v.x )
			v.x = v.x + 0.8*1/i*player.speed*math.cos(angle)
			v.y = v.y + 0.8*1/i*player.speed*math.sin(angle)
			SetObjPos( v.sprite, v.x, v.y, -0.5 )
		end
	end
end

function ProcessInput()
	if keys_held[ keys.esc ] and not old_keys_held[ keys.esc ] then
		if not players[1].lock_controls then
			if paused then
				UnpauseGame()
			else
				PauseGame()
			end
		end
	end
	for key, value in pairs( keys_held ) do
		old_keys_held[key] = value
	end
end

function ProcessPlayer()
	
	for i = 1,players_num do
			players[i].old_x = players[i].x
			players[i].old_y = players[i].y
			if players[i].score > players[i].next_life then
				PlaySnd( "life.wav", false )
				players[i].next_life = 2 * players[i].next_life
				players[i].lives = players[i].lives + 1
			end
			if config.controls[i].type == "keyboard" and players[i].sprite and not players[i].lock_controls then
				if keys_held[config.controls[i].left] and players[i].sprite then
					players[i].x = math.max( players[i].x - players[i].speed, -300 )
					SetObjAnim( players[i].sprite, 21, false )
					SetObjSpriteMirrored( players[i].sprite, true )
					players[i].last_x_movement = -1
				elseif keys_held[config.controls[i].right] and players[i].sprite then
					players[i].x = math.min( players[i].x + players[i].speed, 300 )
					SetObjAnim( players[i].sprite, 21, false )
					SetObjSpriteMirrored( players[i].sprite, false )
					players[i].last_x_movement = 1
				elseif players[i].sprite then
					SetObjAnim( players[i].sprite, 0, false )
				end
				if keys_held[config.controls[i].up] and players[i].sprite then
					UpdateOptions( players[i] )
					players[i].y = math.max( players[i].y - players[i].speed, -400 )
				end
				if keys_held[config.controls[i].down] and players[i].sprite then
					players[i].y = math.min( players[i].y + players[i].speed, 400 )
				end
				if time - players[i].last_use > 500 and keys_held[config.controls[i].fire] and keys_held[config.controls[i].item] and players[i].energy == 32 then
					CreateSuperLaser( players[i] )
					players[i].last_use = time
				else
					if keys_held[config.controls[i].fire] and players[i].sprite then
						PlayerFire(i)
					end
					if time - players[i].last_use > 500 and keys_held[config.controls[i].item] and players[i].item then
						players[i].item( players[i] )
						players[i].last_use = time
					end
				end
			elseif config.controls[i].type == "mouse" and players[i].sprite and not players[i].lock_controls then
				local tx, ty = mouse_x, mouse_y
				if not ( tx == players[i].x and ty == players[i].y ) then
					local angle = math.atan2( ty - players[i].y, tx - players[i].x )
					local shift = { math.min(players[i].speed, math.abs(tx - players[i].x)) * math.cos(angle), math.min(players[i].speed, math.abs(ty - players[i].y)) * math.sin(angle) }
					players[i].x = players[i].x + shift[1]
					players[i].y = players[i].y + shift[2]
					if shift[i] < 0 then
						SetObjAnim( players[i].sprite, 21, false )
						SetObjSpriteMirrored( players[i].sprite, true )
						players[i].last_x_movement = -1
					elseif shift[i] > 0 then
						SetObjAnim( players[i].sprite, 21, false )
						SetObjSpriteMirrored( players[i].sprite, false )
						players[i].last_x_movement = 1
					else
						SetObjAnim( players[i].sprite, 0, false )
					end
				else
					SetObjAnim( players[i].sprite, 0, false )
				end
				if time - players[i].last_use > 500 and keys_held.mouse0 and keys_held.mouse1 and players[i].energy == 32 then
					CreateSuperLaser( players[i] )
					players[i].last_use = time
				else
					if keys_held.mouse0 and players[i].sprite then
						PlayerFire(i)
					end
					if time - players[i].last_use > 500 and  keys_held.mouse1 and players[i].item then
						players[i].item( players[i] )
						players[i].last_use = time
					end
				end
			end
			UpdateOptions( players[i] )
			UpdateEnergy( players[i] )
			UpdateSuperLaser( players[i] )
			if players[i].sprite then
				SetObjPos( players[i].sprite, players[i].x, players[i].y )
				if players[i].item_sprite then
					SetObjPos( players[i].item_sprite, players[i].item_sprite_pos[1], players[i].item_sprite_pos[2] )
					players[i].item_sprite_pos[1] = players[i].item_sprite_pos[1] + ( players[i].x+players[i].item_sprite_target[1] - players[i].item_sprite_pos[1]) * 0.1
					players[i].item_sprite_pos[2] = players[i].item_sprite_pos[2] + ( players[i].y+players[i].item_sprite_target[2] - players[i].item_sprite_pos[2]) * 0.1
				end
				if players[i].shield_sprite then
					SetObjPos( players[i].shield_sprite, players[i].x, players[i].y )
				end
			end
	end
end

function UpdateEnergy( p )
	local ang
	for i=1, #p.energy_visuals do
		ang = time / 1000 + (i-1) * math.pi / 16
		p.energy_visuals[i].x =  p.x + 32*math.cos(ang)
		p.energy_visuals[i].y =  p.y + 32*math.sin(ang)
		SetObjPos( p.energy_visuals[i].sprite, p.energy_visuals[i].x, p.energy_visuals[i].y, -0.3 )
		if config.lights > 0 then
			ChangeLightRadius( p.energy_visuals[i].lightsources[1], 16 + 4 * math.cos( time/2000 + i/32 ) )
		end
	end
end

function CreateSuperLaser( p )
	p.energy = 0
	p.mortal = false
	for k, v in pairs(p.energy_visuals) do
		delete( p.energy_visuals, k )
	end
	local sp = CreateSprite( "superray3", p.x, p.y )
	SetObjPos( sp, p.x-16, p.y-32 )
	p.superlaser = { start_time = time, sprites = {}, sp = sp }
end

function UpdateSuperLaser( p )
	if not p.superlaser then return end
	if time - p.superlaser.start_time > 1400 then
		if p.superlaser.sp then
			SetObjDead( p.superlaser.sp )
			p.superlaser.sp = nil
		end
		if not p.superlaser.sprites[1] then
			PlaySnd( "superlaser.wav", true )
			local spr = CreateSprite("superray1", p.x, p.y )
			local tab = { sprite = spr, x = p.x, y = p.y }
			CreateLightSource( tab, {147/255, 195/255, 237/255, -0.25}, 128 )
			table.insert( p.superlaser.sprites, tab )
			if config.lights == 2 then
				SetObjSpriteColor( spr, {1,1,1,-.25} )
			end
			for i=1,24 do
				spr = CreateSprite("superray2", p.x, p.y )
				if config.lights == 2 then
					SetObjSpriteColor( spr, {1,1,1,-.25} )
				end
				local tab = { sprite = spr, x = p.x, y = p.y }
				CreateLightSource( tab, {147/255, 195/255, 237/255, -0.25}, 128 )
				table.insert( p.superlaser.sprites, tab )
			end
		end
		for i=1,25 do
			p.superlaser.sprites[i].x = p.x
			p.superlaser.sprites[i].y = p.y-i*32
			SetObjPos( p.superlaser.sprites[i].sprite, p.x-32, p.y-i*32 )
		end
		for key, value in pairs( enemies ) do --FIXME: non-square enemies
			if not value.immortal and value.y < p.y and math.abs( value.x - p.x ) < 21 + value.size then
				EnemyHit( key, p )
				if value.protected then
					Resume( NewThread( function() value.immortal = true Wait(50) value.immortal = false end ))
				end
			end
		end
		for key, value in pairs( bullets ) do
			if value.friendly == 0 and value.y < p.y and math.abs( value.x - p.x ) < 21 + value.size then
				delete( bullets, key )
			end
		end
		if time - p.superlaser.start_time > 6000 then
			for key, value in pairs( p.superlaser.sprites ) do
				value.dead = true
				SetObjDead( value.sprite )
			end
			p.superlaser = nil
			p.mortal = true
		end
	else
		SetObjPos( p.superlaser.sp, p.x-16, p.y-32 )	
	end
end

function ResetPlayers()
	players = 
	{
		{
			x = 0,
			y = 350,
			sprite = nil,
			lives = 3,
			speed = 2,
			last_shot = 0,
			last_use = 0,
			reload_time = 500 * options.player_reload,
			size = 6 * options.player_size,
			mortal = true,
			score = 0,
			weapon_level = { 1, 0, 0 },
			color = { 1, 1, 1, 1 },
			last_x_movement = -1,
			options = {},
			energy = 0,
			energy_visuals = {},
			next_life = 50000
		},
		{
			x = 64,
			y = 350,
			sprite = CreateSprite( "sprite", 0-32, 400-32-20 ),
			lives = 3,
			speed = 2,
			last_shot = 0,
			last_use = 0,
			reload_time = 500 * options.player_reload,
			size = 6 * options.player_size,
			mortal = true,
			score = 0,
			weapon_level = { 1, 0, 0 },
			color = { 0.8, 0.8, 1, 1 },
			last_x_movement = -1,
			options = {},
			energy = 0,
			energy_visuals = {},
			next_life = 50000
		}
	}
end
