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

LIST_ACTORS = false

checked = false

viking_accessories = {}
viking_cowboy = {}
viking_hawaii = {}

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

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

--print("tech num players: ".._numplayers)

-- thank u ky dashiel
local poptions = {GAMESTATE:GetPlayerState(0):GetPlayerOptions('ModsLevel_Song'), GAMESTATE:GetPlayerState(1):GetPlayerOptions('ModsLevel_Song')}
_isusingreverse = {false, false}
_miniscale = {1,1}
for pn = 1, 2 do
	if poptions[pn] then
		_isusingreverse[pn] = poptions[pn]:Reverse() ~= 0
		_miniscale[pn] = (200 - poptions[pn]:Mini()) * 0.005
	end
end

			sw,sh = SCREEN_WIDTH,SCREEN_HEIGHT
			
			curmod = 1
			m_current = {{},{}}
			m_lastframe = {{},{}}
			m_startv = {{},{}}
			m_startt = {{},{}}
			m_endv = {{},{}}
			m_len = {{},{}}
			m_ease = {{},{}}
			m_opt1 = {{},{}}
			m_opt2 = {{},{}}
			m_tweening = {{},{}}
			modnames = {}
			m_isreal = {} --REAL mods that are part of the engine
			
			function definemod(name,initv,real)
				if not initv then initv = 0 end
				if real == nil then real = true end
				table.insert(modnames,name)
				m_isreal[name] = real
				for pn=1,2 do
					m_tweening[pn][name] = false
					m_current[pn][name] = initv
					m_lastframe[pn][name] = -1
					m_startv[pn][name] = initv
					m_endv[pn][name] = initv
					m_startt[pn][name] = 0
					m_len[pn][name] = 0
					m_opt1[pn][name] = 0
					m_opt2[pn][name] = 0
					m_ease[pn][name] = linear
				end
			end
			
			function modulo(a, b)
				return a - math.floor(a/b)*b;
			end
			
			function randomXD(t)
				if t == 0 then return 0.5 else
				return modulo(math.sin(t * 3229.3) * 43758.5453, 1) end
			end
			
			--regular ass mods
			definemod('drunk')
			definemod('tipsy')
			definemod('stealth')
			definemod('sudden')
			definemod('suddenoffset')
			definemod('brake')
			definemod('beat')
			definemod('wave')
			definemod('tiny')
			definemod('dark')
			definemod('flip')
			definemod('invert')
			definemod('centered')
			definemod('split')
			definemod('cross')
			definemod('alternate')
			definemod('reverse')
			definemod('hallway')
			definemod('distant')
			definemod('confusionoffset')
			for i=1,8 do
				definemod('movex'..i)
				definemod('movey'..i)
				definemod('dark'..i)
				definemod('tiny'..i)
				definemod('confusionoffset'..i)
			end
			
			--tweens as mods lol
			definemod('x',0,false)
			definemod('y',0,false)
			definemod('x2',0,false)
			definemod('y2',0,false)
			definemod('z',0,false)
			definemod('rotationx',0,false)
			definemod('rotationy',0,false)
			definemod('rotationz',0,false)
			definemod('rotationz2',0,false)
			definemod('zoomx',1,false)
			definemod('zoomy',1,false)
			definemod('zoomz',1,false)
			definemod('zoom',1,false)
			definemod('zoom2',1,false)
			definemod('skewx',0,false)
			
			mods, ma, ca, mfsb = {}, {}, 1, GAMESTATE:GetSongBeat();
			--function mod_do(str,pn) if pn then GAMESTATE:ApplyGameCommand('mod,'..str,pn) else GAMESTATE:ApplyGameCommand('mod,'..str) end end
			local me, m2 = function (t)
				local beat,len,ease,str1,mod = unpack(t)
				for pn=1,2 do
					--print(_diff[pn],t.min)
					if not t.min and not t.only or t.only and _diff[pn] == t.only or t.min and _diff[pn] >= t.min then
						if not t.plr or pn == t.plr then
							table.insert(mods,{beat,len,ease,str1,mod,startVal=t.startVal,opt1=t.opt1,opt2=t.opt2,plr=t.plr})
						end
					end
				end
			end, function (t) local beat,fun,per = unpack(t) table.insert(ma,{beat,fun,per}) end
			function ome(t)
				me{t[1],t[2],t[3],startVal=t[4],t[5],t[6],min=t.min,only=t.only,opt1=t.opt1,opt2=t.opt2,plr=t.plr}
			end
			
			capturedOrig = false
			origx = {SCREEN_WIDTH*0.25,SCREEN_WIDTH*0.75}
			origy = {SCREEN_HEIGHT*0.5,SCREEN_HEIGHT*0.5}
			origz = {0,0}
			
			function sm2(t)
				local b,l,e,v2,v1,mo = unpack(t)
				me{b-.05,.1,linear,v2,mo,min=t.min,plr=t.plr,only=t.only,opt1=t.opt1,opt2=t.opt2}
				me{b+.05,l-.05,e,v1,mo,min=t.min,plr=t.plr,only=t.only,opt1=t.opt1,opt2=t.opt2}
			end
			
			function set(t)
				local b,v1,mo = unpack(t)
				me{b,0,linear,v1,mo,min=t.min,plr=t.plr,only=t.only}
				return set
			end
			
			_anyplayers = false
			_firstplayer = -1
			
			m2{0,function()
				for pn=1,2 do
					local a = SCREENMAN:GetTopScreen():GetChild('PlayerP'..pn)
					
					local darkSize = math.min((SCREEN_WIDTH*.5)/320,SCREEN_HEIGHT/480)
					
					if a then
						origx[pn] = a:GetX()
						origy[pn] = a:GetY()
						origz[pn] = a:GetZ()
						
						_anyplayers = true
						if _firstplayer == -1 then
							_firstplayer = pn
						end
						
					end
					
				end
				if _firstplayer == -1 then
					_firstplayer = 1
				end
				capturedOrig = true
			end,true}
			
			
			--thanks mr thatkid!!!
			local log0_5 = 1/math.log(0.5)
			--Save this so we do one less math.log & division every call, maybe.
			
			function SM5Tiny(amt)
				--takes a nitg tiny% and returns a sm5 tiny%
				--return amt --in nitg, just return base val
				return (math.log(1-0.5*(amt*0.01))*log0_5)*100
			end
			
			function spinny(t)
				local b,d,cd,l1,l2,del = unpack(t)
				local maxc = 3
				if _doubles then
					maxc = 7
					del = del*.5
				end
				for i=0,maxc do
					local wc = i
					if cd == -1 then
						wc = maxc-i
					end
					wc = wc+1
					ome{b-l1+del*i,l1,inExpo,0,314*d,'confusionoffset'..wc,min=t.min,plr=t.plr,only=t.only}
					ome{b+del*i,l2,outExpo,-314*d,0,'confusionoffset'..wc,min=t.min,plr=t.plr,only=t.only}
				end
			end
			
			--[[
			
			for i=228,241 do
				sm2b{i,1,outCubic,SM5Tiny(-70),0,"tiny"}
			end
			for i=242,243.5,.5 do
				sm2b{i,.5,outCubic,SM5Tiny(-70),0,"tiny"}
			end
			
			local bounceHeight = 20
			me{211.104,.896,linear,bounceHeight,"y"}
			for i=212,241 do
				me{i,.5,outSine,0,"y"}
				me{i+.5,.5,inSine,bounceHeight,"y"}
			end
			me{242,1.5,linear,0,"y"}
			
			local xMove = 40
			local theRotation = 3
			local f = 1
			for i=0,3 do
				me{212+8*i,3,linear,-xMove*f,"x"}
				me{216+8*i,3,linear,0,"x"}
				me{212+8*i,2,inOutSine,-theRotation*f,"rotationz"}
				me{215+8*i,1,inOutSine,0,"rotationz"}
				me{216+8*i,2,inOutSine,theRotation*f,"rotationz"}
				me{219+8*i,1,inOutSine,0,"rotationz"}
				f=-f
			end
			
			sm2{318,1,linear,SM5Tiny(-70),0,"tiny"}
			sm2{318+32,1,linear,SM5Tiny(-70),0,"tiny"}
			
			for i=0,1 do
				sm2{325+i,.8,linear,SM5Tiny(-70),0,"tiny"}
				sm2{357+i,.8,linear,SM5Tiny(-70),0,"tiny"}
				
				sm2{373+i,.8,linear,SM5Tiny(-70),0,"tiny"}
				
				sm2{400+4*i,1.3,linear,SM5Tiny(-100),0,"tiny"}
				sm2{401.5+4*i,1.3,linear,SM5Tiny(-100),0,"tiny"}
			end
			
			for i=0,2 do
				me{330+4*i-.25,.5,linear,-16,"centered"}
				me{330.25+4*i,2,outSine,0,"centered"}
				me{362+4*i-.25,.5,linear,-16,"centered"}
				me{362.25+4*i,2,outSine,0,"centered"}
				
				sm2{330+4*i,2,linear,SM5Tiny(-70),0,"tiny"}
				sm2{362+4*i,2,linear,SM5Tiny(-70),0,"tiny"}
				
				sm2{341+i,.8,linear,SM5Tiny(-70),0,"tiny"}
			end
			
			--beat,spins,dir,inTime,outTime,delayBetweenColumns
			spinny{344.5,1,1,2,5,.5,min=2}
			
			
			set{0,100,"sudden"}
			set{0,110,"suddenoffset"}
			
			]]
			
			for i=0,7 do
				local mu = i<4 and .8 or 1
				me{68+8*i,2,outSine,100*mu,"wave"}
				me{72+8*i,4,inOutSine,0,"wave"}
				me{68+8*i,4,inOutSine,80*mu,"brake"}
				me{72+8*i,4,inOutSine,0,"brake"}
				
			end
			for i=0,2 do
				local mu = .8
				me{172+8*i,2,linear,100*mu,"wave"}
				me{174+8*i,2,linear,0,"wave"}
				me{172+8*i,2,linear,80*mu,"brake"}
				me{174+8*i,2,linear,0,"brake"}
			end
			for i=0,2 do
				local mu = 1
				me{204+8*i,2,linear,100*mu,"wave"}
				me{206+8*i,2,linear,0,"wave"}
				me{204+8*i,2,linear,80*mu,"brake"}
				me{206+8*i,2,linear,0,"brake"}
			end
			
			function bt(b,l,a)
				set{b-.5,a,"beat"}
				set{b-.5+l,0,"beat"}
			end
			
			bt(184,3,100)
			bt(216,3,-100)
			
			--SCREENMAN:SystemMessage("HELP")
			
			function cmp(a,b)
				return a[1] < b[1]
			end
			if table.getn(ma) > 1 then
				table.sort(ma, cmp)
			end
			if table.getn(mods) > 1 then
				table.sort(mods, 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
				
				while curmod <= #mods and beat > mods[curmod][1] do
					local v = mods[curmod]
					
					local mn = v[5]
					local dur = v[2]
					if v.timing and v.timing == 'end' then
						dur = v[2]-v[1]
					end
					
					print('launch attack '..v[4]..' '..mn..' at beat '..v[1])
					
					if v.plr and not v.pn then v.pn = v.plr end
					
					for pn=1,2 do
						if not v.pn or pn == v.pn then
							m_startt[pn][mn] = v[1]
							m_len[pn][mn] = dur
							m_ease[pn][mn] = v[3]
							if v.startVal then
								m_startv[pn][mn] = v.startVal
							else
								m_startv[pn][mn] = m_current[pn][mn]
							end
							if v.add then
								m_endv[pn][mn] = m_current[pn][mn]+v[4]
							else
								m_endv[pn][mn] = v[4]
							end
							m_opt1[pn][mn] = v.opt1
							m_opt2[pn][mn] = v.opt2
							m_tweening[pn][mn] = true
						end
					end
					
					curmod = curmod+1
				end
				
				for pn=1,2 do
					for _,v in pairs(modnames) do
						if m_tweening[pn][v] then
							local curtime = beat - m_startt[pn][v]
							local duration = m_len[pn][v]
							local startstrength = m_startv[pn][v]
							local diff = m_endv[pn][v] - startstrength
							local curve = m_ease[pn][v]
							local strength = curve(curtime, startstrength, diff, duration, m_opt1[pn][v], m_opt2[pn][v])
							m_current[pn][v] = strength
							if beat > m_startt[pn][v]+duration then
								m_tweening[pn][v] = false
							end
						else
							m_current[pn][v] = m_endv[pn][v]
						end
					end
				end
				
				--ONLY apply mods if there were changes THIS frame
				for pn=1,2 do
					local mstr = ''
					for _,v in pairs(modnames) do
						if m_isreal[v] and m_lastframe[pn][v] ~= m_current[pn][v] then
							mstr = mstr..'*10000 '..m_current[pn][v]..' '..v..','
							m_lastframe[pn][v] = m_current[pn][v]
						end
					end
					if mstr ~= '' then
						mod_do(mstr,pn)
					end
				end
				
				if capturedOrig then
					for pn=1,2 do
						local a = SCREENMAN:GetTopScreen():GetChild('PlayerP'..pn)
						if a then
						
							a:x(origx[pn]+(m_current[pn].x+m_current[pn].x2)*SCREEN_HEIGHT/480)
							if _isusingreverse[pn] then
								a:y(origy[pn]-(m_current[pn].y+m_current[pn].y2)*SCREEN_HEIGHT/480)
							else
								a:y(origy[pn]+(m_current[pn].y+m_current[pn].y2)*SCREEN_HEIGHT/480)
							end
							a:z(origz[pn]+m_current[pn].z)
							if _isusingreverse[pn] then
								a:rotationx(-m_current[pn].rotationx)
							else
								a:rotationx(m_current[pn].rotationx)
							end
							a:rotationy(m_current[pn].rotationy)
							a:rotationz(m_current[pn].rotationz+m_current[pn].rotationz2)
							a:basezoomx(m_current[pn].zoomx*m_current[pn].zoom*m_current[pn].zoom2)
							a:basezoomy(m_current[pn].zoomy*m_current[pn].zoom*m_current[pn].zoom2)
							a:zoomz(m_current[pn].zoomz*m_current[pn].zoom)
							a:skewx(m_current[pn].skewx)
							
						else
							
						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=cmd(visible,false), OnCommand=cmd(sleep,9E9) },
	
	Name= "xtl_actor_d",
	
}
return ac