From 964451fd7840cb2ad8db89044f0d92180ecd26bd Mon Sep 17 00:00:00 2001 From: tenplus1 Date: Sat, 3 Aug 2024 11:35:28 +0100 Subject: [PATCH] add mob hearing feature and self.on_sound() function --- api.lua | 76 +++++++++++++++++++++++++++++++++++++++++++++++- api.txt | 10 +++++++ settingtypes.txt | 3 ++ 3 files changed, 88 insertions(+), 1 deletion(-) diff --git a/api.lua b/api.lua index db215d8..f20c8f7 100644 --- a/api.lua +++ b/api.lua @@ -21,7 +21,7 @@ end -- Global mobs = { mod = "redo", - version = "20240716", + version = "20240803", translate = S, invis = minetest.global_exists("invisibility") and invisibility or {}, node_snow = has(minetest.registered_aliases["mapgen_snow"]) @@ -2823,6 +2823,16 @@ local tr = minetest.get_modpath("toolranks") -- deal damage and effects when mob punched function mob_class:on_punch(hitter, tflp, tool_capabilities, dir, damage) + -- is punch from sound detection + if hitter == "sound" then + + if self.on_sound then + self.on_sound(self, tool_capabilities) -- pass sound table to custom function + end + + return true + end + -- mob health check if self.health <= 0 then return true @@ -3786,6 +3796,7 @@ minetest.register_entity(":" .. name, setmetatable({ do_punch = def.do_punch, on_breed = def.on_breed, on_grown = def.on_grown, + on_sound = def.on_sound, on_activate = function(self, staticdata, dtime) return self:mob_activate(staticdata, def, dtime) @@ -5045,3 +5056,66 @@ minetest.register_chatcommand("clear_mobs", { minetest.chat_send_player(name, S("@1 mobs removed.", count)) end }) + + +-- Is mob hearing enabled, if so override minetest.sound_play with custom function +if settings:get_bool("mobs_can_hear") ~= false then + +local old_sound_play = minetest.sound_play + +minetest.sound_play = function(spec, param, eph) + + local op_params = {} + + -- store sound position + if param.pos then + op_params.pos = param.pos + elseif param.object then + op_params.pos = param.object:get_pos() + elseif param.to_player then + op_params.pos = minetest.get_player_by_name(param.to_player):get_pos() + end + + -- store sound name and gain + if type(spec) == "string" then + op_params.sound = spec + op_params.gain = param.gain or 1.0 + elseif type(spec) == "table" then + op_params.sound = spec.name + op_params.gain = spec.gain or param.gain or 1.0 + end + + -- store player name or object reference + if param.to_player then + op_params.player = param.to_player + elseif param.object then + op_params.object = param.object + end + + -- find mobs within sounds max_hear_distance + local objs = minetest.get_objects_inside_radius(op_params.pos, + param.max_hear_distance or 32) + + for n = 1, #objs do + + local obj = objs[n] + + if not obj:is_player() then + + local ent = obj:get_luaentity() + + if ent and ent._cmi_is_mob then + + -- calculate loudness of sound to mob + op_params.distance = get_distance(op_params.pos, obj:get_pos()) + op_params.loudness = op_params.gain / op_params.distance + + -- run custom mob on_punch with sound information table + ent:on_punch("sound", 0, op_params) + end + end + end + + return old_sound_play(spec, param, eph) +end +end diff --git a/api.txt b/api.txt index 6590a35..b4b1c78 100644 --- a/api.txt +++ b/api.txt @@ -345,6 +345,15 @@ enhance mob functionality and have them do many interesting things: active and which has access to all of the self.* variables e.g. (self.health for health or self.standing_in for node status), return with 'false' to skip remainder of mob API. + 'on_sound' (self, def) called when mob is inside the hearing distance of + a sound, passes a def table containing: + 'sound' the sound being played, + 'pos' position sound originated, + 'gain' original gain of sound, + 'distance' distance of mob from sound source, + 'loudness' how loud sound is to mob when calculating gain / distance, + 'player' player name sound originated, + 'object' object reference sound originated Internal Variables @@ -819,6 +828,7 @@ External Settings for "minetest.conf" 'mobs_drop_items' when false mobs no longer drop items when they die. 'mobs_griefing' when false mobs cannot break blocks when using either pathfinding level 2, replace functions or mobs:boom + 'mobs_can_hear' True by default, allows mobs to hear sound around them. function. 'mob_nospawn_range' Minimum range a mob can spawn near player (def: 12) 'mob_active_limit' Number of active mobs in game, 0 for unlimited diff --git a/settingtypes.txt b/settingtypes.txt index fcec162..1726bbb 100644 --- a/settingtypes.txt +++ b/settingtypes.txt @@ -60,6 +60,9 @@ mob_height_fix (Fix Mob Height) bool true mob_log_spawn (Log Mob Spawning) bool false +# Mob hearing, when enabled will override minetest.sound_play for mobs to hear +mobs_can_hear (Enable Mob hearing) bool true + [Pathfinding] # Enable pathfinding (default Enabled) mob_pathfinding_enable (Enable pathfinding) bool true