-- Ember's Stuff --
local FLIGHTSTYLE = "client/VoidyChars/ember.dat"

local function FlightChange(player, arg)
	if player.mo and player.mo.valid
		if player.mo.skin == "ember"
			if arg
				arg = arg:lower()
				if arg == "0" 
				or arg == "unlimited"
					player.flightstyle = 0
					if io and player == consoleplayer
						local file = io.openlocal(FLIGHTSTYLE, "w+")
						file:write(player.flightstyle)
						file:close()
					end
				elseif arg == "1" 
				or arg == "capped"
					player.flightstyle = 1
					if io and player == consoleplayer
						local file = io.openlocal(FLIGHTSTYLE, "w+")
						file:write(player.flightstyle)
						file:close()
					end
				elseif arg == "2" 
				or arg == "timed"
					player.flightstyle = 2
					if io and player == consoleplayer
						local file = io.openlocal(FLIGHTSTYLE, "w+")
						file:write(player.flightstyle)
						file:close()
					end
				elseif arg == "3" 
				or arg == "limited"
					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.")
				end
			else
				CONS_Printf(player, "Sets how Ember's flight is limited. Options are:")
				CONS_Printf(player, "0 / unlimited: No height-cap and no timer. This is enabled by default and forced when Ember goes super.")
				CONS_Printf(player, "1 / capped: Ember can no longer ascend past a certain height based on where you started flying.")
				CONS_Printf(player, "2 / timed: After a set amount of time, Ember can no longer fly and will slowly descend.")
				CONS_Printf(player, "3 / limited: Effects of both Capped and Timed. This will be forced in competitive gamemodes.")
			end
		else
			CONS_Printf(player, "You must be Ember to use this command.")
		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(mo)
	local src = mo.target
	if mo and mo.valid and src and src.valid
		local fx = mo.x
		local fy = mo.y
		local fr = mo.radius
		searchBlockmap("objects", function(mo, found)
			if found.valid
				if (found.flags & MF_SHOOTABLE and found != src)
				and found.z - found.scale <= mo.z + mo.height
				and found.z + found.height + found.scale >= mo.z
					P_DamageMobj(found, mo, src, 2)
				end
			end
			if (found.valid and found.type == MT_EGGSHIELD) 
			and found.z - found.scale <= mo.z + mo.height
			and found.z + found.height + found.scale >= mo.z
				P_KillMobj(found, mo, src)
			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 <= mo.z + mo.height
			and found.z + found.height + found.scale >= mo.z
				found.flags2 = $ | MF2_CLASSICPUSH
			end
		end, mo, fx-fr, fx+fr, fy-fr, fy+fr)
		EmberCheckAndCrumble(mo, mo.subsector.sector)
	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 = 100
	player.waterlogged = 0
	player.superfly = false
	player.embercharge = 0
	player.firing = 0
	player.emberdie = false
	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 PSO return end
		if player.flighttime > 0
			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
			end
			if player.powers[pw_super]
				if not player.superfly
					S_StartSound(player.mo, sfx_s3k47)
					player.superfly = true
				end
			else
				S_StartSound(player.mo, sfx_buzz4)
			end
			if player.flightmode == 1
				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 - 500*FRACUNIT
					else
						player.heightcap = player.mo.z + 500*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 player.followmobj and player.followmobj.valid
			player.followmobj.target = player.mo
		end
		if not (player.cmd.buttons & BT_JUMP)
			player.superfly = false
		end
		if player.flightmode >= 1
			player.pflags = $|PF_CANCARRY
			if player.flightmode >= 3 
			and ((player.powers[pw_carry] == CR_NONE) and not (player.pflags & PF_SPINNING)) 
			and not player.powers[pw_justsprung] 
			and not (P_PlayerInPain(player) or (player.playerstate == PST_DEAD)) 
			and not (player.mo.state == S_PLAY_GASP) 
			and not EmberSuperTrans(player) 
			and player.firing == 0
				if player.flighttime > 0
					if player.speed < player.runspeed
						player.mo.state = S_PLAY_WALK
					elseif player.speed >= player.runspeed
						player.mo.state = S_PLAY_RUN
					end
				else
					player.mo.state = S_PLAY_FALL
				end
			end
		end
		if not player.powers[pw_super] 
		and (player.flightstyle == 2 or player.flightstyle == 3 or gametype != 0)
			if player.flightmode >= 1 
			and not (P_IsObjectOnGround(player.mo) or (player.playerstate == PST_DEAD))
				if leveltime%7 == 0
					player.flighttime = $ - 1
				end
			end
			if player.flighttime <= 0 
			and not (P_PlayerInPain(player) or (player.playerstate == PST_DEAD))
				P_SetObjectMomZ(player.mo, -10*FRACUNIT)
			end
		end
		if P_IsObjectOnGround(player.mo) or (player.mo.eflags & MFE_GOOWATER)
			player.flightmode = 0
			if player.flighttime < 100
				player.flighttime = $ + 1
			end
		end
		if player.powers[pw_justsprung] 
		or (player.powers[pw_carry] != CR_NONE) 
		or player.mo.state == S_PLAY_GASP 
		or player.mo.state == S_PLAY_SUPER_TRANS1
			player.flightmode = 0
			player.flighttime = 100
		end
		if player.mo.eflags & MFE_UNDERWATER
			player.waterlogged = 1
		else
			player.waterlogged = 0
		end
		if not (player.exiting or srb2p or PSO)
			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.firing == 0
							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)
										player.chargestinger.target = player.mo
										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)
										player.chargestinger.target = player.mo
										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
								player.weapondelay = TICRATE*1/2
							else
								if player.waterlogged == 0
									if player.embercharge >= 50
										player.chargestinger = P_SPMAngle(player.mo, MT_CHARGEDFS, player.mo.angle)
										player.chargestinger.target = player.mo
										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)
										player.chargestinger.target = player.mo
										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
								player.weapondelay = TICRATE*1/2
							end
							if P_IsObjectOnGround(player.mo)
								if player.speed == 0
									player.mo.state = S_PLAY_FIRE
								else
									if player.speed < player.runspeed
										player.mo.state = S_WALKSHOOT
									elseif player.speed >= player.runspeed
										player.mo.state = S_RUNSHOOT
									end
								end
							else
								if player.speed < player.runspeed
									player.mo.state = S_WALKSHOOT
								elseif player.speed >= player.runspeed
									player.mo.state = S_RUNSHOOT
								end
							end
							if player.autoaim
								player.drawangle = player.stingerangle
							end
						end
					end
					if not (player.cmd.buttons & BT_TOSSFLAG)
						player.flagtapready = true
						player.flagtapping = false
					elseif player.flagtapready
						player.flagtapping = true
						player.flagtapready = false
					else
						player.flagtapping = false
					end
					if player.flagtapping 
					and not player.weapondelay 
					and P_IsObjectOnGround(player.mo) 
					and not player.powers[pw_super]
						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.mo.state == S_PLAY_FIRE 
		or player.mo.state == S_PLAY_FIRE_FINISH 
		or player.mo.state == S_WALKSHOOT 
		or player.mo.state == S_WALKSHOOT_FIN 
		or player.mo.state == S_RUNSHOOT 
		or player.mo.state == S_RUNSHOOT_FIN
			player.firing = 1
		else
			player.firing = 0
		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 player.mo.state == S_PLAY_DEAD 
		or player.mo.state == S_PLAY_DRWN
			if (not (player.mo.eflags & MFE_VERTICALFLIP) and (player.mo.momz <= 0*FRACUNIT)) 
			or ((player.mo.eflags & MFE_VERTICALFLIP) and (player.mo.momz >= 0*FRACUNIT))
				P_SetObjectMomZ(player.mo, 0*FRACUNIT)
				player.mo.flags2 = $|MF2_DONTDRAW
				if not player.emberdie
					S_StartSound(player.mo, sfx_s3ka8)
					player.dieflash = P_SpawnMobj(player.mo.x, player.mo.y, player.mo.z, MT_GHOST)
					if (player.mo.eflags & MFE_VERTICALFLIP)
						player.dieflash.eflags = $1|MFE_VERTICALFLIP
						player.dieflash.flags2 = $1|MF2_OBJECTFLIP
					end
					player.dieflash.skin = "ember"
					player.dieflash.state = S_EMBER_DIE1
					player.emberdie = true
				end
			end
		end
		if player.playerstate == PST_REBORN and player.emberdie == true
			player.emberdie = false
		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) or mapheaderinfo[gamemap].lvlttl == "Dimension Warp") 
			and All7Emeralds(emeralds) and not player.powers[pw_super] then
				player.rings = 50
				EmberSuper(player)
			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(mo)
	local src = mo.target
	if mo and mo.valid and src and src.valid
		if src.player.embercharge == 10
			mo.state = S_CHARGEAURA1
		end
		if src.state == S_PLAY_SUPER_TRANS1
			mo.state = S_CHARGEAURA3
			mo.auraactive = true
		end
		if (src.player.embercharge == 0
		or src.player.embercharge > 50)
		and not src.player.powers[pw_super]
			mo.state = S_INVISIBLE
			mo.auraactive = false
		end
		if P_IsObjectOnGround(src) 
		and mo.state != S_INVISIBLE
			EmberCheckAndCrumble(mo, mo.subsector.sector)
		end
		if mo.auraactive
			if (leveltime%70 == 0)
				S_StartSound(mo, sfx_burnin)
			end
		else
			S_StopSound(mo)
		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 huddisplay = v.cachePatch("EMBHUD1")
	local wingicon = v.cachePatch("EMBHUD2")
	local iconflash = v.cachePatch("EMBHUD3")
	local superflight = v.cachePatch("EMBHUD4")
	local hudbg = v.cachePatch("EMBHUD5")
	if leveltime >= 50 and (player.flightstyle == 2 or player.flightstyle == 3 or gametype != 0)
		v.draw(150, 135, hudbg, V_SNAPTORIGHT|V_SNAPTOBOTTOM|V_PERPLAYER, v.getColormap(nil,SKINCOLOR_EVENTIDE))
		v.drawFill(191, 165, 100, 8, 31|V_SNAPTORIGHT|V_SNAPTOBOTTOM|V_PERPLAYER)
		v.drawFill(191, 165, player.flighttime, 8, 113|V_SNAPTORIGHT|V_SNAPTOBOTTOM|V_PERPLAYER)
		v.draw(130, 135, huddisplay, V_SNAPTORIGHT|V_SNAPTOBOTTOM|V_PERPLAYER, nil)
		if player.powers[pw_super]
			v.draw(130, 135, superflight, V_SNAPTORIGHT|V_SNAPTOBOTTOM|V_PERPLAYER)
		else
			v.draw(130, 135, wingicon, V_SNAPTORIGHT|V_SNAPTOBOTTOM|V_PERPLAYER)
		end
		if player.mo.state == S_PLAY_SUPER_TRANS1 
		or player.mo.state == S_PLAY_SUPER_TRANS2 
		or player.mo.state == S_PLAY_SUPER_TRANS3
			v.draw(130, 135, iconflash, V_SNAPTORIGHT|V_SNAPTOBOTTOM|V_PERPLAYER)
		end
		if player.mo.state == S_PLAY_SUPER_TRANS4
			v.draw(130, 135, iconflash, V_SNAPTORIGHT|V_SNAPTOBOTTOM|V_PERPLAYER|V_40TRANS)
		end
		if player.mo.state == S_PLAY_SUPER_TRANS5
			v.draw(130, 135, iconflash, V_SNAPTORIGHT|V_SNAPTOBOTTOM|V_PERPLAYER|V_80TRANS)
		end
	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)