// --------------------------------------
// Lua_Bomb
// Bomb ability!
// --------------------------------------
local explosionradius = 100
local function bustThroughZ(startz, endz, 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(startz <= topheight and endz >= bottomheight)
			// 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 bombOnLine(mobj, line)
	local cx = mobj.x
	local cy = mobj.y
	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
	// --------------

	local radius = explosionradius*mobj.scale

	if not(abs(refpoint.x - cx) <= radius)
		or not(abs(refpoint.y - cy) <= 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)
			bustThroughZ(checkz-radius, checkz+radius, sector)
		end
		snum = $1 + 1
	end
end

rawset(_G, "K_Bomb", function(checkflags, destroy, late, player)
	if(checkflags)
		if(player.kvars.ablstate)
			return AF_NOFLOAT|AF_NODUCK|AF_NODROP
		end
		return 0
	end
	if(destroy)
		return
	end
	if(late)
		
		// Animation
		if(player.kvars.ablstate)
			if(player.mo.state >= S_PLAY_STND and player.mo.state <= S_PLAY_DASH)
				or(player.mo.state == S_PLAY_ROLL)
				or(player.mo.state >= S_PLAY_JUMP and player.mo.state <= S_PLAY_FALL)
				or(player.mo.state == S_PLAY_EDGE)
				or(player.mo.state >= S_KIRBY_BHOLD and player.mo.state <= S_KIRBY_BTHROW2)
				if not(P_IsObjectOnGround(player.mo))
					and not(player.mo.eflags & MFE_UNDERWATER)
					player.mo.state = S_KIRBY_BWALK7
				elseif(R_PointToDist2(player.cmomx, player.cmomy, player.mo.momx, player.mo.momy))
					if not(player.mo.state >= S_KIRBY_BWALK1 and player.mo.state <= S_KIRBY_BWALK8)
						player.mo.state = S_KIRBY_BWALK1
					end
					
					// Animation speed
					if(player.mo.eflags & MFE_UNDERWATER)
						and not(P_IsObjectOnGround(player.mo))
						if(player.mo.tics > 2)
							player.mo.tics = 2
						end
					else
						if(player.skidtime)	// Last time I touched this, it caused desyncs. Hopefully that doesn't happen again!
							player.mo.state = S_KIRBY_BWALK7
						else
							local speed = FixedDiv(R_PointToDist2(player.cmomx, player.cmomy, player.mo.momx, player.mo.momy), player.mo.scale)
							local maxtics = 4
							if(speed >= player.runspeed)	// Normally 30*FRACUNIT
								maxtics = 1
							elseif(speed >= 20*FRACUNIT)
								maxtics = 2
							elseif(speed >= 10*FRACUNIT)
								maxtics = 3
							end
							if(player.mo.tics > maxtics)
								player.mo.tics = maxtics
							end
						end
					end
				else
					player.mo.state = S_KIRBY_BHOLD
				end
			end
		elseif(player.mo.state == S_KIRBY_BHOLD)
			player.mo.state = S_PLAY_STND
		elseif(player.mo.state >= S_KIRBY_BWALK1 and player.mo.state <= S_KIRBY_BWALK8)
			player.mo.state = S_PLAY_WALK
		end
		
		return
	end
	
	if(player.mo.state == S_KIRBY_BTHROW2)
		and(player.mo.tics <= 1)
		if(P_IsObjectOnGround(player.mo))
			and not(player.mo.momx-player.cmomx or player.mo.momy-player.cmomy)
			player.mo.state = S_PLAY_STND
		else
			player.mo.state = S_PLAY_WALK
		end
	end
	
	if(player.cmd.buttons & BT_USE)
		and not(player.kvars.prevcmd & BT_USE)
		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)
		if(player.kvars.ablstate)
			player.kvars.ablstate = 0
			local bom = P_SPMAngle(player.mo, MT_KIRBYBOMB, player.mo.angle, 0)
			if(bom and bom.valid)
				if(player.mo.eflags & MFE_VERTICALFLIP)
					bom.eflags = $1|MFE_VERTICALFLIP	// Does this later?
					bom.flags2 = $1|MF2_OBJECTFLIP
				end
				bom.momz = FixedMul(mobjinfo[bom.type].speed/6, bom.scale)*P_MobjFlip(bom)
				bom.momx = $1 + player.mo.momx/2
				bom.momy = $1 + player.mo.momy/2
			end
			player.mo.state = S_KIRBY_BTHROW1
			player.drawangle = player.mo.angle
		else
			player.kvars.ablstate = 1
		end
	end
	
	if(player.kvars.ablstate)
		if(player.pflags & PF_SLIDING)
			or(player.powers[pw_carry])
			player.kvars.ablstate = 0
		else
			player.kvars.ablstate = $1 + 1
			local zoff = player.mo.height+(player.mo.scale*6)
			if(player.mo.eflags & MFE_VERTICALFLIP)
				zoff = FixedMul(-(mobjinfo[MT_DUMMYBOMB].height+(player.mo.scale*6)), player.mo.scale)
			end
			local bom = P_SpawnMobj(player.mo.x, player.mo.y, player.mo.z+zoff, MT_DUMMYBOMB)
			bom.scale = player.mo.scale
			bom.frame = leveltime&1
			if(player.mo.eflags & MFE_VERTICALFLIP)
				bom.eflags = $1|MFE_VERTICALFLIP
				bom.flags2 = $1|MF2_OBJECTFLIP
			end
			if(player.kvars.ablstate > TICRATE*3)
				player.kvars.ablstate = 0
				P_DamageMobj(player.mo, nil, nil, 1)	// Should be bomb
				P_RemoveMobj(bom)
				local bom2 = P_SpawnMobj(player.mo.x, player.mo.y, player.mo.z+zoff, MT_KIRBYBOMB)
				bom2.scale = player.mo.scale
				if(player.mo.eflags & MFE_VERTICALFLIP)
					bom2.eflags = $1|MFE_VERTICALFLIP
					bom2.flags2 = $1|MF2_OBJECTFLIP
				end
				P_KillMobj(bom2)
			end
		end
	end
end)

local function SpawnSparks(bomb)
	if(bomb.health)
		and(bomb.state >= S_DUMMYBOMB and bomb.state <= S_KIRBYBOMB)
		local spark = P_SpawnMobj(bomb.x, bomb.y, bomb.z, MT_KIRBYBOMBSPARK)
		spark.scale = bomb.scale
		if(bomb.eflags & MFE_VERTICALFLIP)
			spark.eflags = $1|MFE_VERTICALFLIP
			spark.flags2 = $1|MF2_OBJECTFLIP
		end
		if(leveltime & 1)
			spark.state = S_KIRBYBOMBSPARK2
		end
		spark.timer = 3
	else
		// Exploded
		local radius = explosionradius*bomb.scale
		searchBlockmap("lines", bombOnLine, bomb, bomb.x-radius, bomb.x+radius, bomb.y-radius, bomb.y+radius)
	end
end

addHook("MobjThinker", SpawnSparks, MT_DUMMYBOMB)
addHook("MobjThinker", SpawnSparks, MT_KIRBYBOMB)

addHook("MobjThinker", function(spark)
	if(spark.timer)
		spark.timer = $1 - 1
		if not(spark.timer)
			P_RemoveMobj(spark)
		elseif(spark.state >= S_KIRBYBOMBSPARK1 and spark.state <= S_KIRBYBOMBSPARK2)
			and(spark.timer <= 1)
			spark.state = $1 + 2
		end
	end
end, MT_KIRBYBOMBSPARK)
