---------
-- Cat --
---------

local follow = {
	"animalia:poultry_raw"
}

if minetest.registered_items["ethereal:fish_raw"] then
	follow = {
		"ethereal:fish_raw",
		"animalia:poultry_raw"
	}
end

creatura.register_mob("animalia:cat", {
    -- Stats
    max_health = 10,
    armor_groups = {fleshy = 200},
    damage = 1,
    speed = 5,
	tracking_range = 24,
    despawn_after = 2000,
	-- Entity Physics
	stepheight = 1.1,
    -- Visuals
    mesh = "animalia_cat.b3d",
	hitbox = {
		width = 0.2,
		height = 0.4
	},
	visual_size = {x = 6, y = 6},
	textures = {
		"animalia_cat_1.png",
		"animalia_cat_2.png",
		"animalia_cat_3.png",
		"animalia_cat_4.png"
	},
	animations = {
		stand = {range = {x = 1, y = 39}, speed = 10, frame_blend = 0.3, loop = true},
		walk = {range = {x = 50, y = 90}, speed = 45, frame_blend = 0.3, loop = true},
		run = {range = {x = 100, y = 130}, speed = 50, frame_blend = 0.3, loop = true},
		sit = {range = {x = 140, y = 180}, speed = 10, frame_blend = 0.3, loop = true},
		smack = {range = {x = 190, y = 210}, speed = 40, frame_blend = 0.1, loop = true},
	},
    -- Misc
	catch_with_net = true,
	sounds = {
        random = {
            name = "animalia_cat_idle",
            gain = 0.25,
            distance = 8
        },
		purr = {
            name = "animalia_cat_purr",
            gain = 0.6,
            distance = 8
        },
        hurt = {
            name = "animalia_cat_hurt",
            gain = 0.25,
            distance = 8
        },
        death = {
            name = "animalia_cat_hurt",
            gain = 0.25,
            distance = 8
        }
	},
    follow = follow,
	head_data = {
		offset = {x = 0, y = 0.22, z = 0},
		pitch_correction = -20,
		pivot_h = 0.65,
		pivot_v = 0.65
	},
    -- Function
    activate_func = function(self)
		animalia.initialize_api(self)
		animalia.initialize_lasso(self)
        self._path = {}
		self.interact_sound_cooldown = 0
		self.trust_cooldown = self:recall("trust_cooldown") or 0
		self.order = self:recall("order") or "wander"
		self.owner = self:recall("owner") or nil
		self.trust = self:recall("trust") or {}
		if self.owner
		and minetest.get_player_by_name(self.owner) then
			if not animalia.pets[self.owner][self.object] then
				table.insert(animalia.pets[self.owner], self.object)
			end
		end
    end,
	utility_stack = {
		[1] = {
			utility = "animalia:wander",
			get_score = function(self)
				return 0.1, {self, true}
			end
		},
		[2] = {
			utility = "animalia:swim_to_land",
			get_score = function(self)
				if self.in_liquid then
					return 0.9, {self}
				end
				return 0
			end
		},
		[3] = {
			utility = "animalia:find_and_break_glass_vessels",
			get_score = function(self)
				return math.random(10) * 0.01, {self}
			end
		},
		[4] = {
			utility = "animalia:walk_ahead_of_player",
			get_score = function(self)
				local player = creatura.get_nearby_player(self)
				if player then
					local trust = 0
					if not self.trust[player:get_player_name()] then
						self.trust[player:get_player_name()] = 0
						self:memorize("trust", self.trust)
					else
						trust = self.trust[player:get_player_name()]
					end
					self._nearby_player = player
					if trust > 3 then
						return math.random(10) * 0.01, {self, player}
					else
						return 0
					end
				end
				return 0
			end
		},
		[5] = {
			utility = "animalia:flee_from_player",
			get_score = function(self)
				local player = self._nearby_player
				if player then
					local trust = self.trust[player:get_player_name()] or 0
					if trust < 1 then
						if self.owner
						and minetest.get_player_by_name(self.owner) then
							local pos = self.object:get_pos()
							local owner = minetest.get_player_by_name(self.owner)
							local owner_pos = owner:get_pos()
							if owner ~= player
							and vector.distance(pos, owner_pos) < vector.distance(pos, player:get_pos()) then
								return 0 
							end
						end
						return 0.5, {self, player}
					end
				end
				return 0
			end
		},
		[6] = {
			utility = "animalia:sit",
			get_score = function(self)
				if self.order == "sit"
				and self.trust[self.owner] > 7 then
					return 0.8, {self}
				end
				return 0
			end
		},
		[7] = {
			utility = "animalia:follow_player",
			get_score = function(self)
				if self.order == "follow"
				and minetest.get_player_by_name(self.owner)
				and self.trust[self.owner] > 7 then
					return 1, {self, minetest.get_player_by_name(self.owner)}
				end
				local trust = 0
				local player = self._nearby_player
				if player then
					if not self.trust[player:get_player_name()] then
						self.trust[player:get_player_name()] = 0
						self:memorize("trust", self.trust)
					else
						trust = self.trust[player:get_player_name()]
					end
				else
					return 0
				end
				if player:get_velocity()
				and vector.length(player:get_velocity()) < 2
				and self:follow_wielded_item(player)
				and trust >= 4 then
					return 0.6, {self, player}
				elseif player:get_wielded_item():get_name() == "animalia:cat_toy" then
					return 0.6, {self, player, true}
				end
				return 0
			end
		},
		[8] = {
			utility = "animalia:mammal_breed",
			get_score = function(self)
				if self.breeding then
					return 0.7, {self}
				end
				return 0
			end
		}
	},
    step_func = function(self)
		animalia.step_timers(self)
		animalia.head_tracking(self, 0.75, 0.75)
		animalia.do_growth(self, 60)
		animalia.update_lasso_effects(self)
		if self:timer(1) then
			if self.trust_cooldown > 0 then
				self.trust_cooldown = self:memorize("trust_cooldown", self.trust_cooldown - 1)
			end
			if self.interact_sound_cooldown > 0 then
				self.interact_sound_cooldown = self.interact_sound_cooldown - 1
			end
		end
    end,
    death_func = function(self)
		if self:get_utility() ~= "animalia:die" then
			self:initiate_utility("animalia:die", self)
		end
    end,
	on_rightclick = function(self, clicker)
		local item_name = clicker:get_wielded_item():get_name()
		if item_name == "animalia:net" then return end
		local trust = self.trust[clicker:get_player_name()] or 0
		local pos = self:get_center_pos()
		local minppos = vector.add(pos, 1)
		local maxppos = vector.subtract(pos, 1)
		if animalia.feed(self, clicker, true, true) then
			if self.trust_cooldown <= 0
			and trust < 10 then
				self.trust[clicker:get_player_name()] = trust + 1
				self.trust_cooldown = self:memorize("trust_cooldown", 60)
				self:memorize("trust", self.trust)
				animalia.particle_spawner(pos, "creatura_particle_green.png", "float", minppos, maxppos)
			end
			return
		end
		-- Initiate trust
		if not self.trust[clicker:get_player_name()] then
			self.trust[clicker:get_player_name()] = 0
			self:memorize("trust", self.trust)
		end
		-- Increase trust by playing
		if item_name == "animalia:cat_toy"
		and self:get_utility() == "animalia:follow_player" then
			if trust < 10 then
				self.trust[clicker:get_player_name()] = trust + 1
				self:memorize("trust", self.trust)
				animalia.particle_spawner(pos, "creatura_particle_green.png", "float", minppos, maxppos)
				if self.interact_sound_cooldown <= 0 then
					self.sounds["purr"].gain = 1
					self.interact_sound_cooldown = 3
					self:play_sound("purr")
				end
			end
		end
		-- Purr to indicate trust level (louder = more trust)
		if clicker:get_player_control().sneak then
			if self.interact_sound_cooldown <= 0 then
				self.sounds["purr"].gain = 0.15 * trust
				self.interact_sound_cooldown = 3
				self:play_sound("purr")
			end
		end
		animalia.add_libri_page(self, clicker, {name = "cat", form = "pg_cat;Cats"})
		if not self.owner
		or clicker:get_player_name() ~= self.owner then
			return
		end
		if trust <= 7 then
			if self.interact_sound_cooldown <= 0 then
				self.interact_sound_cooldown = 3
				self:play_sound("random")
			end
			return
		end
		if clicker:get_player_control().sneak then
			if self.interact_sound_cooldown <= 0 then
				self.sounds["purr"].gain = 0.15 * self.trust[self.owner]
				self.interact_sound_cooldown = 3
				self:play_sound("purr")
			end
			local order = self.order
			if order == "wander" then
				self.order = "follow"
			elseif order == "follow" then
				self.order = "sit"
			else
				self.order = "wander"
			end
			self:memorize("order", self.order)
		end
	end,
	on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
		creatura.basic_punch_func(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
		self:initiate_utility("animalia:flee_from_player", self, puncher)
		self:set_utility_score(1)
		if not self.trust[puncher:get_player_name()] then
			self.trust[puncher:get_player_name()] = 0
		else
			local trust = self.trust[puncher:get_player_name()]
			self.trust[puncher:get_player_name()] = trust - 1
		end
		local pos = self.object:get_pos()
		pos = vector.new(pos.x, pos.y + 0.5, pos.z)
		local minppos = vector.add(pos, 1)
		local maxppos = vector.subtract(pos, 1)
		animalia.particle_spawner(pos, "creatura_particle_red.png", "float", minppos, maxppos)
		self:memorize("trust", self.trust)
	end,
	deactivate_func = function(self)
		if self.owner
		and animalia.pets[self.owner][self.object] then
			animalia.pets[self.owner][self.object] = nil
		end
	end
})

creatura.register_spawn_egg("animalia:cat", "db9764" ,"cf8d5a")