local s_chillaxin_speed = 1.5
local s_animation_speed = 15
local s_mesh = "creatures_sheep.x"
local s_texture = {"creatures_sheep.png"}
local s_hp = 8
local s_life_max = 80 --~5min
local s_drop = "wool:white"
local s_drop2 = "creatures:flesh"

local s_player_radius = 14

local s_sound_normal = "creatures_sheep"
local s_sound_hit = "creatures_sheep"
local s_sound_dead = "creatures_sheep"
local s_sound_shears = "creatures_shears"

creatures.s_spawn_nodes = {"default:dirt_with_grass"}

local function s_get_animations()
	return {
		stand_START = 0,
		stand_END = 80,
		walk_START = 81,
		walk_END = 100,
		eat_START = 107,
		eat_END = 185
	}
end

local function eat_cn(self, pos)
	self.object:setvelocity({x=0,y=-20,z=0})
	local p = {x=pos.x,y=pos.y-1,z=pos.z}
	local n = minetest.get_node(p) or nil
	if n and n.name and n.name == "default:dirt_with_grass" then
		self.object:set_animation({x=self.anim.eat_START,y=self.anim.eat_END}, s_animation_speed, 0)
		self.npc_anim = creatures.ANIM_EAT
		self.timer = 0
		minetest.after(3.5, function()
			self.has_wool = true
			self.state = 1
			s_update_visuals(self)
			minetest.set_node(p,{name="default:dirt"})
		end)
	end
end

function s_hit(self)
	local sound = s_sound_hit
	if self.object:get_hp() < 1 then
		sound = s_sound_dead 
	end
	minetest.sound_play(sound, {pos = self.object:getpos(), max_hear_distance = 10, loop = false, gain = 0.4})
	s_update_visuals(self, "^[colorize:#c4000099")
	self.can_punch = false
	minetest.after(0.4, function()
		s_update_visuals(self)
	end)
end

function s_update_visuals(self, hit)	
	self.txture = {"creatures_sheep.png" .. (hit or "")}
	if not self.has_wool then
		self.txture = {"creatures_sheep_shaved.png" .. (hit or "")}
	end
	local prop = {
		mesh = s_mesh,
		textures = self.txture,
	}
	self.object:set_properties(prop)
end

SHEEP_DEF = {
	physical = true,
	collisionbox = {-0.4, -0.01, -0.6, 0.4, 0.9, 0.4},
	visual = "mesh",
	visual_size = {x=1, y=1},
	mesh = s_mesh,
	textures = s_texture,
	txture = s_texture,
	makes_footstep_sound = true,
	npc_anim = 0,
	lifetime = 0,
	timer = 0,
	turn_timer = 0,
	vec = 0,
	yaw = 0,
	yawwer = 0,
	has_wool = true,
	state = 1,
	can_punch = true,
	dead = false,
	jump_timer = 0,
	last_pos = {x=0,y=0,z=0},
	punch_timer = 0,
	sound_timer = 0,
	feeder = "",
	mob_name = "sheep"
}

SHEEP_DEF.get_staticdata = function(self)
	return minetest.serialize({
		itemstring = self.itemstring,
		timer = self.timer,
		txture = self.txture,
		has_wool = self.has_wool,
		lifetime = self.lifetime,
	})
end

SHEEP_DEF.on_activate = function(self, staticdata, dtime_s)
	self.txture = s_texture
	s_update_visuals(self)
	self.anim = s_get_animations()
	self.object:set_animation({x=self.anim.stand_START,y=self.anim.stand_END}, s_animation_speed, 0)
	self.npc_anim = ANIM_STAND
	self.object:setacceleration({x=0,y=-20,z=0})
	self.object:setyaw(self.object:getyaw()+((math.random(0,90)-45)/45*math.pi))
	self.lastpos = self.object:getpos()
	self.state = 1
	self.object:set_hp(s_hp)
	self.object:set_armor_groups({fleshy=130})
	self.can_punch = true
	self.dead = false
	self.has_wool = true
	self.lifetime = 0
	self.feeder = ""
	if staticdata then
		local tmp = minetest.deserialize(staticdata)
		if tmp and tmp.timer then
			self.timer = tmp.timer
		end
		if tmp and tmp.has_wool ~= nil then
			self.has_wool = tmp.has_wool
		end
		if tmp and tmp.lifetime ~= nil then
			self.lifetime = tmp.lifetime
		end
		if not self.has_wool then
			s_update_visuals(self)
		end
	end
end

SHEEP_DEF.on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir)
	if not self.can_punch then return end
	
	self.feeder = ""
	self.timer = 0

	if puncher ~= nil then
		if time_from_last_punch >= 0.2 then --0.45
			s_hit(self)
			local v = self.object:getvelocity()
			self.direction = {x=v.x, y=v.y, z=v.z}
			self.punch_timer = 0
			self.object:setvelocity({x=dir.x*2.5,y=5.2,z=dir.z*2.5})
			self.state = 9
			-- add wear to sword/tool
			creatures.add_wear(puncher, tool_capabilities)
		end

		local my_pos = self.object:getpos()
		my_pos.y = my_pos.y + 0.4

		-- drop 1-2 whool when punched
		if self.has_wool then
			self.has_wool = false
			creatures.drop(my_pos, {{name=s_drop, count=math.random(1,2)}}, dir)
		end
		if self.object:get_hp() < 1 then
			creatures.drop(my_pos, {{name=s_drop2, count=1}}, dir)
		end
	end

end

SHEEP_DEF.on_rightclick = function(self, clicker)
	if not clicker or not self.has_wool then
		return
	end

	local item = clicker:get_wielded_item()
	local name = item:get_name()
	if item and name and name == "creatures:shears" then
		local my_pos = self.object:getpos()
		minetest.sound_play(s_sound_shears, {pos = my_pos, max_hear_distance = 10, gain = 1})
		my_pos.y = my_pos.y + 0.4
		self.has_wool = false
		s_update_visuals(self)
		creatures.drop(my_pos, {{name=s_drop, count=2}})
		if not minetest.setting_getbool("creative_mode") then
			item:add_wear(65535/100)
			clicker:set_wielded_item(item)
		end
	end
end

SHEEP_DEF.on_step = function(self, dtime)
	if self.dead then return end
	if self.lifetime == nil then self.lifetime = 0 end
	self.timer = self.timer + 0.01
	self.lifetime = self.lifetime + 0.01
	self.turn_timer = self.turn_timer + 0.01
	self.jump_timer = self.jump_timer + 0.01
	self.punch_timer = self.punch_timer + 0.01
	self.sound_timer = self.sound_timer + 0.01

	local current_pos = self.object:getpos()
	local current_node = minetest.env:get_node(current_pos)

	-- death
	if self.object:get_hp() < 1 then
		self.object:setvelocity({x=0,y=-20,z=0})
		self.object:set_hp(0)
		self.state = 0
		self.dead = true
		minetest.sound_play(s_sound_dead, {pos = current_pos, max_hear_distance = 10, gain = 0.9})
		self.object:set_animation({x=self.anim.lay_START,y=self.anim.lay_END}, s_animation_speed, 0)
		minetest.after(0.5, function()
			if creatures.drop_on_death then
				local drop = {{name=s_drop2, count=1}}
				if self.has_wool then
					drop[2] = {name=s_drop, count=math.random(1,2)}
				end
				creatures.drop(current_pos, drop, dir)
			end
			self.object:remove()
		end)
	end

	-- die if old and alone
	if self.lifetime > s_life_max then
		if creatures.find_mates(current_pos, "sheep", 15) then
			self.lifetime = 0
		else
			self.object:set_hp(0)
			self.state = 0
			self.dead = true
			self.object:remove()
			return
		end
	end

	-- die when in water, lava
	local wtime = minetest.env:get_timeofday()
	local ll = minetest.env:get_node_light({x=current_pos.x,y=current_pos.y+1,z=current_pos.z}) or 0
	local nn = nil
	if current_node ~= nil then nn = current_node.name end
	if nn ~= nil and nn == "default:water_source" or
	   nn == "default:water_flowing" or 
	   nn == "default:lava_source" or 
	   nn == "default:lava_flowing" then
		self.sound_timer = self.sound_timer + 0.1
		if self.sound_timer >= 0.8 then
			local damage = 2
			self.sound_timer = 0
			self.object:set_hp(self.object:get_hp()-damage)
			s_hit(self)
		end
	 end

	if self.state < 0 then
		return
	end

	-- update moving state depending on current state
	if self.state < 4 then
		if self.timer > 4/self.state then
			self.timer = 0
			--local new = math.random(1,3)
			--if self.state == 3 then new = 1 end
			--if self.feeder == "" then new = 5 end
			self.state = 5--new
			--s_update_visuals(self)
		end
	elseif self.state == 4 and self.timer > 1.5 then
		self.state = 2
		self.timer = 0
	elseif self.state == 5 then
		local new = math.random(1,3)
		if self.state == 3 then new = 1 end
		if self.feeder ~= "" then new = 5 end
		self.state = new
		self.timer = 0
	end

	-- play random sound
	local num = tonumber(self.lifetime/2) or 35
	if num < 6 then num = 6 end
	if self.sound_timer > self.timer + math.random(5, num) then
		minetest.sound_play(s_sound_normal, {pos = current_pos, max_hear_distance = 10, gain = 0.7})
		self.sound_timer = 0
	end

	-- after knocked back
	if self.state >= 8 then
		if self.punch_timer > 0.15 then
			if self.state == 9 then
				self.object:setvelocity({x=self.direction.x*s_chillaxin_speed,y=-20,z=self.direction.z*s_chillaxin_speed})
				self.state = 4
				self.punch_timer = 0
			elseif self.state == 8 then
				self.object:setvelocity({x=0,y=-20,z=0})
				self.state = 1
			end
			self.can_punch = true
		end
	end

	--STANDING
	if self.state == 1 then
		self.yawwer = true
		if self.turn_timer > math.random(1,4) then
			local last = self.yaw
			self.yaw = last + math.random(-0.5,1)
			if self.yaw > 22 or self.yaw < -17 then self.yaw = 0 end
			self.object:setyaw(self.yaw)
			self.turn_timer = 0
			self.direction = {x = math.sin(self.yaw)*-1, y = -20, z = math.cos(self.yaw)}
		end
		self.object:setvelocity({x=0,y=self.object:getvelocity().y,z=0})
		if self.npc_anim ~= creatures.ANIM_STAND then
			self.anim = s_get_animations()
			self.object:set_animation({x=self.anim.stand_START,y=self.anim.stand_END}, s_animation_speed, 0)
			self.npc_anim = creatures.ANIM_STAND
		end
		
	end

	-- stop walking when not moving	
	if self.state == 2 and creatures.compare_pos(self.object:getpos(),self.lastpos) and self.jump_timer <= 0.2 then
		self.state = 1
	end

	-- CHECK FEEDER
	if self.state == 5 then
		self.feeder = ""
		creatures.follow(self, {{name="farming:wheat"}}, 8)
		if self.feeder ~= "" then
			self.direction = {x = math.sin(self.yaw)*-1, y = -20, z = math.cos(self.yaw)}
			self.state = 2
		else 
			local new = math.random(1,3)
			if self.state == 3 then new = 1 end
			self.state = new
		end
	end

	-- WALKING
	if self.state == 2 or self.state == 4 then
		self.lastpos = self.object:getpos()
		local speed = 1
		local anim = creatures.ANIM_WALK
		if self.state == 4 then
			speed = 2.2
			anim = creatures.ANIM_RUN
		end
		if self.feeder ~= "" then
			--use this for following weed, etc
			--self.direction = {x = math.sin(self.yaw)*-1, y = -20, z = math.cos(self.yaw)}
			self.state = 5
		end

		if self.direction ~= nil then
			self.object:setvelocity({x=self.direction.x*s_chillaxin_speed*speed,y=self.object:getvelocity().y,z=self.direction.z*s_chillaxin_speed*speed})
		end
		if (self.turn_timer > math.random(0.8,2)) or (self.state == 4 and self.turn_timer > 0.2) then
			if self.state == 2 then
				local last = self.yaw
				self.yaw = last + math.random(-1,0.5)
				if self.yaw > 22 or self.yaw < -17 then self.yaw = 0 end
			else
				self.yaw = 360 * math.random()
			end
			self.object:setyaw(self.yaw)
			self.turn_timer = 0
			self.direction = {x = math.sin(self.yaw)*-1, y = -20, z = math.cos(self.yaw)}
		end
		if self.npc_anim ~= anim then
			self.object:set_animation({x=self.anim.walk_START,y=self.anim.walk_END}, s_animation_speed*speed, 0)
			self.npc_anim = anim
		end
		--jump
		creatures.jump(self, current_pos, 7.7, 0.2)
	end

	-- EATING
	if self.state == 3 then
		self.state = -1 -- deactivate most while eating
		eat_cn(self, current_pos)
	end
end

minetest.register_entity("creatures:sheep", SHEEP_DEF)
