-- Flame
-- A Library of functions.

-- HomingAttackXY: A copy of P_HomingAttack from the source.
-- However, Z Momentum is not taken into account.
--
-- Flame
--
-- source (mobj_t)			- source mobj
-- enemy (mobj_t)		- target mobj
rawset(_G, "L_HomingAttackXY", function(source, enemy)
	local zdist, dist
	local ns = 0
	
	if not enemy or not enemy.valid then return false end
	
	if (enemy.flags & MF_NOCLIPTHING)
	or (enemy.health <= 0)
	or (enemy.flags2 & MF2_FRET) then
		return false
	end
	
	-- Set Angle
	--source.angle = R_PointToAngle2(source.x, source.y, enemy.x, enemy.y)
	-- Set Slope
	zdist = (P_MobjFlip(source) == -1) and ((enemy.z + enemy.height) - (source.z + source.height)) or (enemy.z - source.z)
	dist = FixedHypot(FixedHypot(enemy.x - source.x, enemy.y - source.y), zdist)
	dist = max($, 1)
	
	if (source.type == MT_PLAYER) -- Specific dummy check
		ns = FixedMul(35*FRACUNIT, source.scale)
	else -- Everything else
		if (source.threshold == 32000) then
			ns = FixedMul(source.info.speed/2, source.scale)
		else
			ns = FixedMul(source.info.speed, source.scale)
		end
	end
	
	source.momx = FixedMul(FixedDiv(enemy.x - source.x, dist), ns)
	source.momy = FixedMul(FixedDiv(enemy.y - source.y, dist), ns)
	--source.momz = FixedMul(FixedDiv(zdist, dist), ns)
	return true
end)

-- SetTarget: Sets a target and returns the mobj if valid.
-- Returns a nil value if no target. Can be used in if statements to check conditionals.
--
-- Flame
--
-- mo (mobj_t)			- source mobj
-- target (mobj_t)		- target mobj
rawset(_G, "L_SetTarget", function(mo, target)
	mo.target = target
	return target
end)

-- SetTracer: Same as above, but sets a tracer instead.
--
-- Flame
--
-- mo (mobj_t)			- source mobj
-- tracer (mobj_t)		- target mobj
rawset(_G, "L_SetTracer", function(mo, tracer)
	mo.tracer = tracer
	return tracer
end)

-- Look4Target: Looks for a target around 'mo' within a distance (If specified).
-- Returns the closest mo found.
--
-- Flame
--
-- mo (mobj_t)			- source mobj
-- maxdist (int)		- Distance to search
rawset(_G, "L_Look4Target", function(mo, maxdist)
	if not maxdist then maxdist = RING_DIST/2 end
	local lastmo
	local dist
	local lastdist = 0

	if not mo or not mo.valid then return end -- Sanity check
	for i_mo in mobjs.iterate()
		if (i_mo == mo) then continue end -- Are we a target somehow? Skip us.
		if (i_mo.health <= 0) then continue end -- mo doesn't have health.
		if not (i_mo.flags & MF_ENEMY) then continue end -- Not an enemy.
		--if not (i_mo.flags & MF_SHOOTABLE) then continue end -- Not touchable
		if (i_mo.flags & MF2_FRET) then continue end -- In pain, ignore
		if (i_mo.z > (mo.z + mo.height)) then continue end -- Ignore anything above your head
		if not P_CheckSight(mo,i_mo) then continue end -- Can't get it if you can't see it!

		dist = FixedHypot(FixedHypot(mo.x - i_mo.x, mo.y - i_mo.y), mo.z - i_mo.z) -- Calculate Distance
		
		-- Last mobj is closer?
		if (lastmo and (dist > lastdist))
		or (dist > maxdist) then continue end

		-- Found a target
		lastmo = i_mo
		lastdist = dist
	end
	return lastmo
end)

-- Look4Target: Same as above, Looks for a target around 'mo' within a distance (If specified).
-- Returns a table of mobj's found around 'mo' found.
--
-- Flame
--
-- mo (mobj_t)			- source mobj
-- maxdist (int)		- Distance to search
rawset(_G, "L_Look4TargetTable", function(mo, maxdist)
	if not maxdist then maxdist = RING_DIST/2 end
	local lastmo
	local dist

	local enemytable = {}

	if not mo or not mo.valid then return end -- Sanity check
	for i_mo in mobjs.iterate()
		if (i_mo == mo) then continue end -- Are we a target somehow? Skip us.
		if (i_mo.health <= 0) then continue end -- mo doesn't have health.
		if not (i_mo.flags & MF_ENEMY) then continue end -- Not an enemy.
		--if not (i_mo.flags & MF_SHOOTABLE) then continue end -- Not touchable
		if (i_mo.flags & MF2_FRET) then continue end -- In pain, ignore
		if (i_mo.z > (mo.z + mo.height)) then continue end -- Ignore anything above your head
		if not P_CheckSight(mo,i_mo) then continue end -- Can't get it if you can't see it!

		dist = FixedHypot(FixedHypot(mo.x - i_mo.x, mo.y - i_mo.y), mo.z - i_mo.z) -- Calculate Distance

		-- Last mobj is closer?
		if (dist > maxdist) then continue end

		table.insert(enemytable, i_mo)
	end
	return enemytable
end)