diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index 4a4a56bb..0cf10941 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -300,6 +300,11 @@ end -- Returns true is node can deal damage to self local is_node_dangerous = function(self, nodename) local nn = nodename + if self.fly then + if not minetest.get_item_group(nn, self.fly_in) then + return true + end + end if self.water_damage > 0 then if minetest.get_item_group(nn, "water") ~= 0 then return true @@ -317,7 +322,10 @@ local is_node_dangerous = function(self, nodename) end if minetest.registered_nodes[nn].drowning > 0 then if self.breath_max ~= -1 then - return true + -- check if the mob is water-breathing _and_ the block is water; only return true if neither is the case + if not self.breathes_in_water and minetest.get_item_group(nn, "water") ~= 0 then + return true + end end end if minetest.registered_nodes[nn].damage_per_second > 0 then @@ -2013,8 +2021,12 @@ local do_states = function(self, dtime) if (self.water_damage > 0 and self.lava_damage > 0) or self.breath_max ~= -1 then - - lp = minetest.find_node_near(s, 1, {"group:water", "group:lava"}) + -- water-breathing mobs don't have to avoid water, but air + if self.breathes_in_water then + lp = minetest.find_node_near(s, 1, {"air", "group:lava"}) + else + lp = minetest.find_node_near(s, 1, {"group:water", "group:lava"}) + end elseif self.water_damage > 0 then @@ -2032,34 +2044,60 @@ local do_states = function(self, dtime) local is_in_danger = false if lp then - -- If mob in or on dangerous block, look for land - if (is_node_dangerous(self, self.standing_in) or + -- minetest.log(self.name .. ": " .. minetest.get_node(lp).name) + -- if mob is flying, only check the block it is inside + if self.fly then + if is_node_dangerous(self, self.standing_in) then + is_in_danger = true + end + elseif not self.fly and (is_node_dangerous(self, self.standing_in) or is_node_dangerous(self, self.standing_on)) then is_in_danger = true - + end + -- If mob in or on dangerous block, look for land + if is_in_danger then + -- minetest.log(self.name .. " is in/on dangerous node " .. self.standing_on .. " or " .. self.standing_in) lp = minetest.find_node_near(s, 5, {"group:solid"}) -- did we find land? if lp then local nn = minetest.get_node(lp).name - if is_node_dangerous(self, nn) then - -- is the chosen destination safe? Retry if not (max 10 iterations) - local i = 0 - while i < 10 do - if lp then - nn = minetest.get_node(lp).name - minetest.log("Found solid block: " .. nn) - if not is_node_dangerous(self, nn) then break + -- minetest.log(self.name .. " found land: " .. nn) + + -- is the chosen destination safe and walkable? Retry if not (max 10 iterations) + local i = 0 + local max_i = 10 + while i < max_i do + local node_above_ok = false + if lp then + nn = minetest.get_node(lp).name + local pos = {x = lp.x, y = lp.y + 2, z = lp.z} + local node_above = minetest.get_node(pos) + local nn_above = node_above.name + + minetest.log("Node: " .. nn .. " Node above: " .. nn_above) + if self.breath_max ~= -1 then + -- water-breathing mobs don't have to avoid water, but air + if self.breathes_in_water and minetest.get_item_group(nn_above, "water") then + node_above_ok = true + elseif not self.breathes_in_water and nn_above == "air" then + node_above_ok = true + end + else + node_above_ok = true end - -- look for solid node 5 blocks around the mob's position - elseif i < 5 then - lp = minetest.find_node_near(s, 5, {"group:solid"}) - -- after 5 iterations double search radius - elseif i < 10 then - lp = minetest.find_node_near(s, 10, {"group:solid"}) - end - i = i + 1 + if not is_node_dangerous(self, nn) and minetest.registered_nodes[nn].walkable and node_above_ok then + minetest.log(self.name .. ": Found solid block: " .. nn .. " Above: " .. nn_above) + break end + -- look for solid node 5 blocks around the mob's position + elseif i < (max_i / 2) then + lp = minetest.find_node_near(s, 5, {"group:solid"}) + -- after 5 iterations double search radius + elseif i < max_i then + lp = minetest.find_node_near(s, 10, {"group:solid"}) + end + i = i + 1 end local vec = {