From 3870f38e8792f3e5d10a30de3245afe3779616c0 Mon Sep 17 00:00:00 2001 From: nixnoxus Date: Sun, 25 Feb 2024 10:45:02 +0100 Subject: [PATCH 1/6] mobs definition.runaway_from can also contain node names --- mods/ENTITIES/mcl_mobs/api.txt | 2 +- mods/ENTITIES/mcl_mobs/movement.lua | 72 ++++++++++++++--------------- 2 files changed, 35 insertions(+), 39 deletions(-) diff --git a/mods/ENTITIES/mcl_mobs/api.txt b/mods/ENTITIES/mcl_mobs/api.txt index fe0da4be2..c3bb985e9 100644 --- a/mods/ENTITIES/mcl_mobs/api.txt +++ b/mods/ENTITIES/mcl_mobs/api.txt @@ -128,7 +128,7 @@ functions needed for the mob to work properly which contains the following: arrow/fireball appears on mob. 'specific_attack' has a table of entity names that mob can also attack e.g. {"player", "mobs_animal:chicken"}. - 'runaway_from' contains a table with mob names to run away from, add + 'runaway_from' contains a table with mob/node names to run away from, add "player" to list to runaway from player also. 'pathfinding' set to 1 for mobs to use pathfinder feature to locate player, set to 2 so they can build/break also (only diff --git a/mods/ENTITIES/mcl_mobs/movement.lua b/mods/ENTITIES/mcl_mobs/movement.lua index ff9a38f56..48450af2f 100644 --- a/mods/ENTITIES/mcl_mobs/movement.lua +++ b/mods/ENTITIES/mcl_mobs/movement.lua @@ -595,15 +595,6 @@ end -- specific runaway local specific_runaway = function(list, what) - if type(list) ~= "table" then - list = {} - end - - -- no list so do not run - if list == nil then - return false - end - -- found entity on list to attack? for no = 1, #list do @@ -621,33 +612,37 @@ function mob_class:check_runaway_from() if not self.runaway_from and self.state ~= "flop" then return end + if type(self.runaway_from) ~= "table" then + return + end local s = self.object:get_pos() - local p, sp, dist - local player, obj, min_player - local type, name = "", "" local min_dist = self.view_range + 1 local objs = minetest.get_objects_inside_radius(s, self.view_range) + local runaway_pos = nil for n = 1, #objs do + local name = "" + local player if objs[n]:is_player() then - if mcl_mobs.invis[ objs[n]:get_player_name() ] + if not (mcl_mobs.invis[ objs[n]:get_player_name() ] or self.owner == objs[n]:get_player_name() - or (not self:object_in_range(objs[n])) then - type = "" - else + or (not self:object_in_range(objs[n]))) then player = objs[n] - type = "player" name = "player" + if not (name ~= self.name + and specific_runaway(self.runaway_from, name)) then + local item = player:get_wielded_item() + name = item:get_name() or "" + end end else - obj = objs[n]:get_luaentity() + local obj = objs[n]:get_luaentity() if obj then player = obj.object - type = obj.type name = obj.name or "" end end @@ -656,37 +651,38 @@ function mob_class:check_runaway_from() if name ~= "" and name ~= self.name and specific_runaway(self.runaway_from, name) then - p = player:get_pos() - sp = s - - -- aim higher to make looking up hills more realistic - p.y = p.y + 1 - sp.y = sp.y + 1 - - dist = vector.distance(p, s) - + local p = player:get_pos() + local dist = vector.distance(p, s) -- choose closest player/mpb to runaway from if dist < min_dist - and self:line_of_sight(sp, p, 2) == true then + -- aim higher to make looking up hills more realistic + and self:line_of_sight(vector.offset(s, 0,1,0), vector.offset(p, 0,1,0), 2) == true then min_dist = dist - min_player = player + runaway_pos = p end end end - if min_player then + if not runaway_pos then - local lp = player:get_pos() - local vec = { - x = lp.x - s.x, - y = lp.y - s.y, - z = lp.z - s.z - } + -- find specific node to runaway from + local p = minetest.find_node_near(s, self.view_range, self.runaway_from, true) + local dist = p and vector.distance(p, s) + if dist and dist < min_dist + --and minetest.line_of_sight(s, p) == true then + and self:line_of_sight(s, p) == true then + min_dist = dist + runaway_pos = p + end + end + if runaway_pos then + + local vec = vector.subtract(runaway_pos, s) local yaw = (atan(vec.z / vec.x) + 3 *math.pi/ 2) - self.rotate - if lp.x > s.x then + if runaway_pos.x > s.x then yaw = yaw + math.pi end From 4dcffc0d5a1be867ff86c26ba74b2351ee5f0b2c Mon Sep 17 00:00:00 2001 From: nixnoxus Date: Sun, 25 Feb 2024 10:49:01 +0100 Subject: [PATCH 2/6] add hoglin breeding and flee from warped_fungus and respawn_anchor --- mods/ENTITIES/mobs_mc/hoglin+zoglin.lua | 29 ++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/mods/ENTITIES/mobs_mc/hoglin+zoglin.lua b/mods/ENTITIES/mobs_mc/hoglin+zoglin.lua index 08f9a46ad..552cd5fad 100644 --- a/mods/ENTITIES/mobs_mc/hoglin+zoglin.lua +++ b/mods/ENTITIES/mobs_mc/hoglin+zoglin.lua @@ -40,6 +40,16 @@ local hoglin = { makes_footstep_sound = true, walk_velocity = 1, run_velocity = 2.8, + runaway_from = { + "mcl_crimson:warped_fungus", + "mcl_flowerpots:flower_pot_warped_fungus", + "mcl_beds:respawn_anchor", + "mcl_beds:respawn_anchor_charged_1", + "mcl_beds:respawn_anchor_charged_2", + "mcl_beds:respawn_anchor_charged_3", + "mcl_beds:respawn_anchor_charged_4", + }, + follow = {"mcl_crimson:crimson_fungus"}, drops = { {name = "mobs_mcitems:leather", chance = 1, @@ -87,9 +97,26 @@ local hoglin = { attack_animals = true, } -mcl_mobs.register_mob("mobs_mc:hoglin", hoglin) local zoglin = table.copy(hoglin) +hoglin.on_rightclick = function(self, clicker) + -- local item = clicker:get_wielded_item() + if self:feed_tame(clicker, 1, true, false) then return end + -- if mcl_mobs:protect(self, clicker) then return end +end +hoglin.on_breed = function(parent1, parent2) + local pos = parent1.object:get_pos() + local child = mcl_mobs.spawn_child(pos, parent1.name) + if child then + local ent_c = child:get_luaentity() + -- ent_c.tamed = true + ent_c.owner = parent1.owner + return false + end +end, + +mcl_mobs.register_mob("mobs_mc:hoglin", hoglin) + zoglin.description = S("Zoglin") zoglin.fire_resistant = 1 zoglin.textures = {"extra_mobs_zoglin.png"} From 105a702931f3d24ee01721325498540004d2dbfc Mon Sep 17 00:00:00 2001 From: nixnoxus Date: Sun, 25 Feb 2024 17:54:55 +0100 Subject: [PATCH 3/6] add mob_class:avoid_from and mob_class:is_object_in_view() --- mods/ENTITIES/mcl_mobs/api.txt | 15 ++- mods/ENTITIES/mcl_mobs/init.lua | 1 + mods/ENTITIES/mcl_mobs/movement.lua | 199 +++++++++++++--------------- 3 files changed, 104 insertions(+), 111 deletions(-) diff --git a/mods/ENTITIES/mcl_mobs/api.txt b/mods/ENTITIES/mcl_mobs/api.txt index c3bb985e9..3356dca05 100644 --- a/mods/ENTITIES/mcl_mobs/api.txt +++ b/mods/ENTITIES/mcl_mobs/api.txt @@ -262,7 +262,10 @@ functions needed for the mob to work properly which contains the following: 'custom_visual_size' will not reset visual_size from the base class on reload 'noyaw' If true this mob will not automatically change yaw 'particlespawners' Table of particlespawners attached to the mob. This is implemented in a coord safe manner i.e. spawners are only sent to players within the player_transfer_distance (and automatically removed). This enables infinitely lived particlespawners. - 'attack_frequency' Attack frequency in seconds. If unset, this defaults to 1. Implemented for melee only atm. + 'attack_frequency' Attack frequency in seconds. If unset, this defaults to 1. Implemented for melee only atm. + 'avoid_from' contains a table with mob/node names to avoid from, add + "player" to list to avoid from player also. + mobs:gopath(self,target,callback_arrived) pathfind a way to target and run callback on arrival @@ -449,6 +452,16 @@ Create death particles at pos with the given collisionbox. mcl_mobs.spawn(pos,name/entity name) + +mcl_mobs:is_object_in_view(object_list, object_range, node_range, turn_around) + +Returns 'true' if an object (mob or node) is in the field of view. + + 'object_list' list of mob and/or node names + 'object_range' maximum distance to a mob from object_list + 'node_range' maximum distance to a node from object_list + 'turn_around' true or false + Making Arrows ------------- diff --git a/mods/ENTITIES/mcl_mobs/init.lua b/mods/ENTITIES/mcl_mobs/init.lua index fb39fa151..c981e6a86 100644 --- a/mods/ENTITIES/mcl_mobs/init.lua +++ b/mods/ENTITIES/mcl_mobs/init.lua @@ -289,6 +289,7 @@ function mcl_mobs.register_mob(name, def) noyaw = def.noyaw or false, particlespawners = def.particlespawners, spawn_check = def.spawn_check, + avoid_from = def.avoid_from, -- End of MCL2 extensions on_spawn = def.on_spawn, on_blast = def.on_blast or function(self,damage) diff --git a/mods/ENTITIES/mcl_mobs/movement.lua b/mods/ENTITIES/mcl_mobs/movement.lua index 48450af2f..a7aa7f756 100644 --- a/mods/ENTITIES/mcl_mobs/movement.lua +++ b/mods/ENTITIES/mcl_mobs/movement.lua @@ -509,6 +509,81 @@ function mob_class:do_jump() return false end +local function in_list(list, what) + return type(list) == "table" and table.indexof(list, what) ~= -1 +end + +function mob_class:is_object_in_view(object_list, object_range, node_range, turn_around) + local s = self.object:get_pos() + local min_dist = object_range + 1 + local objs = minetest.get_objects_inside_radius(s, object_range) + local object_pos = nil + + for n = 1, #objs do + local name = "" + local object = objs[n] + + if object:is_player() then + if not (mcl_mobs.invis[ object:get_player_name() ] + or self.owner == object:get_player_name() + or (not self:object_in_range(object))) then + name = "player" + if not (name ~= self.name + and in_list(object_list, name)) then + local item = object:get_wielded_item() + name = item:get_name() or "" + end + end + else + local obj = object:get_luaentity() + + if obj then + object = obj.object + name = obj.name or "" + end + end + + -- find specific mob to avoid or runaway from + if name ~= "" and name ~= self.name + and in_list(object_list, name) then + + local p = object:get_pos() + local dist = vector.distance(p, s) + + -- choose closest player/mob to avoid or runaway from + if dist < min_dist + -- aim higher to make looking up hills more realistic + and self:line_of_sight(vector.offset(s, 0,1,0), vector.offset(p, 0,1,0)) == true then + min_dist = dist + object_pos = p + end + end + end + + if not object_pos then + + -- find specific node to avoid or runaway from + local p = minetest.find_node_near(s, node_range, object_list, true) + local dist = p and vector.distance(p, s) + if dist and dist < min_dist + and self:line_of_sight(s, p) == true then + min_dist = dist + object_pos = p + end + end + + if object_pos and turn_around then + + local vec = vector.subtract(object_pos, s) + yaw = (atan(vec.z / vec.x) + 3 *math.pi/ 2) - self.rotate + if object_pos.x > s.x then yaw = yaw + math.pi end + + yaw = self:set_yaw(yaw, 4) + end + + return object_pos ~= nil +end + -- should mob follow what I'm holding ? function mob_class:follow_holding(clicker) if self.nofollow then return false end @@ -526,14 +601,8 @@ function mob_class:follow_holding(clicker) return true -- multiple items - elseif t == "table" then - - for no = 1, #self.follow do - - if self.follow[no] == item:get_name() then - return true - end - end + elseif t == "table" and in_list(self.follow, item:get_name()) then + return true end return false @@ -593,100 +662,13 @@ function mob_class:replace_node(pos) end end --- specific runaway -local specific_runaway = function(list, what) - -- found entity on list to attack? - for no = 1, #list do - - if list[no] == what then - return true - end - end - - return false -end - - -- find someone to runaway from function mob_class:check_runaway_from() if not self.runaway_from and self.state ~= "flop" then return end - if type(self.runaway_from) ~= "table" then - return - end - local s = self.object:get_pos() - local min_dist = self.view_range + 1 - local objs = minetest.get_objects_inside_radius(s, self.view_range) - local runaway_pos = nil - - for n = 1, #objs do - local name = "" - local player - - if objs[n]:is_player() then - - if not (mcl_mobs.invis[ objs[n]:get_player_name() ] - or self.owner == objs[n]:get_player_name() - or (not self:object_in_range(objs[n]))) then - player = objs[n] - name = "player" - if not (name ~= self.name - and specific_runaway(self.runaway_from, name)) then - local item = player:get_wielded_item() - name = item:get_name() or "" - end - end - else - local obj = objs[n]:get_luaentity() - - if obj then - player = obj.object - name = obj.name or "" - end - end - - -- find specific mob to runaway from - if name ~= "" and name ~= self.name - and specific_runaway(self.runaway_from, name) then - - local p = player:get_pos() - local dist = vector.distance(p, s) - - -- choose closest player/mpb to runaway from - if dist < min_dist - -- aim higher to make looking up hills more realistic - and self:line_of_sight(vector.offset(s, 0,1,0), vector.offset(p, 0,1,0), 2) == true then - min_dist = dist - runaway_pos = p - end - end - end - - if not runaway_pos then - - -- find specific node to runaway from - local p = minetest.find_node_near(s, self.view_range, self.runaway_from, true) - local dist = p and vector.distance(p, s) - if dist and dist < min_dist - --and minetest.line_of_sight(s, p) == true then - and self:line_of_sight(s, p) == true then - min_dist = dist - runaway_pos = p - end - end - - if runaway_pos then - - local vec = vector.subtract(runaway_pos, s) - local yaw = (atan(vec.z / vec.x) + 3 *math.pi/ 2) - self.rotate - - if runaway_pos.x > s.x then - yaw = yaw + math.pi - end - - yaw = self:set_yaw( yaw, 4) + if self:is_object_in_view(self.runaway_from, self.view_range, self.view_range / 2, true) then self.state = "runaway" self.runaway_timer = 3 self.following = nil @@ -910,23 +892,19 @@ function mob_class:do_states_walk() end end - - -- A danger is near but mob is not inside - else - - -- Randomly turn - if math.random(1, 100) <= 30 then - yaw = yaw + math.random(-0.5, 0.5) - yaw = self:set_yaw( yaw, 8) - end end + end - yaw = self:set_yaw( yaw, 8) - + if not is_in_danger then + local distance = self.avoid_distance or self.view_range / 2 + -- find specific node to avoid + if self:is_object_in_view(self.avoid_from, distance, distance, true) then + self:set_velocity(self.walk_velocity) -- otherwise randomly turn - elseif math.random(1, 100) <= 30 then - yaw = yaw + math.random(-0.5, 0.5) - yaw = self:set_yaw( yaw, 8) + elseif math.random(1, 100) <= 30 then + yaw = yaw + math.random(-0.5, 0.5) + yaw = self:set_yaw(yaw, 8) + end end -- stand for great fall or danger or fence in front @@ -934,6 +912,7 @@ function mob_class:do_states_walk() if is_in_danger then cliff_or_danger = self:is_at_cliff_or_danger() end + if self.facing_fence == true or cliff_or_danger or math.random(1, 100) <= 30 then From 078f5d760b15fdfe41d9ce32129cf421fa3df3e8 Mon Sep 17 00:00:00 2001 From: nixnoxus Date: Sun, 25 Feb 2024 17:56:08 +0100 Subject: [PATCH 4/6] change `runaway_from` to `avoid_from` --- mods/ENTITIES/mobs_mc/hoglin+zoglin.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mods/ENTITIES/mobs_mc/hoglin+zoglin.lua b/mods/ENTITIES/mobs_mc/hoglin+zoglin.lua index 552cd5fad..e3bcf5e8c 100644 --- a/mods/ENTITIES/mobs_mc/hoglin+zoglin.lua +++ b/mods/ENTITIES/mobs_mc/hoglin+zoglin.lua @@ -40,9 +40,10 @@ local hoglin = { makes_footstep_sound = true, walk_velocity = 1, run_velocity = 2.8, - runaway_from = { + avoid_from = { "mcl_crimson:warped_fungus", "mcl_flowerpots:flower_pot_warped_fungus", + "mcl_portals:portal", "mcl_beds:respawn_anchor", "mcl_beds:respawn_anchor_charged_1", "mcl_beds:respawn_anchor_charged_2", From 8d0c3cd1377cb5df966847598f50837fd9c04f87 Mon Sep 17 00:00:00 2001 From: nixnoxus Date: Mon, 26 Feb 2024 04:30:40 +0100 Subject: [PATCH 5/6] tremble for 2s when avoiding and 5s when fleeing --- mods/ENTITIES/mcl_mobs/movement.lua | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mods/ENTITIES/mcl_mobs/movement.lua b/mods/ENTITIES/mcl_mobs/movement.lua index a7aa7f756..d76add92f 100644 --- a/mods/ENTITIES/mcl_mobs/movement.lua +++ b/mods/ENTITIES/mcl_mobs/movement.lua @@ -669,6 +669,7 @@ function mob_class:check_runaway_from() end if self:is_object_in_view(self.runaway_from, self.view_range, self.view_range / 2, true) then + self.shaking = self.shaking or 5 self.state = "runaway" self.runaway_timer = 3 self.following = nil @@ -899,6 +900,7 @@ function mob_class:do_states_walk() local distance = self.avoid_distance or self.view_range / 2 -- find specific node to avoid if self:is_object_in_view(self.avoid_from, distance, distance, true) then + self.shaking = self.shaking or 2 self:set_velocity(self.walk_velocity) -- otherwise randomly turn elseif math.random(1, 100) <= 30 then @@ -1061,6 +1063,12 @@ function mob_class:check_smooth_rotation(dtime) self.delay = self.delay - 1 if self.shaking then yaw = yaw + (math.random() * 2 - 1) * 5 * dtime + if type(self.shaking) == "number" then + self.shaking = self.shaking - dtime + if self.shaking <= 0 then + self.shaking = nil + end + end end self.object:set_yaw(yaw) --self:update_roll() From ecd62dbba1848a78b440ab45025dfd0bffa05fa0 Mon Sep 17 00:00:00 2001 From: nixnoxus Date: Sun, 3 Mar 2024 10:12:31 +0100 Subject: [PATCH 6/6] fix warning --- mods/ENTITIES/mcl_mobs/movement.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ENTITIES/mcl_mobs/movement.lua b/mods/ENTITIES/mcl_mobs/movement.lua index d76add92f..d2a5ee69c 100644 --- a/mods/ENTITIES/mcl_mobs/movement.lua +++ b/mods/ENTITIES/mcl_mobs/movement.lua @@ -575,7 +575,7 @@ function mob_class:is_object_in_view(object_list, object_range, node_range, turn if object_pos and turn_around then local vec = vector.subtract(object_pos, s) - yaw = (atan(vec.z / vec.x) + 3 *math.pi/ 2) - self.rotate + local yaw = (atan(vec.z / vec.x) + 3 *math.pi/ 2) - self.rotate if object_pos.x > s.x then yaw = yaw + math.pi end yaw = self:set_yaw(yaw, 4)