
local S = core.get_translator("mobs_monster")

-- helper function

local function get_velocity(self)

	local v = self.object:get_velocity()

	-- sanity check
	if not v then return 0 end

	return (v.x * v.x + v.z * v.z) ^ 0.5
end

local math_cos, math_sin = math.cos, math.sin

-- custom spider types

local spider_types = {

	{	nodes = {"default:snow", "default:snowblock", "default:dirt_with_snow"},
		skins = {"mobs_spider_snowy.png"},
		docile = true,
		drops = nil
	},

	{	nodes = {"default:dirt_with_rainforest_litter",
		         "ebiomes:dirt_with_japanese_rainforest_litter",
		         "ebiomes:dirt_with_forest_litter",
		         "ebiomes:dirt_with_grass_swamp",
		         "ebiomes:peat_with_swamp_moss_yellow",
		         },
		skins = {"mobs_spider_orange.png"},
		docile = true,
		drops = nil,
		shoot = true
	},

	{	nodes = {"ethereal:crystal_dirt", "ethereal:crystal_spike"},
		skins = {"mobs_spider_crystal.png"},
		docile = true, immune_to = {{"ethereal:crystal_spike", 0}},
		drops = {
			{name = "farming:string", chance = 1, min = 0, max = 2},
			{name = "ethereal:crystal_spike", chance = 15, min = 1, max = 2}}
	}
}

local function gen_drops(pos)
	local res = {}

	if minetest.registered_items["farming:string"] then
		table.insert(res,
			{name = "farming:string", chance = 1, 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

-- Spider by AspireMint (CC-BY-SA 3.0 license)

mobs:register_mob("mobs_monster:spider", {
	stepheight = 0.1,
	type = "monster",
	passive = false,
	attack_type = "dogfight",
	attack_animals = true,
	pathfinding = true,
	reach = 2,
	damage = 2,
	damage_max = 30,
	arrow_damage = 2,
	arrow_damage_max = 30,
	arrow_knockback = 0.0,  -- So that the player gets stuck in the cobweb
	hp_min = 10,
	hp_max = 80,
	armor = 100,
	collisionbox = {-0.7, -0.5, -0.7, 0.7, 0, 0.7},
	visual_size = {x = 1, y = 1},
	visual = "mesh",
	mesh = "mobs_spider.b3d",
	textures = {
		{"mobs_spider_grey.png"},
		{"mobs_spider_crystal.png"},  -- Underutilized otherwise
	},
	makes_footstep_sound = true,
	sounds = {
		random = "mobs_spider",
		war_cry = "mobs_spider",
		attack = "mobs_spider",
		shoot_attack = "mobs_spider"
	},
	walk_velocity = 2,
	run_velocity = 4,
	run_velocity_max = 6,
	jump = true,
	view_range = 15,
	floats = 0,
	drops = gen_drops,
	water_damage = 0,
	lava_damage = 8,
	light_damage = 0,
	fall_damage = false,
	node_damage = false, -- disable damage_per_second node damage
	animation = {
		speed_normal = 15, speed_run = 20,
		stand_start = 0, stand_end = 0,
		walk_start = 1, walk_end = 21,
		run_start = 1, run_end = 21,
		punch_start = 25, punch_end = 45
	},
	base_exp = 50,
	max_exp = 5000,

	-- check surrounding nodes and spawn a specific spider
	on_spawn = function(self)

		local pos = self.object:get_pos() ; pos.y = pos.y - 1
		local tmp

		for n = 1, #spider_types do

			tmp = spider_types[n]

			if core.find_node_near(pos, 1, tmp.nodes) then

				self.base_texture = tmp.skins
				self.object:set_properties({textures = tmp.skins})

				if tmp.drops then self.drops = tmp.drops end

				if n == 1 then  -- ice spider
					self.yams_resists = {yams_ice = {damage = 25, knockback = 50}}
				end

				if tmp.immune_to then self.immune_to = tmp.immune_to end

			end
		end

		-- Spiders located above ground are docile during the day
		if pos.y >= 0 then
			self.docile_by_day = true
		end

		local num = math.random(1, 4)

		-- Very rare spider that drops a mese block and runs away from players
		-- YAMS-TODO: make the movement smoother
		if math.random(1, 500) == 1 then
			self.runaway_from = {"player"}
			self.drops = {{name = "default:mese", chance = 1, min = 1, max = 1}}
			self.run_velocity = self.run_velocity + 2.0

			self.base_texture = {"mobs_spider_mese.png"}
			self.object:set_properties({textures = self.base_texture})
		-- Disable its projectile attack on the surface to give beginners
		-- an easier time, but enable it 25% of the time otherwise
		elseif (pos.y <= -16 or pos.y >= 1000) and num == 1 then
			self.attack_type = "dogshoot"
			self.arrow = "mobs_monster:cobweb"
			self.dogshoot_switch = math.random(1, 2)
			self.dogshoot_count_max = math.random(5, 15)
			self.dogshoot_count2_max = math.random(5, 15)
			self.shoot_interval = 2
			self.shoot_offset = 2
			self.exp_value = self.exp_value * 1.2

			local effect_name = "yams_effects:speed_down_small"
			if pos.y <= -1024 or pos.y >= 1000 then
				effect_name = "yams_effects:speed_down_medium"
			end

			self.yams_arrow_effects = {
				{name = effect_name, duration = 10, chance = 100},
			}
		-- Poisonous spiders start appearing later on
		elseif (pos.y <= -1024 or pos.y >= 1000) and num == 2 then
			self.yams_melee_effects = {
				{name = "yams_effects:poison", duration = 16, chance = 50},
			}
			self._particle_timer = 10.0

		end

		return true -- run only once, false/nil runs every activation
	end,

	-- custom function to make spiders climb vertical facings
	do_custom = function(self, dtime)
		if self._particle_timer then  -- not nil = poisonous
			self._particle_timer = self._particle_timer + dtime
			-- 10 seconds is a long enough interval
			if self._particle_timer >= 10.0 then
				-- YAMS-TODO: disappears on despawn and logout
				-- Thus, we just do this messy solution for now but eventually
				-- we should be smarter about it and only add it when needed
				-- to save bandwidth
				-- See: https://github.com/minetest/minetest/issues/4624
				minetest.add_particlespawner({
					amount = 100,
					time = 10,
					attached = self.object,
					texture = {
						name = "[fill:1x1:#00ff00cc",
						scale = 0.5,
					},
					pos = {
						min = vector.new(-0.5, 0, -0.5),
						max = vector.new(0.5, 0, 0.5)
					},
					vel = vector.new(0, 1, 0)
				})
				self._particle_timer = self._particle_timer - 10.0
			end
		end

		-- quarter second timer
		self.spider_timer = (self.spider_timer or 0) + dtime
		if self.spider_timer < 0.25 then return end
		self.spider_timer = 0

		-- need to be stopped to go onwards
		if get_velocity(self) > 0.5 then
			self.disable_falling = nil
			return
		end

		local pos = self.object:get_pos()
		local yaw = self.object:get_yaw() ; if not yaw then return end
		local prop = self.object:get_properties()

		pos.y = pos.y + prop.collisionbox[2] - 0.2

		local dir_x = -math_sin(yaw) * (prop.collisionbox[4] + 0.5)
		local dir_z = math_cos(yaw) * (prop.collisionbox[4] + 0.5)
		local nod = core.get_node_or_nil({
			x = pos.x + dir_x,
			y = pos.y + 0.5,
			z = pos.z + dir_z
		})

		-- get current velocity
		local v = self.object:get_velocity()

		-- can only climb solid facings
		if not nod or not core.registered_nodes[nod.name]
		or not core.registered_nodes[nod.name].walkable then
			self.disable_falling = nil
			v.y = 0
			self.object:set_velocity(v)
			return
		end

--print ("----", nod.name, self.disable_falling, dtime)

		-- turn off falling if attached to facing
		self.disable_falling = true

		-- move up facing
		v.x = 0 ; v.y = 0
		v.y = self.jump_height

		self:set_animation("jump")

		self.object:set_velocity(v)
	end,

	-- make spiders jump at you on attack
	custom_attack = function(self, pos)

		local vel = self.object:get_velocity()

		self.object:set_velocity({
			x = vel.x * self.run_velocity,
			y = self.jump_height * 1.5,
			z = vel.z * self.run_velocity
		})

		self.pausetimer = 0.5

		return true -- continue rest of attack function
	end
})

-- where to spawn

if not mobs.custom_spawn_monster then

	-- above ground spawn
	mobs:spawn({
		name = "mobs_monster:spider",
		nodes = {
			"default:dirt_with_rainforest_litter",
			"default:dirt_with_snow",
			"ethereal:crystal_dirt", "ethereal:cold_dirt",
			"ebiomes:dirt_with_grass_swamp",
			"ebiomes:peat_with_swamp_moss_yellow",
			"ebiomes:dirt_with_japanese_rainforest_litter",
			"ebiomes:dirt_with_forest_litter",
		},
		neighbors = {},
		min_light = 0,
		max_light = 4,
		interval = 15,
		chance = 8000,
		min_height = 0,
		max_height = 8190,
	})

	-- below ground spawn
	mobs:spawn({
		name = "mobs_monster:spider",
		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,
	})
end

-- spawn egg

mobs:register_egg("mobs_monster:spider", S("Spider"), "mobs_cobweb.png", 1)

-- compatibility with older mobs mod

mobs:alias_mob("mobs_monster:spider2", "mobs_monster:spider")
mobs:alias_mob("mobs:spider", "mobs_monster:spider")

-- cobweb and recipe

core.register_node(":mobs:cobweb", {
	description = S("Cobweb"),
	drawtype = "plantlike",
	visual_scale = 1.2,
	tiles = {"mobs_cobweb.png"},
	inventory_image = "mobs_cobweb.png",
	paramtype = "light",
	sunlight_propagates = true,
	liquid_viscosity = 11,
	liquidtype = "source",
	liquid_alternative_flowing = "mobs:cobweb",
	liquid_alternative_source = "mobs:cobweb",
	liquid_renewable = false,
	liquid_range = 0,
	walkable = false,
	groups = {snappy = 3, disable_jump = 1},
	is_ground_content = false,
	drop = {}, -- nothing
	sounds = mobs.node_sound_leaves_defaults()
})

--[[
core.register_craft({
	output = "mobs:cobweb",
	recipe = {
		{"farming:string", "", "farming:string"},
		{"", "farming:string", ""},
		{"farming:string", "", "farming:string"}
	}
})
]]--

-- YAMS-TODO: replace 'find_node_near' with something smarter
-- cobweb place function

local web_place = function(pos)

	if core.find_node_near(pos, 1, {"ignore"}) then return end

	local pos2 = core.find_node_near(pos, 1, {"air", "group:leaves"}, true)

	if pos2 then
		core.swap_node(pos2, {name = "mobs:cobweb"})
	end
end

-- cobweb arrow

mobs:register_arrow("mobs_monster:cobweb", {
	visual = "sprite",
	visual_size = {x = 0.25, y = 0.25},
	textures = {"mobs_cobweb.png"},
	collisionbox = {-0.1, -0.1, -0.1, 0.1, 0.1, 0.1},
	velocity = 12,
	tail = 1,
	tail_texture = "mobs_cobweb.png",
	tail_size = 5,
	glow = 2,
	expire = 0.1,
	damage = 2,

	hit_player = function(self, player)

		player:punch(self.object, 1.0, {
			full_punch_interval = 1.0,
			damage_groups = {fleshy = self.damage}
		}, nil)

		web_place(self.object:get_pos())
	end,

	hit_node = function(self, pos, node)
		web_place(pos)
	end,

	hit_mob = function(self, player)

		player:punch(self.object, 1.0, {
			full_punch_interval = 1.0,
			damage_groups = {fleshy = self.damage}
		}, nil)
	end
})
