// --------------------------------------
// Lua_FireBall
// FireBall ability!
// --------------------------------------
local function RandomOff(num)
	return (P_RandomByte()%num)-(num/2)
end
local function SpawnSparkles(player, spriteheight)
	local zoff = 2*player.mo.scale*P_MobjFlip(player.mo)
	local sparkle = P_SpawnMobj(player.mo.x+(RandomOff(30)*player.mo.scale), player.mo.y+(RandomOff(30)*player.mo.scale), player.mo.z+(player.mo.height/2)+(RandomOff(spriteheight)*player.mo.scale)+zoff, MT_PUMATRAIL)
	sparkle.scale = player.mo.scale
	if(player.mo.eflags & MFE_VERTICALFLIP)
		sparkle.eflags = $1|MFE_VERTICALFLIP
	end
end

local function bustAtZ(checkz, sector)
	for rover in sector.ffloors()
		if not(rover.flags & FF_EXISTS)
			or not(rover.flags & FF_BUSTUP)
			continue
		end
		
		local topheight = rover.topheight
		local bottomheight = rover.bottomheight
		if(rover.t_slope) topheight = P_GetZAt(rover.t_slope, mobj.x, mobj.y) end
		if(rover.b_slope) bottomheight = P_GetZAt(rover.b_slope, mobj.x, mobj.y) end
		
		if(topheight >= checkz and bottomheight <= checkz)
			// In bustable; break it!
			EV_CrumbleChain(sector, rover)		// Bust it!
			// Run a linedef executor??
			if(rover.master.flags & ML_EFFECT5)
				P_LinedefExecute(P_AproxDistance(rover.master.dx, rover.master.dy)>>FRACBITS, mobj, sector)
			end
		end
	end
end

local function fireOnLine(mobj, line)
	local cx = mobj.x+mobj.momx
	local cy = mobj.y+mobj.momy
	local pointx, pointy = P_ClosestPointOnLine(cx, cy, line)
	// SRB2 doesn't account for this, fun.
	// --------------
	// Check if we're past the line!
	local refpoint = nil
	
	local rx = cx-line.v1.x
	local ry = cy-line.v1.y
	local px = line.v1.x-line.v2.x
	local py = line.v1.y-line.v2.y
	local mag = R_PointToDist2(0, 0, px, py)
	px = FixedDiv($1, mag)
	py = FixedDiv($1, mag)
	if(FixedMul(px, rx)+FixedMul(py, ry) > 0)
		refpoint = line.v1
	else
		rx = cx-line.v2.x
		ry = cy-line.v2.y
		px = line.v2.x-line.v1.x
		py = line.v2.y-line.v1.y
		mag = R_PointToDist2(0, 0, px, py)
		px = FixedDiv($1, mag)
		py = FixedDiv($1, mag)
		if(FixedMul(px, rx)+FixedMul(py, ry) > 0)
			refpoint = line.v2
		end
	end
	
	if(refpoint == nil)
		refpoint = {}
		refpoint.x = pointx
		refpoint.y = pointy
	end
	// --------------
	
	if not(abs(refpoint.x - cx) <= mobj.radius)
		or not(abs(refpoint.y - cy) <= mobj.radius)
		return
	end
	
	local checkz = mobj.z+(mobj.height/2)
	local snum = 0
	while(snum < 2)
		local sector = line.frontsector
		if(snum)
			sector = line.backsector
		end
		if(sector and sector.valid)
			and(line.backside or not snum)
			bustAtZ(checkz, sector)
		end
		snum = $1 + 1
	end
end

rawset(_G, "K_FireBall", function(checkflags, destroy, late, player)
	if(checkflags)
		if(player.kvars.ablstate)
			or(player.kvars.ablvar3)
			return AF_NOFLOAT|AF_NODUCK|AF_NOJUMP|AF_NOSWIM|AF_NODROP
		end
		return 0
	end
	if(destroy)
		return
	end
	if(late)
		return
	end
	
	if(player.cmd.buttons & BT_USE)
		and not(player.kvars.prevcmd & BT_USE)
		and not(player.kvars.ablstate)
		and not(player.kvars.ducking)
		and not(player.kvars.floating)
		and not(player.pflags & PF_SLIDING)
		and not(player.powers[pw_carry] or player.kvars.prevcarry)
		and not(player.exiting)
		and not(player.pflags & PF_STASIS)
		and not(player.powers[pw_nocontrol])
		and not(player.kvars.industdevil)
		and not(player.kvars.inmud)
		and not(player.kvars.ablvar3)
		player.kvars.ablstate = 1
		player.kvars.ablvar1 = player.mo.angle
	end
	
	if(player.kvars.ablstate)
		// Check blockmap to bust walls
		local sx = player.mo.x+player.mo.momx
		local sy = player.mo.y+player.mo.momy
		searchBlockmap("lines", fireOnLine, player.mo, sx-player.mo.radius, sx+player.mo.radius, sy-player.mo.radius, sy+player.mo.radius)
		
		// Check for walls
		local wallchecker = P_SpawnMobj(player.mo.x, player.mo.y, player.mo.z, MT_GARGOYLE)
		wallchecker.radius = player.mo.radius
		wallchecker.height = player.mo.height
		wallchecker.flags = ($1|MF_NOCLIPTHING) & !(MF_SOLID|MF_PUSHABLE)
		local hit = P_TryMove(wallchecker, player.mo.x+player.mo.momx, player.mo.y+player.mo.momy, true)
		P_RemoveMobj(wallchecker)
		
		if not(hit)
			player.pflags = ($1|PF_NOJUMPDAMAGE) & !PF_JUMPED
			player.mo.state = S_KIRBY_WHEELTRANS2
			P_TeleportMove(player.mo, player.mo.x, player.mo.y, player.mo.z+P_MobjFlip(player.mo))
			player.mo.momz = 3*player.mo.scale*P_MobjFlip(player.mo)
			P_InstaThrust(player.mo, player.drawangle, -5*player.mo.scale)
			player.mo.momx = $1 + player.cmomx
			player.mo.momy = $1 + player.cmomy
			player.kvars.ablstate = 0
			S_StartSound(player.mo, sfx_stone)
			player.kvars.ablvar3 = TICRATE/2
		elseif(player.kvars.ablstate > TICRATE)
			or(player.kvars.inmud)
			player.pflags = ($1|PF_NOJUMPDAMAGE) & !PF_JUMPED
			player.mo.state = S_PLAY_WALK
			player.kvars.ablstate = 0
			player.mo.momx = $1 - player.cmomx
			player.mo.momy = $1 - player.cmomy
			player.mo.momx = $1 / 2
			player.mo.momy = $1 / 2
			player.mo.momx = $1 + player.cmomx
			player.mo.momy = $1 + player.cmomy
		else
			player.pflags = ($1|PF_JUMPED) & !PF_NOJUMPDAMAGE
			if(player.kvars.ablstate < TICRATE/5)
				player.mo.state = S_KIRBY_FIRE1
				player.mo.momx = player.cmomx
				player.mo.momy = player.cmomy
				player.mo.momz = 0
			else
				if(player.kvars.ablstate & 1)
					local fb = P_SpawnMobj(player.mo.x, player.mo.y, player.mo.z+(player.mo.height/2)-(5*player.mo.scale*P_MobjFlip(player.mo)), MT_FIREBALLTRAIL)
					if(player.mo.eflags & MFE_VERTICALFLIP)
						fb.eflags = $1|MFE_VERTICALFLIP
						K_FlipMobjZ(fb, player.mo)
					end
				end
				SpawnSparkles(player, 30)
				if not(player.mo.state == S_KIRBY_FIRE2)
					player.mo.state = S_KIRBY_FIRE2
				end
				if(player.kvars.ablstate%3 == 0)
					S_StartSound(player.mo, sfx_fire)
				end
				P_InstaThrust(player.mo, player.kvars.ablvar1, 35*player.mo.scale)
				player.mo.momx = $1 + player.cmomx
				player.mo.momy = $1 + player.cmomy
				if not(P_IsObjectOnGround(player.mo))
					player.mo.momz = $1 - (P_GetMobjGravity(player.mo)/2)
				end
			end
			
			if not(player.powers[pw_nocontrol] > 2)
				player.powers[pw_nocontrol] = 2
			end
			player.drawangle = player.kvars.ablvar1
			
			player.kvars.ablstate = $1 + 1
		end
	end
	
	// Cooldown
	if(player.kvars.ablvar3)
		if(P_IsObjectOnGround(player.mo))
			player.kvars.ablvar3 = 0
		else
			player.mo.state = S_KIRBY_WHEELTRANS2
			player.kvars.ablvar3 = $1 - 1
			if not(player.kvars.ablvar3)
				player.mo.state = S_PLAY_FALL
			elseif not(player.powers[pw_justsprung])
				player.powers[pw_justsprung] = 1
			end
		end
	end
end)
