--[[

	Mobs Skeletons - Adds skeletons.
	Copyright © 2021 Hamlet and contributors.

	Licensed under the EUPL, Version 1.2 or – as soon they will be
	approved by the European Commission – subsequent versions of the
	EUPL (the "Licence");
	You may not use this work except in compliance with the Licence.
	You may obtain a copy of the Licence at:

	https://joinup.ec.europa.eu/software/page/eupl
	https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX:32017D0863

	Unless required by applicable law or agreed to in writing,
	software distributed under the Licence is distributed on an
	"AS IS" basis,
	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
	implied.
	See the Licence for the specific language governing permissions
	and limitations under the Licence.

--]]

---
--- Variables
---

-- Global mod's namespace
mobs_skeletons = {}

-- Used for localization
local S = core.get_translator("mobs_skeletons")

-- Setting to enable direct sunlight only death of skeletons
local sunlight = core.settings:get_bool("mobs_skeletons.sunlight_kill") == true
local light_damage_min = sunlight and 14 or (default.LIGHT_MAX / 2)
local light_damage_max = sunlight and 16 or (default.LIGHT_MAX + 1)

-- Sounds
local sounds = {
	random = "mobs_skeletons_skeleton_random",
	-- Source: https://opengameart.org/content/80-cc0-creature-sfx
	-- File used is alien_02.ogg and was created by rubberduck
    -- Licensed under CC0
	-- Sound was converted from stereo to mono
	war_cry = "mobs_skeletons_skeleton_war_cry",
	attack = "mobs_skeletons_slash_attack",
	damage = "mobs_skeletons_skeleton_hurt",
	death = "mobs_skeletons_skeleton_death",
	shoot_attack = "bweapons_bows_pack_longbow_fire"
}

---
--- Functions
---

-- Used to calculate the damage per second
mobs_skeletons.fn_DamagePerSecond = function(self)

	-- direct sunlight returns full damage
	if sunlight then
		return 7
	end

	-- Constants
	local i_SECONDS_PER_DAY = 86400
	local i_SECONDS_PER_5_MINUTES = 300

	local i_hitPoints = self.health
	local i_timeSpeed = tonumber(core.settings:get("i_timeSpeed")) or 72

	if i_timeSpeed == 0 then
		i_timeSpeed = 1
	end

	local i_inGameDayLength = i_SECONDS_PER_DAY / i_timeSpeed
	local i_fiveInGameMinutes =
			(i_inGameDayLength * i_SECONDS_PER_5_MINUTES) / i_SECONDS_PER_DAY

	local i_damagePerSecond = i_hitPoints / i_fiveInGameMinutes

	return i_damagePerSecond
end


---
--- Arrow
---

-- Arrow item
core.register_craftitem("mobs_skeletons:arrow", {
	description = S("Skeleton Arrow"),
	inventory_image = "mobs_skeletons_arrow.png",
	groups = {not_in_creative_inventory = 1}
})

-- Arrow entity
mobs:register_arrow("mobs_skeletons:arrow", {
	visual = "wielditem",
	visual_size = {x = 0.25, y = 0.25},
	textures = {"mobs_skeletons:arrow"},
	velocity = 30,
	rotate = 0,
	drop = false,
})

-- Arrow entity
mobs:register_arrow("mobs_skeletons:poison_arrow", {
	visual = "wielditem",
	visual_size = {x = 0.25, y = 0.25},
	textures = {"mobs_skeletons:arrow"},
	-- YAMS-TODO: refine the appearance later
	tail = 1,
	tail_texture = "[fill:1x1:#00ff00cc",
	tail_size = 1,
	velocity = 30,
	rotate = 0,
	drop = false,
})

---
--- Dropped Items
---

local sword_drops = {
	{name = "default:sword_steel", chance = 5, min = 1, max = 1}
}

local archer_drops = {}

if core.get_modpath("bonemeal") then
	table.insert(sword_drops, {name = "bonemeal:bone", chance = 3, min = 1, max = 2})
	table.insert(archer_drops, {name = "bonemeal:bone", chance = 3, min = 1, max = 2})
end

if core.get_modpath("x_bows") then
	table.insert(archer_drops, {name = "x_bows:bow_wood", chance = 10, min = 1, max = 1})
	table.insert(archer_drops, {name = "x_bows:arrow_steel", chance = 3, min = 1, max = 3})
end

if core.get_modpath("bows") then
	table.insert(archer_drops, {name = "bows:bow_wood", chance = 10, min = 1, max = 1})
	table.insert(archer_drops, {name = "bows:arrow_steel", chance = 3, min = 1, max = 3})
end

---
--- Skeleton Entities
---

mobs:register_mob("mobs_skeletons:skeleton", {
	type = "monster",
	hp_min = 12,
	hp_max = 90,
	yams_resists = {
		yams_fire = {damage = 150, knockback = 100},
		yams_mese = {damage = 150, knockback = 100},
		yams_light = {damage = 200, knockback = 100},
		yams_dark = {damage = 0, knockback = 0},
	},
	walk_velocity = 1,
	run_velocity = 3,
	run_velocity_max = 5,
	jump = true,
	view_range = 15,
	damage = 2,
	damage_max = 30,
	knock_back = true,
	fear_height = 4,
	fall_damage = true,
	water_damage = 0,
	lava_damage = 8,
	light_damage = 2,
	floats = 0,
	reach = 2,
	attack_type = "dogfight",
	blood_texture = "[fill:1x1:#aaaaaa",  -- YAMS-TODO: temporary
	pathfinding = 1,
	makes_footstep_sound = true,
	sounds = sounds,
	visual = "mesh",
	visual_size = {x = 2.7, y = 2.7},
	collisionbox = {-0.3, 0.0, -0.3, 0.3, 1.7, 0.3},
	selectionbox = {-0.3, 0.0, -0.3, 0.3, 1.7, 0.3},
	textures = {
		"default_tool_steelsword.png",
		"mobs_skeletons_skeleton.png"
	},
	mesh = "mobs_skeletons_skeleton.b3d",
	animation = {
		stand_start = 0,
		stand_end = 40,
		stand_speed = 15,
		walk_start = 40,
		walk_end = 60,
		walk_speed = 15,
		run_start = 40,
		run_end = 60,
		run_speed = 30,
		shoot_start = 70,
		shoot_end = 90,
		punch_start = 110,
		punch_end = 130,
		punch_speed = 25,
		die_start = 160,
		die_end = 170,
		die_speed = 15,
		die_loop = false,
	},
	drops = {
		{name = "bonemeal:bone", chance = 3, min = 1, max = 2}
	},
	base_exp = 60,
	max_exp = 3000,
})

local function gen_drops_archer(pos)
	local res = {}

	if minetest.get_modpath("bonemeal") then
		table.insert(res, {name = "bonemeal:bone", chance = 1, min = 1, max = 1})
	end

	if minetest.get_modpath("bweapons_bows_pack") then
		table.insert(res,
			{name = "bweapons_bows_pack:arrow", chance = 2, min = 1, max = 1}
		)
	end
	
	if minetest.get_modpath("magic_materials") then
		table.insert(res,
			{name = "magic_materials:egerum_crystal", chance = 8, min = 1, max = 1}
		)
	end

	return res
end

mobs:register_mob("mobs_skeletons:skeleton_archer", {
	type = "monster",
	hp_min = 12,
	hp_max = 90,
	yams_resists = {
		yams_fire = {damage = 150, knockback = 100},
		yams_mese = {damage = 150, knockback = 100},
		yams_light = {damage = 200, knockback = 100},
		yams_dark = {damage = 0, knockback = 0},
	},
	walk_velocity = 1,
	run_velocity = 3,
	run_velocity_max = 5,
	jump = true,
	view_range = 15,
	damage = 2,
	damage_max = 30,
	arrow_damage = 2,
	arrow_damage_max = 30,
	arrow_error = 0.05,
	knock_back = true,
	fear_height = 4,
	fall_damage = true,
	water_damage = 0,
	lava_damage = 8,
	light_damage = 2,
	floats = 0,
	reach = 2,
	attack_type = "shoot",
	arrow = "mobs_skeletons:arrow",
	shoot_interval = 3.0,
	shoot_offset = 1.0,
	blood_texture = "[fill:1x1:#aaaaaa",  -- YAMS-TODO: temporary
	pathfinding = 1,
	makes_footstep_sound = true,
	sounds = sounds,
	visual = "mesh",
	visual_size = {x = 2.7, y = 2.7},
	collisionbox = {-0.3, 0.0, -0.3, 0.3, 1.7, 0.3},
	selectionbox = {-0.3, 0.0, -0.3, 0.3, 1.7, 0.3},
	textures = {
		"mobs_skeleton_bow.png",
		"mobs_skeletons_skeleton_archer.png"
	},
	mesh = "mobs_skeletons_skeleton_archer.b3d",
	animation = {
		stand_speed = 15,
		stand_start = 0,
		stand_end = 40,
		walk_speed = 15,
		walk_start = 40,
		walk_end = 60,
		run_speed = 30,
		shoot_start = 70,
		shoot_end = 90,
		die_start = 160,
		die_end = 170,
		die_speed = 15,
		die_loop = false,
	},
	drops = gen_drops_archer,
	base_exp = 60,
	max_exp = 6000,
	-- For the below: self.timer increases even if the mob is not attacking
	-- for whatever reason and can exceed the shoot interval, so we have to
	-- manually limit it to reduce player frustration
	do_custom = function(self, dtime, moveresult)
		-- We limit the timer while the skeleton has no target so that it does
		-- not instantly shoot the moment it sees the player, which felt cheap
		-- during my testing
		if self.state ~= "attack" and self.timer > 1.5 then
			self.timer = math.min(self.timer, 1.5)
		end
		return true  -- Continue with the rest of Mobs Redo's routines
	end,
	-- Delay the skeleton archer's next attack if it is knocked back
	on_knockback = function(self, kb)
		-- do_custom is not called while knockback is occurring, so we need
		-- a separate callback just for this
		self.timer = math.min(self.timer, 3.0)
		self.timer = self.timer / 2
	end,
})

local function gen_drops_dark_archer(pos)
	local res = {}

	if minetest.get_modpath("bonemeal") then
		table.insert(res, {name = "bonemeal:bone", chance = 1, min = 1, max = 2})
	end

	if minetest.get_modpath("bweapons_bows_pack") then
		table.insert(res,
			{name = "bweapons_bows_pack:arrow", chance = 2, min = 1, max = 2}
		)
	end

	if minetest.get_modpath("magic_materials") then
		table.insert(res,
			{name = "magic_materials:egerum_crystal", chance = 4, min = 1, max = 2}
		)
		table.insert(res,
			{name = "magic_materials:februm_crystal", chance = 16, min = 1, max = 1}
		)
	end

	if minetest.get_modpath("nether") then
		table.insert(res,
			{name = "nether:nether_lump", chance = 8, min = 1, max = 1}
		)
	end

	return res
end

mobs:register_mob("mobs_skeletons:skeleton_archer_dark", {
	type = "monster",
	hp_min = 30,
	hp_max = 100,
	yams_resists = {
		yams_fire = {damage = 150, knockback = 100},
		yams_mese = {damage = 150, knockback = 100},
		yams_light = {damage = 200, knockback = 100},
		yams_dark = {damage = -100, knockback = 0},
	},
	walk_velocity = 1,
	run_velocity = 3,
	run_velocity_max = 5,
	jump = true,
	view_range = 15,
	damage = 8,
	damage_max = 40,
	arrow_damage = 8,
	arrow_damage_max = 40,
	arrow_error = 0.05,
	yams_arrow_effects = {
		{name = "yams_effects:poison", duration = 16, chance = 25},
	},
	knock_back = true,
	fear_height = 4,
	fall_damage = true,
	water_damage = 0,
	lava_damage = 8,
	light_damage = 2,
	floats = 0,
	reach = 2,
	attack_type = "shoot",
	arrow = "mobs_skeletons:poison_arrow",
	shoot_interval = 2.5,
	shoot_offset = 1.0,
	blood_texture = "[fill:1x1:#aaaaaa",  -- YAMS-TODO: temporary
	pathfinding = 1,
	makes_footstep_sound = true,
	sounds = sounds,
	visual = "mesh",
	visual_size = {x = 2.7, y = 2.7},
	collisionbox = {-0.3, 0.0, -0.3, 0.3, 1.7, 0.3},
	selectionbox = {-0.3, 0.0, -0.3, 0.3, 1.7, 0.3},
	textures = {
		"mobs_skeleton_bow.png",
		"mobs_skeletons_skeleton_archer_dark.png",
		"mobs_skeletons_skeleton_archer_dark_overlay.png"
	},
	mesh = "mobs_skeletons_skeleton_archer_dark.b3d",
	animation = {
		stand_speed = 15,
		stand_start = 0,
		stand_end = 40,
		walk_speed = 15,
		walk_start = 40,
		walk_end = 60,
		run_speed = 30,
		shoot_start = 70,
		shoot_end = 90,
		die_start = 160,
		die_end = 170,
		die_speed = 15,
		die_loop = false,
	},
	drops = gen_drops_dark_archer,
	base_exp = 2000,
	max_exp = 8000,
	-- The reasoning for the regular skeleton archer applies here too
	do_custom = function(self, dtime, moveresult)
		-- Stricter than the regular skeleton archer
		if self.state ~= "attack" and self.timer > 1.5 then
			self.timer = math.min(self.timer, 1.5)
		end
		return true
	end,
	on_knockback = function(self, kb)
		-- Stricter than the regular skeleton archer
		self.timer = math.min(self.timer, 2.5)
		self.timer = self.timer / 1.5
	end,
})


---
--- Skeletons spawning (check for custom spawn.lua)
---

local MP = core.get_modpath(core.get_current_modname()) .. "/"
local input = io.open(MP .. "spawn.lua", "r")

if input then
	input:close()
	input = nil
	dofile(MP .. "spawn.lua")
else

--[[
	mobs:spawn({
		name = "mobs_skeletons:skeleton",
		nodes = {"group:crumbly", "group:cracky"},
		neighbors = "air",
		chance = 7000,
		active_object_count = 2,
		min_height = -31000,
		max_height = 31000,
		max_light = 6,
	})
]]--

	-- above ground spawn
	mobs:spawn({name = "mobs_skeletons:skeleton_archer",
		-- Exclude a few of the more dense biomes, such as rainforests,
		-- but otherwise spawn them basically everywhere
		nodes = {"default:dirt_with_grass", "default:dirt_with_snow",
			"default:dirt_with_coniferous_litter", "default:dry_dirt_with_dry_grass",
			"default:sand", "default:desert_sand", "default:silver_sand",
			"default:snowblock", "default:permafrost_with_stones",
			"ebiomes:dirt_with_grass_med", "ebiomes:dirt_with_grass_steppe_warm",
			"ebiomes:dirt_with_grass_steppe", "ebiomes:dirt_with_grass_steppe_cold",
			"ebiomes:dirt_with_grass_cold", "ebiomes:dirt_with_grass_swamp",
			"ebiomes:dirt_with_grass_warm", "ebiomes:dry_dirt_with_grass_arid",
			"ebiomes:dry_dirt_with_grass_arid_cool", "ebiomes:peat_with_swamp_moss_yellow",
			"ebiomes:dirt_with_forest_litter", "ebiomes:dirt_with_jungle_savanna_grass",
			"ebiomes:dry_dirt_with_humid_savanna_grass"},
		neighbors = {},
		min_light = 0,
		max_light = 4,
		interval = 15,
		chance = 16000,
		min_height = 0,
		max_height = 8190,
		day_toggle = false
	})

	-- below ground spawn
	mobs:spawn({
		name = "mobs_skeletons:skeleton_archer",
		nodes = {"default:stone", "default:desert_stone", "default:sandstone",
			"default:sand", "default:desert_sand", "default:silver_sand",
			"default:ice", "caverealms:stone_with_moss",
			"caverealms:stone_with_lichen", "caverealms:stone_with_algae",
			"caverealms:stone_with_salt", "caverealms:hot_cobble",
			"caverealms:thin_ice", "caverealms:glow_obsidian",
			"caverealms:glow_obsidian_2", "caverealms:coal_dust"},
		min_light = 0,
		max_light = 4,
		interval = 15,
		chance = 8000,
		min_height = -19900,
		max_height = -16,
	})

--[[
	mobs:spawn({
		name = "mobs_skeletons:skeleton_archer_dark",
		nodes = {"group:crumbly", "group:cracky"},
		neighbors = "air",
		chance = 7000,
		active_object_count = 2,
		min_height = -31000,
		max_height = 31000,
		max_light = 6
	})
]]--

	mobs:spawn({
		name = "mobs_skeletons:skeleton_archer_dark",
		nodes = {"nether:rack", "nether:rack_deep", "nether:geode"},
		interval = 15,
		chance = 24000,
		max_height = -20000
	})
end


---
--- Spawn Eggs
---

mobs:register_egg("mobs_skeletons:skeleton", S("Skeleton"),
		"mobs_skeletons_skeleton_egg.png")

mobs:register_egg("mobs_skeletons:skeleton_archer", S("Skeleton Archer"),
	"mobs_skeletons_skeleton_archer_egg.png")

mobs:register_egg("mobs_skeletons:skeleton_archer_dark", S("Dark Skeleton Archer"),
		"mobs_skeletons_skeleton_archer_dark_egg.png")


---
--- Aliases
---

mobs:alias_mob("mobs:skeleton", "mobs_skeletons:skeleton")
mobs:alias_mob("mobs:skeleton_archer", "mobs_skeletons:skeleton_archer")
mobs:alias_mob("mobs:dark_skeleton_archer", "mobs_skeletons:skeleton_archer_dark")


print("[MOD] Mobs Skeletons loaded")
