--SMILER 2 WOOOAH!
--Mods by HellKiteChaos & MrTwinkles

--This whole file stolen from Benpai x Crash Cringle's Delightful Day from the pack Animal Crossover.

local P1, P2, P1Score, P2Score
local difficulty, sTable
local songName= GAMESTATE:GetCurrentSong():GetSongDir() -- Looks for Song
local last_score_x = 0
local musicrate = GAMESTATE:GetSongOptionsObject("ModsLevel_Song"):MusicRate()

-- Deals with the resolution of the game
local WideScale = function(AR4_3, AR16_9)
	-- return scale( SCREEN_WIDTH, 640, 854, AR4_3, AR16_9 )
	local w = 480 * PREFSMAN:GetPreference("DisplayAspectRatio")
	return scale( w, 640, 854, AR4_3, AR16_9 )
 end

-- Applies Players options to not be disabled-
local function Handler_mod_internal(str, pn)
	local ps= GAMESTATE:GetPlayerState(pn)
	local pmods= ps:GetPlayerOptionsString('ModsLevel_Song')
	ps:SetPlayerOptions('ModsLevel_Song', pmods .. ', ' .. str)
	--GAMESTATE:ApplyGameCommand('mod,'..str, pn)
end

-- Checks if the song difficulty is EDIT and returns a TRUE or FALSE
local function isEditMode()
	for _,player in ipairs(GAMESTATE:GetHumanPlayers()) do
		if (GAMESTATE:GetCurrentSteps(player):GetDifficulty() == "Difficulty_Edit") then
			return true;
		end
	end
	return false;
end

-- Appears to check each player and the difficulty they selected either HARD or CHALLENGE. Appears to set the table value sTable[x] with the current player and step selection.
local function setEditChart()
	-- Captures current song and step type (Singles or Doubles etc.)
	sTable = GAMESTATE:GetCurrentSong():GetStepsByStepsType( "StepsType_Dance_Single" ); 
	
	-- Appears to check each player and the difficulty they selected either HARD or CHALLENGE. Appears to set the table value sTable[x] with the current player and step selection.
	for _,player in ipairs(GAMESTATE:GetHumanPlayers()) do
		if (GAMESTATE:GetCurrentSteps(player):GetDifficulty() == "Difficulty_Challenge" or GAMESTATE:GetCurrentSteps(player):GetDifficulty() == "Difficulty_Hard") then
			GAMESTATE:SetCurrentSteps(player,sTable[2])
			SCREENMAN:SetNewScreen('ScreenGameplay')
		end
	end
end

-- Looks for many players are on the screen 
local function Handler_mod(str) 
	if (isEditMode()) then 
		return 
	end
	
	for i=1,2 do
		Handler_mod_internal(str, 'PlayerNumber_P' .. i)
	end
end

-- Houses the MOD arrays
local function Handler_init() 
	-- Variable setup
	fgcurcommand = 0;
	wndr_skewx = 0.3;
	checked = false;
	curmod = 1;
	
	-- Checks if the chart is EDIT. If so, return (Escape the function)
	if (isEditMode()) then
		setEditChart()
		return;
	end
	
	-- If player 1 and isEditMode is false, set var P1 and set visable to false.
	if SCREENMAN:GetTopScreen():GetChild('PlayerP1') and not isEditMode() then
		P1 = SCREENMAN:GetTopScreen():GetChild('PlayerP1')
		P1:visible(false)
	end
	
	-- If player 2 and isEditMode is false, set var P2 and set visable to false.
	if SCREENMAN:GetTopScreen():GetChild('PlayerP2') and not isEditMode() then
		P2 = SCREENMAN:GetTopScreen():GetChild('PlayerP2')
		P2:visible(false)
	end
	
	-- This appears to set the player score back at the top of the screen
	if SCREENMAN:GetTopScreen():GetChild('Underlay'):GetChild('P1Score') and not isEditMode() then
		P1Score = SCREENMAN:GetTopScreen():GetChild('Underlay'):GetChild('P1Score')
	end
	
	-- This appears to set the player score back at the top of the screen
	if SCREENMAN:GetTopScreen():GetChild('Underlay'):GetChild('P2Score')and not isEditMode() then
		P2Score = SCREENMAN:GetTopScreen():GetChild('Underlay'):GetChild('P2Score')
	end

	--{beat,'mod'},
	mods = {

		-- Roller Coaster Hills
		{0, '*0.35 175% Distant,*1 25% Bumpy'},	
		{16, '-10% Confusion'},
		{17, '10% Confusion'},
		{18, '-10% Confusion'},
		{19, '10% Confusion'},
		{20, '-10% Confusion'},
		{21, '10% Confusion'},
		{22, '-10% Confusion'},
		{23, '10% Confusion'},
		{24, '-10% Confusion'},
		{25, '10% Confusion'},
		{26, '-10% Confusion'},
		{27, '10% Confusion'},
		{28, '-10% Confusion'},
		{29, '10% Confusion'},
		{30, '-10% Confusion'},
		{31, '10% Confusion'},
		{32, '-10% Confusion'},
		{33, '10% Confusion'},
		{34, '-10% Confusion'},
		{35, '10% Confusion'},
		{36, '-10% Confusion'},
		{37, '10% Confusion'},
		{38, '-10% Confusion'},
		{39, '10% Confusion'},
		{40, '-10% Confusion'},
		{41, '10% Confusion'},
		{42, '-10% Confusion'},
		{43, '10% Confusion'},
		{44, '-10% Confusion'},
		{45, '10% Confusion'},
		{46, '-10% Confusion'},
		{47, '10% Confusion'},
		{48, '-10% Confusion'},
		{49, '10% Confusion'},
		{50, '-10% Confusion'},
		{51, '10% Confusion'},
		{52, '-10% Confusion'},
		{53, '10% Confusion'},
		{54, '-10% Confusion'},
		{55, '10% Confusion'},
		{56, '-10% Confusion'},
		{57, '10% Confusion'},
		{58, '-10% Confusion'},
		{59, '10% Confusion'},
		{60, '-10% Confusion'},
		{61, '10% Confusion'},
		{62, '-10% Confusion'},
		{63, '10% Confusion'},
		{64, '-10% Confusion'},
		{65, '10% Confusion'},
		{66, '-10% Confusion'},
		{67, '10% Confusion'},
		{68, '-10% Confusion'},
		{69, '10% Confusion'},
		{70, '-10% Confusion'},
		{71, '10% Confusion'},
		{72, '-10% Confusion'},
		{73, '10% Confusion'},
		{74, '-10% Confusion'},
		{75, '10% Confusion'},
		{76, '-10% Confusion'},
		{77, '10% Confusion'},
		{78, '*3 no Distant, *99999 no Bumpy, no Confusion'},

		--Cleanup from WAG
		{159, '*99999 50% Cross'},
		{159.25, '*99999 100% Cross'},
		{159.5, '*99999 no Cross, *99999 50% Split'},
		{159.75, '*99999 100% Split'},
		{160, '*99999 50% Split, *0.25 Dark'},
		{160.25, '*99999 50% Cross'},
		{160.5, '*99999 100% Cross'},
		{160.75, '*99999 no Cross, *99999 50% Split'},
		{161, '*99999 100% Split'},
		{161.25, '*99999 50% Split'},
		{161.50, '*99999 no Split'},
		
		--Pre Heart Beat HAHAs
		{172, '*0.5 no Dark, *99999 75% Sudden'},
	
		--Heart Beat HAHAs
		{176, '*99999 -100% Tiny'},
		{176.38, '*99999 no Tiny'},
		{177, '*99999 Stealth, Dark'},
		{177.5, '*99999 No Stealth'},
		{178, '*99999 -100% Tiny'},
		{178.38, '*99999 no Tiny'},
		{179, '*99999 Stealth, Dark'},
		{179.5, '*99999 No Stealth'},
		{180, '*99999 -100% Tiny'},
		{180.38, '*99999 no Tiny'},
		{181, '*99999 Stealth, Dark'},
		{181.5, '*99999 No Stealth'},
		{182, '*99999 -100% Tiny'},
		{182.38, '*99999 no Tiny'},
		{183, '*99999 Stealth, Dark'},
		{183.5, '*99999 No Stealth'},
		{184, '*99999 -100% Tiny'},
		{184.38, '*99999 no Tiny'},
		{185, '*0.5 No Dark,*99999 no Sudden'},

		--Warning
		{189, '*2 Stealth, Blink'},
		{195, '*2 no Stealth'},
		{201, '*2 Stealth'},
		{207, '*2 no Stealth'},
		{211, 'no Stealth, no Blink'},

		--Static Transitions
		{237, '*3 Reverse,*3 Tornado,*99999 Blink'},
		{239, '*99999 no Tornado,*99999 no Blink'},
		{269, '*3 no Reverse,*3 Tornado,*99999 Blink'},
		{271, '*99999 no Tornado,*99999 no Blink'},
		{301, '*3 Reverse,*3 Tornado,*99999 Blink'},
		{303, '*99999 no Tornado,*99999 no Blink,'},
		{333, '*3 no Reverse,*3 Tornado,*99999 Blink'},
		{335, '*99999 no Tornado,*99999 no Blink'},
		
		-- {237, '*3 Tornado,*99999 Blink,*99999 Flip'},
		-- {239, '*99999 no Tornado,*99999 no Blink'},
		-- {269, '*3 Tornado,*99999 Blink'},
		-- {271, '*99999 no Tornado,*99999 no Blink, *99999 no Flip'},
		-- {301, '*3 Tornado,*99999 Blink,*99999 Flip'},
		-- {303, '*99999 no Tornado,*99999 no Blink,'},
		-- {333, '*3 Tornado,*99999 Blink'},
		-- {335, '*99999 no Tornado,*99999 no Blink, *99999 no Flip'},
	
		--Post Static Transition
		{338.5, '*99999 Dark'},
		{340, '*4 no Dark'},
		{343, '*99999 Dark'},
		{345, '*4 no Dark'},
		
		--Ending
		{373, '25% Drunk, 10% Confusion'},
		{391.5, '-25% Drunk, -10% Confusion'},
		{423.5, '25% Drunk, 10% Confusion'},
		{431.5, '-25% Drunk, -10% Confusion'},
		{438, 'no Drunk, no Confusion'},
	}


	--SCREAMING GUMBALL / timed message broadcaster
	curmessage = 1;
	--{beat,message,ignoreIfAhead}
	messages = {
		--Intro
		{4,'FadeOutUIfast'},
		{6,'FadeInUIfast'},	
		{14.5,'FadeOutUIfast'},
		{15.5,'FadeInUIfast'},	
			
		--2nd half of intro
		{77,'FadeOutUIfast'},
		{78,'WagPlayers'},
		{80,'FadeInUIfast'},

		--Prep for HAHA's
		{159.0,'Stop'},
		{160.0,'FadeOutUIslow'},
		{170.0,'VibrateOnLite'},
		{176.0,'VibrateOff'},
		
		--Warning
		{189.0, 'VibrateOn'},
		{211.0, 'VibrateOff'},
		
		--UI Cleanup before Static
		{213.0,'FadeInUI'},
		
		--Static Transitions
		{237.0,'FadeOutUIfast'},
		{239.0,'FadeInUIfast'},
		{269.0,'FadeOutUIfast'},
		{271.0,'FadeInUIfast'},
		{301.0,'FadeOutUIfast'},
		{303.0,'FadeInUIfast'},
		
		--Post Static Transition
		{336.0, 'VibrateOnLite'},
		{338.5, 'VibrateOff'},
		{340.0, 'VibrateOnLite'},
		{343.0, 'VibrateOff'},
	}
	
end

-- Updates the command to look for the players at the start of the song.
local function Handler_update() 

	-- Looks at the current song beat and if this function has already been "checked" 
	if GAMESTATE:GetSongBeat()>=0.1 and not checked then
		screen = SCREENMAN:GetTopScreen()
		checked = true;
	end
	
	
	-- Collect the BPM of the song?
	local beat = GAMESTATE:GetSongBeat()

	-- Collect all the mods that will be applied in this frame into one string.
	-- Mod tweening doesn't work correctly if the mods are in seperate commands.
	local mods_this_frame= {} -- Sets the array
	
	
	-- Adds the mod passed through as the argument mod_str and adds it to the array string
	local function add_mod(mod_str)
		mods_this_frame[#mods_this_frame+1]= mod_str
	end
	
	
	-- Execute the mod string
	local function execute_mods()
		
		-- If there are no mods in the string, then exit the function
		if #mods_this_frame <= 0 then 
			return 
		end
		
		
		-- No clue whats happening here yet
		local total_mod_str= ""
		for i, ms in ipairs(mods_this_frame) do
			if #total_mod_str > 0 then
				total_mod_str= total_mod_str .. ", "
			end
			total_mod_str= total_mod_str .. ms
		end
		Handler_mod(total_mod_str)
	end
	
	while curmod<= #mods and GAMESTATE:GetSongBeat()>=mods[curmod][1] do
		add_mod(mods[curmod][2])
		curmod = curmod+1
	end

	execute_mods()
	
	while curmessage<= #messages and GAMESTATE:GetSongBeat()>=messages[curmessage][1] do
		if messages[curmessage][3] and GAMESTATE:GetSongBeat()>=messages[curmessage][1]+5 then
			curmessage = curmessage+1;
		else
			MESSAGEMAN:Broadcast(messages[curmessage][2])
			curmessage = curmessage+1;
		end
	end
end


-- Kicks everything off
return Def.ActorFrame{

	OnCommand= function(self)
		Handler_init()
		self:SetUpdateFunction(Handler_update)
		local screen = SCREENMAN:GetTopScreen()
		if isEditMode() then 
			return;
		end
	end,


	Def.Quad{
		Name= "I may be sleeping, but I preserve the world.",
		InitCommand= cmd(visible,false),
		OnCommand= cmd(sleep,1000),


		-- Stop any effect command
        StopMessageCommand= function(self)
			if P1 then
				P1:smooth(2);
				P1:stopeffect();
			end
			if P2 then
				P2:smooth(2);
				P2:stopeffect();
			end
		end,
			

		-- Swaying
		WagPlayersMessageCommand = function(self)
			self:sleep(0);
			if P1 then
				P1:wag();
				P1:effectclock('bgm');
				P1:effectmagnitude(0,0,30);
				P1:effectperiod(4);
			end
			
			if P2 then			
				P2:wag();
				P2:effectclock('bgm');
				P2:effectmagnitude(0,0,-30);
				P2:effectperiod(4);
			end
		end,		
		
		
		FadeOutUIslowMessageCommand = function(self)
			for name,layer in pairs(screen:GetChildren()) do
				if not (name=="SongBackground" or name=="SongForeground" or name=="Underlay" or name=="PlayerP1" or name=="PlayerP2") then
					layer:smooth(4):diffusealpha(0)
				end
				if (name=="SongBackground") then
					layer:visible(true)
				end
				if name == "In" then layer:smooth(4):diffusealpha(0) end
				if name == 'Underlay' then
					layer:smooth(4):diffusealpha(0)
					for player_index=1,2 do
						local score = layer:GetChild('P' .. player_index .. 'Score')					
						if score then score:smooth(4):diffusealpha(0) end
					end
				end
			end
		end,
		
		
		FadeOutUIfastMessageCommand = function(self)
			for name,layer in pairs(screen:GetChildren()) do
				if not (name=="SongBackground" or name=="SongForeground" or name=="Underlay" or name=="PlayerP1" or name=="PlayerP2") then
					layer:smooth(0.5):diffusealpha(0)
				end
				if (name=="SongBackground") then
					layer:visible(true)
				end
				if name == "In" then layer:smooth(0.5):diffusealpha(0) end
				if name == 'Underlay' then
					layer:smooth(0.5):diffusealpha(0)
					for player_index=1,2 do
						local score = layer:GetChild('P' .. player_index .. 'Score')					
						if score then score:smooth(0.5):diffusealpha(0) end
					end
				end
			end
		end,
		
		
		FadeInUIMessageCommand = function(self)
			for name,layer in pairs(screen:GetChildren()) do
				if not (name=="SongBackground" or name=="SongForeground" or name=="Underlay" or name=="PlayerP1" or name=="PlayerP2") then
					layer:smooth(1.5):diffusealpha(1)
				end
				if (name=="SongBackground") then
					layer:visible(true)
				end
				if name == "In" then layer:smooth(1.5):diffusealpha(1) end
				if name == 'Underlay' then
					layer:smooth(1.5):diffusealpha(1)
					for player_index=1,2 do
						local score = layer:GetChild('P' .. player_index .. 'Score')					
						if score then score:smooth(1.5):diffusealpha(1) end
					end
				end
			end
		end,
		
		
		FadeInUIfastMessageCommand = function(self)
			for name,layer in pairs(screen:GetChildren()) do
				if not (name=="SongBackground" or name=="SongForeground" or name=="Underlay" or name=="PlayerP1" or name=="PlayerP2") then
					layer:smooth(0.5):diffusealpha(1)
				end
				if (name=="SongBackground") then
					layer:visible(true)
				end
				if name == "In" then layer:smooth(0.5):diffusealpha(1) end
				if name == 'Underlay' then
					layer:smooth(0.5):diffusealpha(1)
					for player_index=1,2 do
						local score = layer:GetChild('P' .. player_index .. 'Score')					
						if score then score:smooth(0.5):diffusealpha(1) end
					end
				end
			end
		end,


		VibrateOnMessageCommand = function(self)
			self:sleep(0);
			if P1 then
				P1:smooth(8):vibrate():effectmagnitude(30,30,0)
			end
			if P2 then
				P2:smooth(8):vibrate():effectmagnitude(-30,-30,0)
			end
		end,

		
		VibrateOffMessageCommand = function(self)
			self:sleep(0);
			if P1 then
				P1:smooth(2):vibrate():effectmagnitude(0,0,0)
			end
			if P2 then
				P2:smooth(2):vibrate():effectmagnitude(0,0,0)
			end
		end,
		
		
		VibrateOnLiteMessageCommand = function(self)
			self:sleep(0);
			if P1 then
				P1:smooth(1):vibrate():effectmagnitude(5,5,0)
			end
			if P2 then
				P2:smooth(1):vibrate():effectmagnitude(-5,-5,0)
			end
		end,
		
		RotateMessageCommand = function(self)
			self:sleep(0);
			if P1 then
				P1:smooth(1):zoom(-1)
			end
			if P2 then
				P2:smooth(1):zoom(-1)
			end
		end,

		DiffuseAlphaMessageCommand= function(self)
				self:diffusealpha(0);
				self:linear(0.8);
				self:diffusealpha(0.2);
		end,

	},


	Def.Quad{
		OnCommand=function(self)
			if (isEditMode()) then
				self:visible(false)
			end
			self:FullScreen():Center()
			self:diffuse(0,0,0,0.2)
		end,
	},
	Def.ActorProxy {
		OnCommand = function(self)
			self:queuecommand('Set')
		end,
		SetCommand = function(self)
			if P1Score and not isEditMode() then
				self:SetTarget(P1Score)
			end
		end
	},
	Def.ActorProxy {
		OnCommand = function(self)
			self:queuecommand('Set')
		end,
		SetCommand = function(self)
			if P2Score and not isEditMode() then
				self:SetTarget(P2Score)
			end
		end
	},
	Def.ActorProxy {
		OnCommand = function(self)
			self:queuecommand('Set')
		end,
		SetCommand = function(self)
			if P1 and not isEditMode() then
				self:SetTarget(P1)
			end
		end
	},
	Def.ActorProxy {
		OnCommand = function(self)
			self:queuecommand('Set')
		end,
		SetCommand = function(self)
			if P2 and not isEditMode() then
				self:SetTarget(P2)
			end
		end
	},
}