-- Ember's Stuff --
local flightstyle
local FLIGHTSTYLE = "client/VoidyChars/ember.dat"
local configplayer
local function valid(mo)
	return mo and mo.valid
end
local flightmode = 0
local heightcap = 0
local flighttime = 0
local waterlogged = 0
local embercharge = 0
local drippedout = 0

local function FlightChange(player, arg)
	if player.mo and player.mo.valid
		if arg
			arg = arg:lower()
			if arg == "unlimited" 
			or arg == "0" 
			or arg == "-default"
				player.flightstyle = 0
				if io and player == consoleplayer
					local file = io.openlocal(FLIGHTSTYLE, "w+")
					file:write(player.flightstyle)
					file:close()
				end
			elseif arg == "leveled" 
			or arg == "1"
				player.flightstyle = 1
				if io and player == consoleplayer
					local file = io.openlocal(FLIGHTSTYLE, "w+")
					file:write(player.flightstyle)
					file:close()
				end
			elseif arg == "timed" 
			or arg == "2"
				player.flightstyle = 2
				if io and player == consoleplayer
					local file = io.openlocal(FLIGHTSTYLE, "w+")
					file:write(player.flightstyle)
					file:close()
				end
			elseif arg == "limited" 
			or arg == "3"
				player.flightstyle = 3
				if io and player == consoleplayer
					local file = io.openlocal(FLIGHTSTYLE, "w+")
					file:write(player.flightstyle)
					file:close()
				end
			else
				CONS_Printf(player, "Invalid input. Check options by just typing \130ember_flightstyle\128.")
			end
		else
			CONS_Printf(player, "ember_flightstyle Options:")
			CONS_Printf(player, "unlimited/0/-default: No height-cap and no timer. This is enabled by default and forced when Ember goes super.")
			CONS_Printf(player, "leveled/1: Ember can no longer ascend past a certain height based on where you started flying.")
			CONS_Printf(player, "timed/2: After a set amount of time, Ember can no longer fly and will slowly descend.")
			CONS_Printf(player, "limited/3: Effects of both leveled and timed. This will be forced in competitive gamemodes.")
		end
	else
		CONS_Printf(player, "This can only be done in a level.")
	end
end

local function EmberCheckAndCrumble(mo, sec)
  for fof in sec.ffloors()
    if not (fof.flags & FF_EXISTS) then continue end
    if not (fof.flags & FF_BUSTUP) then continue end
    if mo.z + mo.height < fof.bottomheight then continue end 
    if mo.z > fof.topheight then continue end
    EV_CrumbleChain(fof)
  end
end

local function EmberCrumbleCollide(mo, line)
	for _, sec in ipairs({line.frontsector, line.backsector})
		EmberCheckAndCrumble(mo, sec)
	end
end

local function ChargedStingerThink(chargedstinger)
	for player in players.iterate do
		local p = player.mo
		if chargedstinger and chargedstinger.valid and p and p.valid and p.skin == "ember"
			local fx = chargedstinger.x
			local fy = chargedstinger.y
			local fr = chargedstinger.radius
			searchBlockmap("objects", function(chargedstinger, found)
				if found.valid
					if found.flags & MF_SHOOTABLE
					and found.z - found.scale <= chargedstinger.z + chargedstinger.height
					and found.z + found.height + found.scale >= chargedstinger.z
						P_DamageMobj(found, chargedstinger, p, 2)
					end
				end
				if (found.valid and found.type == MT_EGGSHIELD) 
				and found.z - found.scale <= chargedstinger.z + chargedstinger.height
				and found.z + found.height + found.scale >= chargedstinger.z
					P_KillMobj(found, chargedstinger, p)
				end
				if (found.valid and found.type == MT_METALSONIC_BATTLE) 
				and found.state == found.info.spawnstate
				and not (found.flags2 & MF2_CLASSICPUSH) 
				and found.z - found.scale <= chargedstinger.z + chargedstinger.height
				and found.z + found.height + found.scale >= chargedstinger.z
					found.flags2 = $ | MF2_CLASSICPUSH
				end
			end, chargedstinger, fx-fr, fx+fr, fy-fr, fy+fr)
			EmberCheckAndCrumble(chargedstinger, chargedstinger.subsector.sector)
		end
	end
end

local function EmberKillSpikes(thing, tmthing)
	if thing and thing.valid and tmthing and tmthing.valid
	and (tmthing.type == MT_CHARGEDFS or tmthing.type == MT_WATERCFS) 
	and thing.z - thing.scale <= tmthing.z + tmthing.height + (tmthing and P_MobjFlip(tmthing) or tmthing.momz)
	and thing.z + thing.height + thing.scale >= tmthing.z + (tmthing and P_MobjFlip(tmthing) or tmthing.momz)
		P_KillMobj(thing, tmthing)
		return true
	end
end

local function EmberFakeNoClip(mo)
	P_SetOrigin(mo, mo.x + mo.momx, mo.y + mo.momy, mo.z + mo.momz)
    return
	true
end

local function EmberSuperTrans(player)
    if ((player.mo.state == S_PLAY_SUPER_TRANS1) 
	or (player.mo.state == S_PLAY_SUPER_TRANS2) 
	or (player.mo.state == S_PLAY_SUPER_TRANS3) 
	or (player.mo.state == S_PLAY_SUPER_TRANS4) 
	or (player.mo.state == S_PLAY_SUPER_TRANS5) 
	or (player.mo.state == S_PLAY_SUPER_TRANS6))
        return true
    else
        return false
    end
end

local function EmberSuperCheck(player)
    if not P_IsObjectOnGround(player.mo) and player.rings >= 50 and All7Emeralds(emeralds) and not player.powers[pw_super] and (player.playerstate == PST_LIVE)
    and (skins[player.mo.skin].flags & SF_SUPER)
    and not (player.cmd.buttons & BT_USE)
    and not (player.pflags & PF_THOKKED) and not (mapheaderinfo[gamemap].typeoflevel & TOL_NIGHTS) and not (player.pflags & PF_SHIELDABILITY) and (player.pflags & PF_JUMPED) and not EmberSuperTrans(player)
    and not EmberSuperTrans(player)
    and ((player.powers[pw_shield] == 0) or (player.powers[pw_shield] > 0))
    then
        return true
    else
        return false
    end
end

local function EmberSuper(player)
    player.pflags = $ & ~PF_JUMPED
    player.charflags = $1 | SF_SUPER
	P_DoSuperTransformation(player, false)
end

local function EmberVariableReset(player, health)
	if (player.embervars == nil)
		player.embervars = {}
	end
	if io and player == consoleplayer
		local file = io.openlocal(FLIGHTSTYLE)
		if file
			player.flightstyle = file:read("*n")
			file:close()
		else
			COM_BufInsertText(consoleplayer, "ember_flightstyle unlimited")
		end
	end
	player.flightmode = 0
	player.heightcap = 0
	player.flighttime = 0
	player.waterlogged = 0
	player.embercharge = 0
	player.drippedout = 0
end

addHook("MapLoad", function()
	for player in players.iterate
		EmberVariableReset(player, false)
	end
end)

COM_AddCommand("ember_flightstyle", function(player, arg)
	FlightChange(player, arg)
end)

addHook("JumpSpecial", function(player)
	if player.mo and player.mo.skin == "ember"
		if player.flighttime <= 600
			player.flightmode = $ + 1
			if player.waterlogged == 1 and not player.powers[pw_super]
				if not player.powers[pw_super] 
				and (player.flightstyle == 1 or player.flightstyle == 3 or gametype != 0) 
					if (player.mo.eflags & MFE_VERTICALFLIP)
						if player.mo.z <= player.heightcap
							P_SetObjectMomZ(player.mo, 0*FRACUNIT)
						else
							P_SetObjectMomZ(player.mo, 2*FRACUNIT)
						end
					else
						if player.mo.z >= player.heightcap
							P_SetObjectMomZ(player.mo, 0*FRACUNIT)
						else
							P_SetObjectMomZ(player.mo, 2*FRACUNIT)
						end
					end
				else
					P_SetObjectMomZ(player.mo, 2*FRACUNIT)
				end
			else
				if not player.powers[pw_super] 
				and (player.flightstyle == 1 or player.flightstyle == 3 or gametype != 0) 
					if (player.mo.eflags & MFE_VERTICALFLIP)
						if player.mo.z <= player.heightcap
							P_SetObjectMomZ(player.mo, 0*FRACUNIT)
						else
							P_SetObjectMomZ(player.mo, 5*FRACUNIT)
						end
					else
						if player.mo.z >= player.heightcap
							P_SetObjectMomZ(player.mo, 0*FRACUNIT)
						else
							P_SetObjectMomZ(player.mo, 5*FRACUNIT)
						end
					end
				else
					P_SetObjectMomZ(player.mo, 5*FRACUNIT)
				end
				player.pflags = $|PF_CANCARRY
			end
			S_StartSound(player.mo, sfx_buzz4)
			player.panim = PA_JUMP
			if player.flightmode == 1
				if not (player.mo.state == S_STARTFLIGHT)	
					player.mo.state = S_STARTFLIGHT
				end
				if not player.powers[pw_super] 
				and (player.flightstyle == 1 or player.flightstyle == 3 or gametype != 0)
					if (player.mo.eflags & MFE_VERTICALFLIP)
						player.heightcap = player.mo.z - 600*FRACUNIT
					else
						player.heightcap = player.mo.z + 600*FRACUNIT
					end
				end
			end
		end
		return false
	end
end)

addHook("PlayerThink", function(player)
	if player.mo and player.mo.skin == "ember"
		if (player.embervars == nil)
			EmberVariableReset(player, true)
		end
		if P_IsObjectOnGround(player.mo) 
		or player.powers[pw_justsprung] 
		or player.mo.state == S_PLAY_SUPER_TRANS1
			player.flightmode = 0
			player.flighttime = 0
		end
		if not player.powers[pw_super] 
		and (player.flightstyle == 2 or player.flightstyle == 3 or gametype != 0) 
		and player.flightmode >= 1 
		and not P_IsObjectOnGround(player.mo)
			player.flighttime = $ + 1
		end
		if not player.powers[pw_super] 
		and (player.flightstyle == 2 or player.flightstyle == 3 or gametype != 0) 
		and player.flighttime >= 600 
		and not P_PlayerInPain(player)
			P_SetObjectMomZ(player.mo, -5*FRACUNIT)
		end
		if player.mo.eflags & MFE_UNDERWATER
			player.waterlogged = 1
		else
			player.waterlogged = 0
		end
		if not (player.exiting or srb2p)
			if not (P_PlayerInPain(player) or (player.playerstate == PST_DEAD))
				if ((player.powers[pw_carry] == CR_NONE) and not (player.pflags & PF_SPINNING))
					if player.drippedout == 0
						if (player.cmd.buttons & BT_USE)
							player.spintapping = true
							player.spintapready = false
						elseif player.spintapping
							player.spintapready = true
							player.spintapping = false
						else
							player.spintapready = false
						end
						if player.spintapping
							if player.powers[pw_super]
								player.embercharge = 51
							end
							if not player.weapondelay and not (player.mo.state == S_PLAY_SPRING)
								if (player.powers[pw_shield] & SH_PROTECTFIRE)
									player.embercharge = $+2
								else
									player.embercharge = $+1
								end
							end
						end
						if player.spintapready and player.embercharge < 50
							player.embercharge = 0
						end
						if player.mo.state != S_PLAY_FIRE and player.mo.state != S_PLAY_FIRE_FINISH and player.mo.state != S_FLYSHOOT and player.mo.state != S_FLYSHOOT_FIN
							player.autoaim = P_LookForEnemies(player, false, true)
						end
						if (player.autoaim 
						and player.autoaim.valid 
						and player.autoaim.health)
							player.stingerangle = R_PointToAngle2(player.mo.x, player.mo.y, player.autoaim.x, player.autoaim.y)
							P_SpawnLockOn(player, player.autoaim, S_LOCKON1)
						end
						if player.spintapready and not player.weapondelay
							if player.autoaim and player.autoaim.valid
								if player.waterlogged == 0
									if player.embercharge >= 50
										player.chargestinger = P_SpawnMissile(player.mo, player.autoaim, MT_CHARGEDFS)
										S_StartSound(player.mo, sfx_s3ka0)
										player.embercharge = 0
									else
										P_SpawnMissile(player.mo, player.autoaim, MT_FLAMESTINGER)
										S_StartSound(player.mo, sfx_fire)
										player.charflags = $ & ~SF_SUPER 
									end
								else
									if player.embercharge >= 50
										player.chargestinger = P_SpawnMissile(player.mo, player.autoaim, MT_WATERCFS)
										S_StartSound(player.mo, sfx_s3ka0)
										player.embercharge = 0
									else
										P_SpawnMissile(player.mo, player.autoaim, MT_WATERFS)
										S_StartSound(player.mo, sfx_s3k47)
										player.charflags = $ & ~SF_SUPER
									end
									S_StartSound(player.mo, sfx_s3k47)
								end
								if player.powers[pw_super] 
								or (player.powers[pw_shield] & SH_PROTECTFIRE)
									player.weapondelay = TICRATE*1/2
								else
									player.weapondelay = TICRATE*1
								end
							else
								if player.waterlogged == 0
									if player.embercharge >= 50
										player.chargestinger = P_SPMAngle(player.mo, MT_CHARGEDFS, player.mo.angle)
										S_StartSound(player.mo, sfx_s3ka0)
										player.embercharge = 0
									else
										P_SPMAngle(player.mo, MT_FLAMESTINGER, player.mo.angle)
										S_StartSound(player.mo, sfx_fire)
									end
								else
									if player.embercharge >= 50
										player.chargestinger = P_SPMAngle(player.mo, MT_WATERCFS, player.mo.angle)
										S_StartSound(player.mo, sfx_s3ka0)
										player.embercharge = 0
									else
										P_SPMAngle(player.mo, MT_WATERFS, player.mo.angle)
										S_StartSound(player.mo, sfx_s3k47)
									end
								end
								if player.powers[pw_super]
									player.weapondelay = TICRATE*1/2
								else
									player.weapondelay = TICRATE*1
								end
							end
							if P_IsObjectOnGround(player.mo)
								if player.mo.state != S_PLAY_FIRE and player.mo.state != S_PLAY_FIRE_FINISH
									player.mo.state = S_PLAY_FIRE
									if player.autoaim
										player.drawangle = player.stingerangle
									end
								end
							else
								if player.mo.state != S_FLYSHOOT and player.mo.state != S_FLYSHOOT_FIN
									player.mo.state = S_FLYSHOOT
									if player.autoaim
										player.drawangle = player.stingerangle
									end
								end
							end
						end
					end
					if not (player.cmd.buttons & BT_CUSTOM1)
						player.cust1tapready = true
						player.cust1tapping = false
					elseif player.cust1tapready
						player.cust1tapping = true
						player.cust1tapready = false
					else
						player.cust1tapping = false
					end
					if player.cust1tapping 
					and not player.weapondelay 
					and P_IsObjectOnGround(player.mo)
						if player.drippedout == 0
							player.drippedout = 1
							player.mo.state = S_EMBER_DRIP
							player.weapondelay = TICRATE*1
							P_PlayJingleMusic(player, "EMDRIP", nil, true, JT_OTHER)
						elseif player.drippedout == 1
							player.drippedout = 0
							player.mo.state = S_PLAY_STND
							player.weapondelay = TICRATE*1
							P_RestoreMusic(player)
						end
					end
					if player.mo.state == S_EMBER_DRIP
						player.mo.momx = 0*FRACUNIT
						player.mo.momy = 0*FRACUNIT
						player.pflags = $|PF_JUMPSTASIS|PF_GODMODE
					else
						player.pflags = $ & ~PF_GODMODE
					end
				end
			end
		end
		if player.embercharge == 10
			S_StartSound(player.mo, sfx_s3kcal)
		end
		if player.embercharge == 0 or player.embercharge >= 50
			S_StopSoundByID(player.mo, sfx_s3kcal) 
		end
		if player.embercharge == 50
			S_StartSound(player.mo, sfx_kc48)
			P_Earthquake(player.mo, player.mo, 50*FRACUNIT)
		end
		if (All7Emeralds(emeralds)) and not player.embernotified
			player.embernotified = true
			S_StartSound(player.mo, sfx_s3k68)
		end
		if not G_EnoughPlayersFinished()
			if not player.powers[pw_super]
				player.charflags = $ & ~SF_SUPER
			end
			if (player.cmd.buttons & BT_CUSTOM1) and EmberSuperCheck(player)
				EmberSuper(player)
			end
			if P_PlayerTouchingSectorSpecial(player, 4, 6) and All7Emeralds(emeralds) and not player.powers[pw_super] then
				player.rings = 50
				EmberSuper(player)
			end
			if not player.powers[pw_super]
				S_StopSoundByID(player.mo, sfx_burnin)
			end
        end
	end
end)

addHook("ShouldDamage", function(mo, inf, src, dmg, dmgt)
	if (mo and (mo.skin == "ember") and mo.player)
		if ((inf and inf.valid) or (src and src.valid))
			if dmgt == DMG_FIRE
				return false
			end
			if ((inf.type == MT_DEMONFIRE) or (inf.type == MT_GREENFLAME))
				return false
			end
		end
	end
end, MT_PLAYER)

addHook("MobjLineCollide", EmberCrumbleCollide, MT_CHARGEDFS)
addHook("MobjThinker", ChargedStingerThink, MT_CHARGEDFS)
addHook("MobjMoveBlocked", EmberFakeNoClip, MT_CHARGEDFS)

addHook("MobjLineCollide", EmberCrumbleCollide, MT_WATERCFS)
addHook("MobjThinker", ChargedStingerThink, MT_WATERCFS)
addHook("MobjMoveBlocked", EmberFakeNoClip, MT_WATERCFS)

addHook("MobjCollide", EmberKillSpikes, MT_SPIKE)
addHook("MobjCollide", EmberKillSpikes, MT_WALLSPIKE)

addHook("MobjThinker", function(emberaura)
	for player in players.iterate do
		local p = player.mo
		if emberaura and emberaura.valid and p and p.valid and p.skin == "ember"
			if player.embercharge == 10
				emberaura.state = S_CHARGEAURA1
			end
			if p.state == S_PLAY_SUPER_TRANS1
				emberaura.state = S_CHARGEAURA3
				S_StartSound(p, sfx_burnin)
			end
			if (player.embercharge == 0
			or player.embercharge > 50)
			and not player.powers[pw_super]
				emberaura.state = S_INVISIBLE
			end
			if P_IsObjectOnGround(p) 
			and emberaura.state != S_INVISIBLE
				EmberCheckAndCrumble(emberaura, emberaura.subsector.sector)
			end
		end
	end
end, MT_EMBERCHARGEAURA)

addHook("MobjLineCollide", EmberCrumbleCollide, MT_EMBERCHARGEAURA)

hud.add(function(v, player)
	if player.mo == nil or player.mo.skin ~= "ember" or srb2p
		return
	end
	local emerdudes2 = v.cachePatch('EHUDA0')
	if (All7Emeralds(emeralds))
		if (leveltime > 0) and (leveltime < 150)
			v.draw(70, 60, emerdudes2, V_PERPLAYER)
			v.drawString(5, 150, "Ember can now transform into Blazing Ember", V_PERPLAYER)
			v.drawString(50, 160, "by pressing Custom 1 while flying!", V_PERPLAYER)
		end
	end
end)