From 79f5afe0f6da6cf830c28e0c21a58f3561ca5458 Mon Sep 17 00:00:00 2001 From: cora Date: Sun, 11 Sep 2022 19:40:16 +0200 Subject: [PATCH] Implement shulker teleportation --- mods/ENTITIES/mobs_mc/shulker.lua | 81 ++++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/mods/ENTITIES/mobs_mc/shulker.lua b/mods/ENTITIES/mobs_mc/shulker.lua index 6e12146f2..01712f03d 100644 --- a/mods/ENTITIES/mobs_mc/shulker.lua +++ b/mods/ENTITIES/mobs_mc/shulker.lua @@ -9,8 +9,26 @@ local S = minetest.get_translator("mobs_mc") --################### SHULKER --################### +local adjacents = { + vector.new(1,0,0), + vector.new(-1,0,0), + vector.new(0,1,0), + vector.new(0,-1,0), + vector.new(0,0,1), + vector.new(0,0,-1), +} +local function check_spot(pos) + local n = minetest.get_node(pos) + if n.name~="air" then return false end + for _,a in pairs(adjacents) do + local p = vector.add(pos,a) + local pn = minetest.get_node(p) + if minetest.get_item_group(pn.name,"solid") > 0 then return true end + end + return false +end +local pr = PseudoRandom(os.time()*(-334)) -- animation 45-80 is transition between passive and attack stance - mcl_mobs:register_mob("mobs_mc:shulker", { description = S("Shulker"), type = "monster", @@ -35,6 +53,8 @@ mcl_mobs:register_mob("mobs_mc:shulker", { walk_chance = 0, knock_back = false, jump = false, + can_despawn = false, + fall_speed = 0, drops = { {name = "mcl_mobitems:shulker_shell", chance = 2, @@ -55,6 +75,7 @@ mcl_mobs:register_mob("mobs_mc:shulker", { fear_height = 0, noyaw = true, do_custom = function(self,dtime) + local pos = self.object:get_pos() if math.floor(self.object:get_yaw()) ~=0 then self.object:set_yaw(0) mcl_mobs:yaw(self, 0, 0, dtime) @@ -68,6 +89,64 @@ mcl_mobs:register_mob("mobs_mc:shulker", { end self.path.way = false self.look_at_players = false + if not check_spot(pos) then + self:teleport(nil) + end + end, + do_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir, damage) + self:teleport(puncher) + end, + do_teleport = function(self, target) + if target ~= nil then + local target_pos = target:get_pos() + -- Find all solid nodes below air in a 10×10×10 cuboid centered on the target + local nodes = minetest.find_nodes_in_area_under_air(vector.subtract(target_pos, 5), vector.add(target_pos, 5), {"group:solid", "group:cracky", "group:crumbly"}) + local telepos + if nodes ~= nil then + if #nodes > 0 then + -- Up to 64 attempts to teleport + for n=1, math.min(64, #nodes) do + local r = pr:next(1, #nodes) + local nodepos = nodes[r] + local tg = vector.offset(nodepos,0,1,0) + if check_spot(tg) then + telepos = tg + node_ok = true + end + end + if telepos then + self.object:set_pos(telepos) + end + end + end + else + local pos = self.object:get_pos() + -- Up to 8 top-level attempts to teleport + for n=1, 8 do + local node_ok = false + -- We need to add (or subtract) different random numbers to each vector component, so it couldn't be done with a nice single vector.add() or .subtract(): + local randomCube = vector.new( pos.x + 8*(pr:next(0,16)-8), pos.y + 8*(pr:next(0,16)-8), pos.z + 8*(pr:next(0,16)-8) ) + local nodes = minetest.find_nodes_in_area_under_air(vector.subtract(randomCube, 4), vector.add(randomCube, 4), {"group:solid", "group:cracky", "group:crumbly"}) + if nodes ~= nil then + if #nodes > 0 then + -- Up to 8 low-level (in total up to 8*8 = 64) attempts to teleport + for n=1, math.min(8, #nodes) do + local r = pr:next(1, #nodes) + local nodepos = nodes[r] + local tg = vector.offset(nodepos,0,1,0) + if check_spot(tg) then + self.object:set_pos(tg) + node_ok = true + break + end + end + end + end + if node_ok then + break + end + end + end end, })