local bpm = 173.0
local beat_duration = 60.0 / bpm

local command_list = {}
local command_index = 1

-- BEGIN init command list
table.insert(command_list, 'Oh')
for i=1,16 do table.insert(command_list, 'Blink') end
for i=1,6 do table.insert(command_list, 'Ah') end

table.insert(command_list, 'Oh')
for i=1,14 do table.insert(command_list, 'Blink') end
for i=1,7 do table.insert(command_list, 'Ah') end

table.insert(command_list, 'Oh')
for i=1,16 do table.insert(command_list, 'Blink') end
for i=1,6 do table.insert(command_list, 'Ah') end

table.insert(command_list, 'Oh')
for i=1,16 do table.insert(command_list, 'Blink') end
for i=1,2 do table.insert(command_list, 'Ah') end
for i=1,2 do table.insert(command_list, 'Blink') end
table.insert(command_list, 'Ah')
for i=1,4 do table.insert(command_list, 'Blink') end


table.insert(command_list, 'Oh')
for i=1,16 do table.insert(command_list, 'Blink') end
for i=1,6 do table.insert(command_list, 'Ah') end

table.insert(command_list, 'Oh')
for i=1,14 do table.insert(command_list, 'Blink') end
for i=1,7 do table.insert(command_list, 'Ah') end

table.insert(command_list, 'Oh')
for i=1,16 do table.insert(command_list, 'Blink') end
for i=1,6 do table.insert(command_list, 'Ah') end

table.insert(command_list, 'Oh')
for i=1,16 do table.insert(command_list, 'Blink') end
for i=1,2 do table.insert(command_list, 'Ah') end
for i=1,2 do table.insert(command_list, 'Blink') end
table.insert(command_list, 'Ah')
for i=1,4 do table.insert(command_list, 'Blink') end


table.insert(command_list, 'Oh')
for i=1,16 do table.insert(command_list, 'Blink') end
for i=1,6 do table.insert(command_list, 'Ah') end

table.insert(command_list, 'Oh')
for i=1,14 do table.insert(command_list, 'Blink') end
for i=1,7 do table.insert(command_list, 'Ah') end

table.insert(command_list, 'Oh')
for i=1,16 do table.insert(command_list, 'Blink') end
for i=1,6 do table.insert(command_list, 'Ah') end

table.insert(command_list, 'Oh')
for i=1,16 do table.insert(command_list, 'Blink') end
for i=1,2 do table.insert(command_list, 'Ah') end
for i=1,2 do table.insert(command_list, 'Blink') end
table.insert(command_list, 'Ah')
for i=1,4 do table.insert(command_list, 'Blink') end


table.insert(command_list, 'Oh')
for i=1,16 do table.insert(command_list, 'Blink') end
for i=1,6 do table.insert(command_list, 'Ah') end

table.insert(command_list, 'Oh')
for i=1,14 do table.insert(command_list, 'Blink') end
for i=1,7 do table.insert(command_list, 'Ah') end

for i=1,5*16 do table.insert(command_list, 'Blink') end

for i=1,2*16 do table.insert(command_list, 'Preowr') end
-- END init command list

local for_each_player = function(iter)
	-- iter(SCREENMAN:GetTopScreen())

	for player_index=1,2 do
		local player = SCREENMAN:GetTopScreen():GetChild('PlayerP' .. player_index)
		
		if player then iter(player) end
	end
end

local blink = function(player)
	local x = 0.08 * _screen.w * (2 * math.random() - 1)
	local y = 0.08 * _screen.h * (2 * math.random() - 1)

	player
		:addx(x)
		:addy(y)
		:sleep(0.125 * beat_duration)
		:diffusealpha(0)
		:addx(-x)
		:addy(-y)
		:sleep(0.125 * beat_duration)
		:diffusealpha(1)
end

local oh = function(player)
	player
		:linear(beat_duration)
		:addy(-0.3 * _screen.h)
		:sleep(0)
		:addy(0.3 * _screen.h)
end

local ah = function(player)
	local t = math.random() * 2.0 * math.pi
	local r = 0.2 * _screen.h
	local x = r * math.cos(t)
	local y = r * math.sin(t)

	player
		:decelerate(0.5 * beat_duration)
		:addx(x)
		:addy(y)
		:sleep(0)
		:addx(-x)
		:addy(-y)
end

local preowr_magnitude = 100
local preowr_change = preowr_magnitude / 31
local preowr = function(player)
	player
		:vibrate()
		:effectmagnitude(preowr_magnitude,preowr_magnitude,0)
end

local let_the_bass_kick = function(player_index)
	local player = SCREENMAN:GetTopScreen():GetChild('PlayerP' .. player_index)
	
	if not player then return end
	
	for i=1,32 do
		player:sleep(0.125 * beat_duration)
		      :diffusealpha(0)
			  :sleep(0.125 * beat_duration)
			  :diffusealpha(1)
	end
end

local next_count = 0

local for_each_options = function(iter)
	for player_index=1,2 do
		if GAMESTATE:IsPlayerEnabled(player_index-1) then
			local ps = GAMESTATE:GetPlayerState('PlayerNumber_P' .. player_index)
			local po = ps:GetPlayerOptions('ModsLevel_Song')
			iter(po)
		end
	end
end

local mods_actor = Def.ActorFrame {
	OnCommand=function(self)
		self:queuecommand('Wait1')
	end,
}

local mods_list = {
	{
		at = 2.815,
		apply = function(po)
			po:Beat(2,999999)
		end,
	},
	{
		at = 19.756,
		apply = function(po)
			po:Centered(1,0.25)
			po:Brake(0.25,0.25)
		end,
	},
	{
		at = 23.991,
		apply = function(po)
			po:Beat(0,999999)
			po:Reverse(1,999999)
		end,
	},
	{
		at = 24.255,
		apply = function(po)
			po:Reverse(0,999999)
		end,
	},
	{
		at = 24.520,
		apply = function(po)
			po:Reverse(1,999999)
		end,
	},
	{
		at = 24.785,
		apply = function(po)
			po:Reverse(0,999999)
		end,
	},
	{
		at = 25.050,
		apply = function(po)
			po:Reverse(1,999999)
		end,
	},
	{
		at = 25.226,
		apply = function(po)
			po:Reverse(0,999999)
		end,
	},
	{
		at = 25.403,
		apply = function(po)
			po:Centered(0,1)
			po:Brake(0,0.25)
			po:Beat(2,999999)
		end,
	},
	{
		at = 35.285,
		apply = function(po)
			po:Dizzy(8,999999)
		end,
	},
	{
		at = 35.638,
		apply = function(po)
			po:Dizzy(0,999999)
			po:Beat(0,999999)
		end,
	},
	{
		at = 35.991,
		apply = function(po)
			po:Beat(2,999999)
			po:Brake(0.5,999999)
		end,
	},
	{
		at = 36.343,
		apply = function(po)
			po:Brake(-0.5,999999)
		end,
	},
	{
		at = 36.697,
		apply = function(po)
			po:Brake(0,999999)
		end,
	},
	{
		at = 47.638,
		apply = function(po)
			po:Beat(0,999999)
		end,
	},
	{
		at = 47.991,
		apply = function(po)
			po:Tipsy(0.5,1)
			po:Drunk(0.5,1)
		end,
	},
	{
		at = 58.932,
		apply = function(po)
			po:Tipsy(0,1)
			po:Drunk(0,1)
		end,
	},
	{
		at = 59.285,
		apply = function(po)
			po:Beat(2,999999)
		end,
	},
	{
		at = 71.929,
		apply = function(po)
			po:Beat(0,999999)
			po:Brake(1,999999)
		end,
	},
	{
		at = 71.973,
		apply = function(po)
			po:Brake(0,8)
		end,
	},
	{
		at = 72.190,
		apply = function(po)
			po:Beat(0,999999)
			po:Brake(0.5,999999)
		end,
	},
	{
		at = 72.233,
		apply = function(po)
			po:Brake(0,8)
		end,
	},
	{
		at = 72.450,
		apply = function(po)
			po:Beat(0,999999)
			po:Brake(0.5,999999)
		end,
	},
	{
		at = 72.494,
		apply = function(po)
			po:Brake(0,8)
		end,
	},
	{
		at = 72.711,
		apply = function(po)
			po:Beat(0,999999)
			po:Brake(0.5,999999)
		end,
	},
	{
		at = 72.754,
		apply = function(po)
			po:Brake(0,8)
		end,
	},
}

local cur_time = -0.009
for i,mod in ipairs(mods_list) do
	local sleep_time = mod.at - cur_time
	cur_time = mod.at
	mods_actor['Wait' .. i .. 'Command'] = function(self)
		self:sleep(sleep_time):queuecommand('Mods' .. i)
	end
	
	mods_actor['Mods' .. i .. 'Command'] = function(self)
		for_each_options(mod.apply)
		self:queuecommand('Wait' .. (i+1))
	end
end 

local last_score_x = 0

return Def.ActorFrame {
	InitCommand=function(self)
		self:sleep(420)
	end,
	Def.ActorFrame {
		OnCommand=function(self)
			local under = SCREENMAN:GetTopScreen():GetChild('Underlay')
			
			if not under then return end
			
			under:addx(-9999)
			
			for player_index=1,2 do
				local score = under:GetChild('P' .. player_index .. 'Score')
				
				if score then
					score:addx(9999)
				end
			end
			
			self:queuecommand('MoveScores')
		end,
		MoveScoresCommand=function(self)
			local under = SCREENMAN:GetTopScreen():GetChild('Underlay')
			
			if not under then return end
			
			local beat = GAMESTATE:GetSongBeat()
			
			if beat > 8 then
				
				local x = 100 * math.pow(math.sin(math.pi * (beat-0.6)), 11)
				
				for player_index=1,2 do
					local score = under:GetChild('P' .. player_index .. 'Score')
					
					if score then
						score:addx(x - last_score_x)
					end
				end
				
				last_score_x = x
			end
			
			
			self:sleep(1/60):queuecommand('MoveScores')
		end,
	},
	Def.ActorFrame {
		OnCommand=function(self)
			self:sleep(73.328043):queuecommand('Next')
		end,
		NextCommand=function(self)
			next_count = next_count + 1
			if command_index > #command_list then return end
			
			local command = command_list[command_index]
			command_index = command_index + 1
			
			self:queuecommand(command)
		end,
		
		BlinkCommand=function(self)
			for_each_player(blink)
			self:sleep(0.25 * beat_duration):queuecommand('Next')
		end,
		
		OhCommand=function(self)
			for_each_player(oh)
			self:sleep(beat_duration):queuecommand('Next')
		end,
		
		AhCommand=function(self)
			for_each_player(ah)
			self:sleep(0.5 * beat_duration):queuecommand('Next')
		end,
		
		PreowrCommand=function(self)
			for_each_player(preowr)
			preowr_magnitude = preowr_magnitude - preowr_change
			self:sleep(0.25 * beat_duration):queuecommand('Next')
		end
	},
	mods_actor,
	Def.ActorFrame {
		InitCommand=function(self)
			self:xy(_screen.cx, _screen.cy)
		end,
		OnCommand=function(self)
			self
				:diffusealpha(0)
				:linear(0.5)
				:diffusealpha(1)
				:sleep(11)
				:linear(0.5)
				:diffusealpha(0)
		end,
		Def.Quad {
			InitCommand=function(self)
				self:zoomtowidth(_screen.w)
				self:zoomtoheight(_screen.h)
				self:diffuse({0,0,0,0.9})
			end,
		},
		
		Def.BitmapText {
			Font="Common normal",
			InitCommand=function(self)
				self:zoom(2)
				self:settext("PHOTOSENSITIVITY WARNING\n\nThis chart may trigger seizures\nin people with photosensitive epilepsy.\nPlayer discretion is advised.")
			end,
		},
	},
}