-- Mic Drop

-- ABOUT: FL Chan's secondary ability.

local mic = nil
local shockwave = nil
local altshckwve = nil

if srb2p return end

addHook("ThinkFrame", function()
	for player in players.iterate do
		if player.mo.skin ~= "flchan" then
			continue
		end
	
		if not player.exiting then // If the player isn't exiting the level...
			if not (P_PlayerInPain(player) or (player.playerstate == PST_DEAD)) then // Then, if the player isn't in pain or dead...
				if ((player.powers[pw_carry] == CR_NONE) and not (player.pflags == PF_SPINNING)) then // Then if the player isn't being carried or spinning...
					if not (player.mo.state == S_PLAY_FLOAT 
					or player.mo.state == S_PLAY_FLOAT_RUN 
					or player.mo.state == S_PLAY_DASH 
					or player.powers[pw_tailsfly]) then // Then if the player isn't Slow Falling, not in their Dash Mode animation, or not swimming...
						if not (player.cmd.buttons & BT_USE) then // Then if spin isn't pressed...
							player.spintapready = true -- The following makes it act as a singular button press
							player.spintapping = false
						elseif player.spintapready then
							player.spintapping = true
							player.spintapready = false
						else
							player.spintapping = false
						end
						
						if player.spintapping and not player.weapondelay then // If the above function is true while the cooldown isn't active...
							if not ((player.mo.boomboxspawned == 1) or (player.mo.flchanhugging == 1)) then // Then if there's no Kaboom Box or if the player isn't hugging someone...
								mic = P_SpawnMobj(player.mo.x, player.mo.y, player.mo.z + (player.mo.height/2), MT_DROPPEDMIC) -- Spawns the mic
								S_StartSound(mic, sfx_brakrl) -- Plays a launching sound
								mic.target = player.mo -- Mics will not hurt the user
								if not P_IsObjectOnGround(player.mo) then // If player isn't on the ground...
									player.mo.state = S_MICDROP_MIDAIR -- Plays the midair animation
									if player.mo.flchanupgraded == 1
										player.mo.momz = 20*FRACUNIT -- Boosts the player 20 fracunits upwards
										player.weapondelay = TICRATE*3 -- Even longer cooldown so that you won't abuse it
									else
										player.mo.momz = 10*FRACUNIT -- Boosts the player 10 fracunits upwards
										player.weapondelay = TICRATE*2 -- Longer cooldown so that you won't abuse it
									end
								else // Otherwise...
									player.mo.state = S_MICDROP -- Plays the grounded animation
									player.weapondelay = TICRATE*1 -- Quick cooldown for quick damage
								end
								if (player.mo.eflags & MFE_VERTICALFLIP) then // The player is upside down...
									if not P_IsObjectOnGround(player.mo) then
										if player.mo.flchanupgraded == 1
											player.mo.momz = -20*FRACUNIT
										else
											player.mo.momz = -10*FRACUNIT
										end
									end
								end
							end
						end
					end
				end
			end
		end
		
		-- NOTE: Taken from Padoru (who is reusable), this is supposed to be more for Metal Sonic's boss fight, but it'll only work exactly as written.
		if not player.mo.eferuchan then
			local eferuuchan = {
				screwthisboss = false
			}
			player.mo.eferuchan = eferuuchan
		end
		local fx = player.mo.x
		local fy = player.mo.y
		local br = 3000*FRACUNIT
		searchBlockmap("objects", function(mo, found)
			if found.flags & MF_BOSS
				mo.eferuchan.screwthisboss = (not not found.health)
			end
		end, player.mo, fx-br, fx+br, fy-br, fy+br)
		
		if (player.mo.state == S_MICDROP or player.mo.state == S_MICDROP_FIN) then // If the grounded animation is playing...
			player.pflags = $|PF_FULLSTASIS -- Stabilizes the player
		end
	end
end)

-- NOTE: Mic Drop internal functions
addHook("MobjThinker", function(mic)
	-- Defines the player
	local p = players[0]
	local mo = p.mo
	-- Dropping
	if (mo.eflags & MFE_VERTICALFLIP)
		mic.eflags = $1|MFE_VERTICALFLIP -- Considers it flipped
		mic.flags2 = $1|MF2_OBJECTFLIP -- Visually flips it upside down
		mic.momz = 30*FRACUNIT -- Drops the opposite direction
	else
		mic.momz = -30*FRACUNIT -- Drops it really quick
	end
	-- Shockwaves
	if mic.valid and mic.state == S_XPLD1 // If the mic explodes...
		if mo.flchanupgraded
			P_Earthquake(mic, mo, 400*FRACUNIT) -- Attacks in a 400 fracunit radius
			shockwave = P_SpawnMobj(mic.x, mic.y, mic.z, MT_SHOCKWAVE2) -- Spawns a bigger shockwave mobj
			if ((mo.eferuchan.screwthisboss)
			or  (CBW_Battle.Gametypes.SuddenDeath) 
			or (CBW_Battle.Gametypes.Battle) 
			or (CBW_Battle.Gametypes.CP) 
			or (CBW_Battle.Gametypes.Arena) 
			or (CBW_Battle.Gametypes.Diamond)) // Then if the player is around a boss or in a BattleMod gametype...
				altshckwve = P_SpawnMobj(mic.x, mic.y, mic.z, MT_ALTSHCKWVE2) -- Spawns an alternate version of the bigger shockwave with the MF_MISSILE flag
			end
			shockwave.target = mo -- Shockwaves will not hurt the user
			altshckwve.target = mo
		else
			P_Earthquake(mic, mo, 200*FRACUNIT) -- Attacks in a 200 fracunit radius
			shockwave = P_SpawnMobj(mic.x, mic.y, mic.z, MT_SHOCKWAVE1) -- Spawns a shockwave mobj
			if ((mo.eferuchan.screwthisboss) 
			or (CBW_Battle.Gametypes.SuddenDeath) 
			or (CBW_Battle.Gametypes.Battle) 
			or (CBW_Battle.Gametypes.CP) 
			or (CBW_Battle.Gametypes.Arena) 
			or (CBW_Battle.Gametypes.Diamond))
				altshckwve = P_SpawnMobj(mic.x, mic.y, mic.z, MT_ALTSHCKWVE1) -- Spawns an alternate version of the shockwave with the MF_MISSILE flag
			end
			shockwave.target = mo
			altshckwve.target = mo
		end
	end
	-- Floor breaking
	-- NOTE: This part of the code was taken from SSN Mighty since he's reusable.
	if P_IsObjectOnGround(mic) // If the mic is on the ground...
		for x = mic.x, mic.x + mic.radius, mic.radius -- The following will set up variables for floor breaking
			for y = mic.y, mic.y + mic.radius, mic.radius
				local ss = R_PointInSubsector(x,y)
				for fof in ss.sector.ffloors()
					if (fof.flags & FF_BUSTUP) and (fof.flags & FF_EXISTS) // If a breakable floor exists where the mic drops...
						EV_CrumbleChain(ss.sector, fof) -- Breaks that floor
					end
				end
			end
		end
	end
end, MT_DROPPEDMIC)

-- NOTE: Because of the midair functionality, she can't use shield actives (it's also why she can't go super by normal means). Although, she herself is practically two shields in one.
addHook("ShieldSpecial", function(player)
	if player.mo.skin == "flchan"
		if player.powers[pw_shield] == SH_FLAMEAURA
		or player.powers[pw_shield] == SH_BUBBLEWRAP
			return false
		else
			return true
		end
	end
end)

-- NOTE: The following allows the shockwave mobj to destroy spikes.
local killspikes = function(thing, tmthing)
	if not (thing and thing.valid and tmthing and tmthing.valid) return end
	if tmthing == shockwave then
		P_KillMobj(thing, tmthing)
		return true
	end
end

addHook("MobjCollide", function(thing, tmthing) killspikes(thing, tmthing) end, MT_SPIKE)
addHook("MobjCollide", function(thing, tmthing) killspikes(thing, tmthing) end, MT_WALLSPIKE)

-- NOTE: Fail message support for Henry Stickmin.
addHook("MobjDeath", function(mo, inflictor, source, damagetype)
	if mo.skin == "henry"
	and mo.valid and not (mo.player.powers[pw_carry] == CR_NIGHTSMODE)
		local player = mo.player
		if inflictor and inflictor.type == MT_DROPPEDMIC
			player.failwhy = "YOU'LL NEVER SEE IT COMING"
			player.failwhy2 = nil
			player.failwhy3 = nil
			player.failwhy4 = nil
			player.failwhy5 = nil
			player.failwhy6 = nil
			player.failwhy7 = nil
			player.failwhy8 = nil
			player.failwhy9 = nil
			player.failwhy10 = nil
		end
		if inflictor and inflictor == shockwave
			player.failwhy = "DR-DR-DROP THE BASS"
			player.failwhy2 = nil
			player.failwhy3 = nil
			player.failwhy4 = nil
			player.failwhy5 = nil
			player.failwhy6 = nil
			player.failwhy7 = nil
			player.failwhy8 = nil
			player.failwhy9 = nil
			player.failwhy10 = nil
		end
	end
end, MT_PLAYER)