-- EASING --
local path = GAMESTATE:GetCurrentSong():GetSongDir()..'lua/'
loadfile(path..'easing.lua')()
loadfile(path.."mods.lua")()

forged_darkness = {} forged_darkmask = {} forged_darkaux = {}
checked = false

local linear, inQuad, outQuad, inOutQuad, outInQuad, inCubic, outCubic, inOutCubic, outInCubic, inQuart,outQuart, inOutQuart, outInQuart, inQuint, outQuint, inOutQuint, outInQuint, inSine, outSine, inOutSine,outInSine, inExpo, outExpo, inOutExpo, outInExpo, inCirc, outCirc, inOutCirc, outInCirc, inElastic,outElastic, inOutElastic, outInElastic, inBack, outBack, inOutBack, outInBack, inBounce, outBounce,inOutBounce, outInBounce = ease.linear, ease.inQuad, ease.outQuad, ease.inOutQuad, ease.outInQuad,ease.inCubic, ease.outCubic, ease.inOutCubic, ease.outInCubic, ease.inQuart, ease.outQuart,ease.inOutQuart, ease.outInQuart, ease.inQuint, ease.outQuint, ease.inOutQuint, ease.outInQuint,ease.inSine, ease.outSine, ease.inOutSine, ease.outInSine, ease.inExpo, ease.outExpo, ease.inOutExpo,ease.outInExpo, ease.inCirc, ease.outCirc, ease.inOutCirc, ease.outInCirc, ease.inElastic,ease.outElastic, ease.inOutElastic, ease.outInElastic, ease.inBack, ease.outBack, ease.inOutBack,ease.outInBack, ease.inBounce, ease.outBounce, ease.inOutBounce, ease.outInBounce

	sw = SCREEN_WIDTH
	sh = SCREEN_HEIGHT --shortcuts
	
	scx = sw/2
	scy = sh/2
	
local po = {GAMESTATE:GetPlayerState(0):GetPlayerOptions'ModsLevel_Song', GAMESTATE:GetPlayerState(1):GetPlayerOptions'ModsLevel_Song'}
function mod_do(str,pn)
	--if pn then if GAMESTATE:IsPlayerEnabled(pn-1) then handle_mods(str,pn) end
	--else for pn=1,2 do if GAMESTATE:IsPlayerEnabled(pn-1) then handle_mods(str,pn) end end end
	
    if pn then
        po[pn]:FromString(str)
    else
        po[1]:FromString(str)
        po[2]:FromString(str)
    end
end

forged_numplayers = 0
local forged_diff = {0,0}
if GAMESTATE:IsHumanPlayer(PLAYER_1) then
	local stepsr = (GAMESTATE:GetCurrentSteps(PLAYER_1):GetDifficulty())
	if stepsr == "Difficulty_Beginner" then forged_diff[1] = 0 end
	if stepsr == "Difficulty_Easy" then forged_diff[1] = 1 end
	if stepsr == "Difficulty_Medium" then forged_diff[1] = 2 end
	if stepsr == "Difficulty_Hard" then forged_diff[1] = 3 end
	if stepsr == "Difficulty_Challenge" then forged_diff[1] = 4 end
	forged_numplayers = forged_numplayers+1
end
if GAMESTATE:IsHumanPlayer(PLAYER_2) then
	local stepsr = (GAMESTATE:GetCurrentSteps(PLAYER_2):GetDifficulty())
	if stepsr == "Difficulty_Beginner" then forged_diff[2] = 0 end
	if stepsr == "Difficulty_Easy" then forged_diff[2] = 1 end
	if stepsr == "Difficulty_Medium" then forged_diff[2] = 2 end
	if stepsr == "Difficulty_Hard" then forged_diff[2] = 3 end
	if stepsr == "Difficulty_Challenge" then forged_diff[2] = 4 end
	forged_numplayers = forged_numplayers+1
end

print("Forged num players: "..forged_numplayers)

mes, ma, ca, mfsb = {}, {}, 1, GAMESTATE:GetSongBeat();
local l, e, me, m2 = 'len', 'end', function (t)
	local beat,len,str1,str2,mod,ease,sus,opt1,opt2 = unpack(t)
	for pn=1,2 do
		if not t.min and not t.only or t.only and forged_diff[pn] == t.only or t.min and forged_diff[pn] >= t.min then
			if not t.plr or pn == t.plr then
				table.insert(mes,{beat,len,str1,str2,mod,'len',ease,pn,sus,opt1,opt2})
			end
		end
	end
end, function (beat,fun,per) table.insert(ma,{beat,fun,per}) end


--me{56,4,0,30,'drunk',inOutCubic,min=3}

if GAMESTATE:GetCurrentStyle():GetName() ~= 'double' then
	me{60,3,0,100,'stealth',linear,min=2}
	me{64,2,100,0,'stealth',outCubic,min=2}
	me{60,3,0,100,'dark',linear,min=2}
	me{64,2,100,0,'dark',outCubic,min=2}
	me{64,2,-30,0,'flip',outExpo,min=2}
	me{64,3,250,0,'tipsy',outElastic,min=2}
	
	if PlayerOptions.ConfusionOffset then
		me{64,2,628*-1,0,'confusionoffset1',outExpo}
		me{64,2,314*-1,0,'confusionoffset2',outExpo}
		me{64,2,-314*-1,0,'confusionoffset3',outExpo}
		me{64,2,-628*-1,0,'confusionoffset4',outExpo}
	end
else
	me{60,4,0,100,'stealth',linear,min=2}
	me{64,2,100,0,'stealth',outCubic,min=2}
	me{60,3,0,100,'dark',linear,min=2}
	me{64,2,100,0,'dark',outCubic,min=2}
	me{64,2,-20,0,'flip',outExpo,min=2}
	me{64,3,200,0,'tipsy',outElastic,min=2}
	
	if PlayerOptions.ConfusionOffset then
		me{64,2,628*-1,0,'confusionoffset1',outExpo}
		me{64,2,628*-1,0,'confusionoffset2',outExpo}
		me{64,2,314*-1,0,'confusionoffset3',outExpo}
		me{64,2,314*-1,0,'confusionoffset4',outExpo}
		me{64,2,-314*-1,0,'confusionoffset5',outExpo}
		me{64,2,-314*-1,0,'confusionoffset6',outExpo}
		me{64,2,-628*-1,0,'confusionoffset7',outExpo}
		me{64,2,-628*-1,0,'confusionoffset8',outExpo}
	end	
end

me{80,1,-100,-100,'suddenoffset',linear}
me{83.4,1,-100,200,'suddenoffset',linear}
me{81,1,0,80,'sudden',outCubic}
me{86,3,0,0,'sudden',linear}

local f = 1
for i=0,3 do
	me{280.75-.1+i*.75,.2,0,30,'brake',linear}
	me{280.75+.1+i*.75,.5,30,0,'brake',outQuad}
	me{280.75-.1+i*.75,.2,0,30*f,'drunk',linear}
	me{280.75+.1+i*.75,.5,30*f,0,'drunk',outCubic}
	f=-f
end

me{289.5,.5,0,80,'brake',linear}
me{290,2,80,0,'brake',outCubic}

me{289.5,.5,0,50,'stealth',linear}
me{290,3,50,0,'stealth',outQuad}

me{306,1,50,0,'stealth',linear}

for p=316,380,8 do
	if p==380 then
		me{p-.25,.25,0,50,'stealth',linear}
		me{p,8,50,0,'stealth',outCubic}
	else
		me{p-.1,.1,0,30,'stealth',linear}
		me{p,4,30,0,'stealth',outCubic}
	end
end

m2(0,function()
	for pn=1,2 do
		forged_darkaux[pn]:x(0)
		forged_darkaux[pn]:y(0)
		forged_darkaux[pn]:z(0)
	end
end,true)

m2(60,function()
	for pn=1,2 do
		forged_darkaux[pn]:linear(220/167)
		forged_darkaux[pn]:z(0.3)
		forged_darkaux[pn]:decelerate(60/167)
		forged_darkaux[pn]:z(0)
	end
end)

m2(196,function()
	for pn=1,2 do
		forged_darkaux[pn]:linear(360/167)
		forged_darkaux[pn]:z(1)
	end
end)
m2(202,function()
	for pn=1,2 do
		forged_darkaux[pn]:z(1)
	end
	forged_staticaux:x(.15)
end,true)

m2(264,function()
	for pn=1,2 do
		forged_darkaux[pn]:linear(240/167)
		forged_darkaux[pn]:z(0)
	end
	forged_staticaux:linear(240/167)
	forged_staticaux:x(0)
end)
m2(268,function()
	for pn=1,2 do
		forged_darkaux[pn]:z(0)
	end
	forged_staticaux:x(0)
end,true)

m2(376,function()
	for pn=1,2 do
		forged_darkaux[pn]:accelerate(4*60/167)
		forged_darkaux[pn]:z(.5)
		forged_darkaux[pn]:decelerate(4*60/167)
		forged_darkaux[pn]:z(1)
	end
	forged_staticaux:linear(240/167)
	forged_staticaux:x(.2)
end)
m2(384,function()
	for pn=1,2 do
		forged_darkaux[pn]:z(1)
	end
end,true)

for i=0,3 do
	local i=i
	m2(380+8*i,function()
		forged_scaler:finishtweening()
		if forged_numplayers == 1 then
			forged_scaler:x(1.2)
		end
		forged_scaler:y(1.2)
		forged_scaler:decelerate(7.9*60/167)
		if forged_numplayers == 1 then
			forged_scaler:x(1)
		end
		forged_scaler:y(1)
		
		forged_staticaux:x(.2 + .04*i)
		if i < 3 then
			forged_staticaux:decelerate(7.9*60/167)
			forged_staticaux:x(.1 + .033*i)
		else
			forged_staticaux:decelerate(8*60/167)
			forged_staticaux:x(.1 + .033*i)
			forged_staticaux:accelerate(6*60/167)
			forged_staticaux:x(1)
		end
		
	end)
end

m2(204,function()
	for pn=1,2 do
		if forged_plr[pn] then
			forged_darkaux[pn]:x(1)
			forged_darkaux[pn]:y(forged_startsize1[ forged_diff[pn]+1 ])
		end
	end
end)
m2(375,function()
	for pn=1,2 do
		if forged_plr[pn] then
			forged_darkaux[pn]:x(1)
			forged_darkaux[pn]:y(forged_startsize2[ forged_diff[pn]+1 ])
		end
	end
end,true)
m2(416,function()
	for pn=1,2 do
		forged_darkaux[pn]:y(0)
	end
end,true)

forged_startsize1 = {1.6,1.5,1.4,1.3,1.2}
forged_endsize1 = {1.1,0.9,0.7,0.6,0.5}
forged_startsize2 = {1.6,1.5,1.4,1.3,1.2}
forged_endsize2 = {1.1,1.0,0.8,0.7,0.6}

if GAMESTATE:GetCurrentStyle():GetName() == 'double' then
	forged_startsize1 = {1.6,1.6,1.6,1.2,1}
	forged_endsize1 = {1,0.8,0.7,0.5,0.5}
	forged_startsize2 = {1.6,1.6,1.6,1.6,1.6}
	forged_endsize2 = {1.3,1.2,1.1,1.1,1.1}
end

function cmp(a,b)
	return a[1] < b[1]
end
if table.getn(ma) > 1 then
	table.sort(ma, cmp)
end

local ac = Def.ActorFrame{
	
	Def.Actor{
		OnCommand=function(s)
			s:queuecommand('Loop')
		end,
		LoopCommand=function(self)
			local beat = GAMESTATE:GetSongBeat()
			if beat > mfsb+0.1 then
				
				if not checked then
					forged_plr = {}
					forged_anyplayers = false
					forged_firstplayer = -1
					for pn=1,2 do
						local doublesMult = 1
						if GAMESTATE:GetCurrentStyle():GetName() == 'double' then
							doublesMult = 2.4
							forged_diff[pn] = forged_diff[pn]-2
						end
						local darkSize = math.min((SCREEN_WIDTH*.5)/320,SCREEN_HEIGHT/480)
						if SCREENMAN:GetTopScreen():GetChild('PlayerP'..pn) then
							forged_plr[pn] = SCREENMAN:GetTopScreen():GetChild('PlayerP'..pn)
							forged_anyplayers = true
							if forged_firstplayer == -1 then
								forged_firstplayer = pn
							end
						end
						--if GAMESTATE:IsEditMode() then
						--	forged_plr[2] = nil
						--end
						if forged_plr[pn] then
							--print('P'..pn..' x = '..forged_plr[pn]:GetX())
							forged_darkness[pn]:x(forged_plr[pn]:GetX())
							forged_darkness[pn]:y(SCREEN_CENTER_Y)
							forged_darkness[pn]:basezoomx(doublesMult * darkSize)
							forged_darkness[pn]:basezoomy(darkSize)
							forged_darkmask[pn]:x(forged_plr[pn]:GetX())
							forged_darkmask[pn]:y(SCREEN_CENTER_Y)
							forged_darkmask[pn]:basezoomx(doublesMult * darkSize)
							forged_darkmask[pn]:basezoomy(darkSize)
						end
					end
					
					checked = true
				end
				
				if beat > 202 and beat < 204 then
					local scl = outExpo(beat-202,0,1,2)
					for pn=1,2 do
						if forged_plr[pn] then
							forged_darkaux[pn]:x(scl*1)
							forged_darkaux[pn]:y(scl*forged_startsize1[ forged_diff[pn]+1 ])
						end
					end
				end
				if beat > 204 and beat < 268 then
					local scl = inOutCubic(beat-204,0,1,64)
					for pn=1,2 do
						if forged_plr[pn] then
							local ss = forged_startsize1[ forged_diff[pn]+1 ]
							local es = forged_endsize1[ forged_diff[pn]+1 ]
							forged_darkaux[pn]:y(ss + scl*(es-ss))
						end
					end
				end
				if beat > 376 and beat < 412 then
					local scl = inOutCubic(beat-376,0,1,36)
					for pn=1,2 do
						if forged_plr[pn] then
							local ss = forged_startsize2[ forged_diff[pn]+1 ]
							local es = forged_endsize2[ forged_diff[pn]+1 ]
							forged_darkaux[pn]:y(ss + scl*(es-ss))
						end
					end
				end
				if beat > 412 and beat < 416 then
					local scl = inCubic(beat-412,0,1,4)
					for pn=1,2 do
						if forged_plr[pn] then
							local ss = forged_endsize2[ forged_diff[pn]+1 ]
							local es = 0
							forged_darkaux[pn]:y(ss + scl*(es-ss))
						end
					end
				end
				
				if forged_anyplayers then
					forged_darkcover:diffusealpha(forged_darkaux[forged_firstplayer]:GetZ())
				end
				
				for pn=1,2 do
					if forged_plr[pn] then
						forged_darkness[pn]:zoomx(forged_darkaux[pn]:GetX()*forged_scaler:GetX())
						forged_darkness[pn]:zoomy(forged_darkaux[pn]:GetY()*forged_scaler:GetY())
						forged_darkness[pn]:diffusealpha(forged_darkaux[pn]:GetZ())
						
						forged_darkmask[pn]:zoomx(forged_darkaux[pn]:GetX()*forged_scaler:GetX())
						forged_darkmask[pn]:zoomy(forged_darkaux[pn]:GetY()*forged_scaler:GetY())
					else
						forged_darkmask[pn]:visible(false)
					end
				end
				
				forged_static:diffusealpha(forged_staticaux:GetX())
				
				for i,v in pairs(mes) do
					if beat >=v[1] then
						if (v[6] == 'len' and beat <=v[1]+v[2]) or (v[6] == 'end' and beat <=v[2]) then
							local duration, curtime, diff, startstrength, curve, mod = v[2], beat - v[1], v[4] - v[3], v[3], v[7], v[5]
							if v[6] == 'end' then duration = v[2] - v[1] end
							local strength = curve(curtime, startstrength, diff, duration, v[10], v[11])
							local modstr = v[5] == 'xmod' and strength..'x' or (v[5] == 'cmod' and 'C'..strength or strength..' '..v[5])
							mod_do('*10000 '..modstr,v[8])
						elseif (v[9] and ((v[6] == 'len' and beat <=v[1]+v[2]+v[9]) or (v[6] == 'end' and beat <=v[9]))) then
							local strength, modstr = v[4], v[5] == 'xmod' and strength..'x' or (v[5] == 'cmod' and 'C'..strength or strength..' '..v[5])
							mod_do('*10000 '..modstr,v[8])
						end
					end
				end
				
				while ca<=table.getn(ma) and GAMESTATE:GetSongBeat()>=ma[ca][1] do
					if ma[ca][3] or GAMESTATE:GetSongBeat() < ma[ca][1]+2 then
						ma[ca][2]()
					end
					ca = ca+1;
				end
			end
			self:sleep(1/60) self:queuecommand('Loop')
		end
	},
	
	Def.Quad{ InitCommand=function(self) forged_staticaux = self end, OnCommand=cmd(visible,false;) },
	Def.Quad{ InitCommand=function(self) forged_scaler = self end, OnCommand=cmd(visible,false;x,1;y,1) },
	Def.Quad{ InitCommand=function(self) forged_darkaux[1] = self end, OnCommand=cmd(visible,false) },
	Def.Quad{ InitCommand=function(self) forged_darkaux[2] = self end, OnCommand=cmd(visible,false) },

	Def.Sprite{
		Delay0000= 0.034,
		Delay0001= 0.034,
		Delay0002= 0.034,
		Delay0003= 0.034,
		Frame0000= 0,
		Frame0001= 1,
		Frame0002= 2,
		Frame0003= 3,
		InitCommand= function(self) forged_static = self; self:SetTextureFiltering(false) end,
		OnCommand= cmd(x,SCREEN_CENTER_X;y,SCREEN_CENTER_Y;diffusealpha,0;scaletocover,0,0,SCREEN_WIDTH,SCREEN_HEIGHT),
		Texture= "static",
	},

	
	LoadActor("darkness")..{ InitCommand=function(self) forged_darkness[1] = self end, OnCommand=cmd(diffusealpha,0) },
	LoadActor("darkness")..{ InitCommand=function(self) forged_darkness[2] = self end, OnCommand=cmd(diffusealpha,0) },
	LoadActor("darkness")..{ InitCommand=function(self) forged_darkmask[1] = self end, OnCommand=cmd(zwrite,1;blend,"noeffect";) },
	LoadActor("darkness")..{ InitCommand=function(self) forged_darkmask[2] = self end, OnCommand=cmd(zwrite,1;blend,"noeffect";) },
	
	Def.Quad{ InitCommand=cmd(visible,false), OnCommand=cmd(sleep,9E9) },
	
	Def.Quad{
		InitCommand=function(self) forged_darkcover = self end,
		OnCommand=cmd(diffuse,0,0,0,0;stretchto,0,0,SCREEN_WIDTH,SCREEN_HEIGHT;ztestmode,"writeonpass";)
	},
	
}
return ac