--[[ reflectors.lua
Copyright 2025 Pixelo789

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.

SPDX-License-Identifier: AGPL-3.0-or-later
--]]


local S = core.get_translator(core.get_current_modname())
register_node = core.register_node


-- Changes the "scale" of the function
local function number_change_scale(num, scale1, scale2)
	local range1 = scale1[2] - scale1[1]
	local range2 = scale2[2] - scale2[1]
	local percent = (num - scale1[1]) / range1
	return range2 * percent + scale2[1]
end


local function param2_to_dir(param2)
	return {x = 1 - math.abs(param2 - 1), z = math.abs(param2 - 2) - 1}
end


local front = "thinkingwitharrows_bows_reflector_front.png"
local back = "thinkingwitharrows_bows_reflector_back.png"
local side = "thinkingwitharrows_bows_reflector_side.png"

local front_mineable = "thinkingwitharrows_bows_mineable_reflector_front.png"
local back_mineable = "thinkingwitharrows_bows_mineable_reflector_back.png"
local side_mineable = "thinkingwitharrows_bows_mineable_reflector_side.png"


--[[ Definition table: {
	id = "string",
	name = "string",
	tiles = {},
	mineable = bool,
	paramtype2 = "string",
	on_shoot = function(pos, node, player, pointed_thing),
}
--]]
local function register_reflector(def)
	local groups = {oddly_breakable_by_hand = 2}
	if def.mineable == true then
		groups = {oddly_breakable_by_hand = 3}
	end
	register_node(def.id, {
		description = def.description,
		tiles = def.tiles,
		stack_max = 1000,
		groups = groups,
		paramtype2 = def.paramtype2,
		on_punch = function(pos, node, puncher, pointed_thing)
			local pt = pointed_thing or {}

			if pt.intersection_normal and pt.intersection_point and (puncher and puncher:is_player()) then
				core.sound_play("thinkingwitharrows_reflect", {pitch = 2^-1, start_time = -0.9})

				local callback = def.on_shoot
				if callback then
					callback(pos, node, puncher, pointed_thing)
				end
			end
		end
	})
end


--[[ Helper function to spawn an arrow
Definition table: {
	name = "str",
	pos = {},
	dir = {},
	velocity = {},
}
--]]
local function spawn_arrow(def)
	local arrow = core.add_entity(
		def.pos,
		'x_bows:arrow_entity',
		core.serialize({
			_arrow_name = "thinkingwitharrows_bows:arrow",
			_bow_name = "thinkingwitharrows_bows:bow",
			_user_name = def.name,
			_is_critical_hit = false,
			_tool_capabilities = {
				full_punch_interval = 0.7,
				max_drop_level = 0,
				damage_groups = { fleshy = 2 }
			},
			_tflp = 1,
			_add_damage = 0,
			_custom_dir = def.dir,
		})
	)

	arrow:set_velocity(def.velocity)
end


-- Horizontal reflector
register_reflector {
	id = "thinkingwitharrows_bows:reflector",
	description = S("Reflector"),
	tiles = {side .. "^[transformR90", side .. "^[transformR270", side, side .. "^[transformR180", front, back},
	paramtype2 = "4dir",
	on_shoot = function(pos, node, player, pointed_thing)
		local name = player:get_player_name()
		local param2_dir = param2_to_dir(node.param2)

		spawn_arrow {
			name = name,
			pos = {x = pos.x, y = pos.y + 0.7, z = pos.z},
			dir = {x = param2_dir.x / 2, y =  0.2, z = param2_dir.z / 2},
			velocity = {x = param2_dir.x * 30, y = 1, z = param2_dir.z * 30},
		}
	end
}


-- Up reflector
register_reflector {
	id = "thinkingwitharrows_bows:reflector_up",
	description = S("Up Reflector"),
	tiles = {front, back, side .. "^[transformR90", side .. "^[transformR90", side .. "^[transformR90", side .. "^[transformR90"},
	paramtype2 = "none",
	on_shoot = function(pos, node, player, pointed_thing)
		local name = player:get_player_name()

		spawn_arrow {
			name = name,
			pos = {x = pos.x, y = pos.y + 0.7, z = pos.z},
			dir = {x = 0, y = 0.6, z = 0},
			velocity = {x = 0, y = 0.1, z = 0},
		}
	end
}


-- Down reflector
register_reflector {
	id = "thinkingwitharrows_bows:reflector_down",
	description = S("Down Reflector"),
	tiles = {back, front, side .. "^[transformR270", side .. "^[transformR270", side .. "^[transformR270", side .. "^[transformR270"},
	paramtype2 = "none",
	on_shoot = function(pos, node, player, pointed_thing)
		local name = player:get_player_name()

		spawn_arrow {
			name = name,
			pos = {x = pos.x, y = pos.y - 0.7, z = pos.z},
			dir = {x = 0, y = -0.6, z = 0},
			velocity = {x = 0, y = -0.1, z = 0},
		}
	end
}


-- Horizontal mineable reflector
register_reflector {
	id = "thinkingwitharrows_bows:mineable_reflector",
	description = S("Mineable Reflector"),
	tiles = {side_mineable .. "^[transformR90", side_mineable .. "^[transformR270", side_mineable, side_mineable .. "^[transformR180", front_mineable, back_mineable},
	mineable = true,
	paramtype2 = "4dir",
	on_shoot = function(pos, node, player, pointed_thing)
		local name = player:get_player_name()
		local param2_dir = param2_to_dir(node.param2)

		spawn_arrow {
			name = name,
			pos = {x = pos.x, y = pos.y + 0.7, z = pos.z},
			dir = {x = param2_dir.x / 2, y =  0.2, z = param2_dir.z / 2},
			velocity = {x = param2_dir.x * 30, y = 1, z = param2_dir.z * 30},
		}
	end
}
