diff options
| author | Beha <shacknetisp@mail.com> | 2017-03-22 09:15:17 -0400 | 
|---|---|---|
| committer | Beha <shacknetisp@mail.com> | 2017-03-22 09:15:17 -0400 | 
| commit | df542c5a167906dfcfc5a23d4b9b5318d1481f5d (patch) | |
| tree | d7c77072388555a5a8bbf81b641babbc2907c3d9 | |
| parent | 79fe50056d56c7001c7cf2cf7ea85ebb683e00e4 (diff) | |
More cleanups, minor fixes.
| -rw-r--r-- | depends.txt | 1 | ||||
| -rw-r--r-- | init.lua | 401 | 
2 files changed, 231 insertions, 171 deletions
| diff --git a/depends.txt b/depends.txt index 87ab59d..175eea5 100644 --- a/depends.txt +++ b/depends.txt @@ -1,3 +1,4 @@  default  technic? +homedecor?  chains? @@ -1,10 +1,16 @@ +-- Initial speed of a box.  local SPEED = 10 +-- Acceleration of a box.  local ACCEL = 0.1 +-- Elevator interface/database version.  local VERSION = 8 +-- Maximum time a box can go without players nearby.  local PTIMEOUT = 120 +-- Detect optional mods.  local technic_path = minetest.get_modpath("technic")  local chains_path = minetest.get_modpath("chains") +local homedecor = minetest.get_modpath("homedecor")  -- Central "network" table.  local elevator = { @@ -49,27 +55,35 @@ local function get_node(pos)      return minetest.get_node_or_nil(pos)  end --- Placeholder node, in the style of homedecor. -local placeholder = "elevator:placeholder" -minetest.register_node(placeholder, { -    description = "Expansion placeholder (you hacker you!)", -    selection_box = { type = "fixed", fixed = { 0, 0, 0, 0, 0, 0 } }, -    groups = { -        not_in_creative_inventory=1 -    }, -    drawtype = "airlike", -    paramtype = "light", -    sunlight_propagates = true, +-- Use homedecor's placeholder if possible. +local placeholder = homedecor and "homedecor:expansion_placeholder" or "elevator:placeholder" +if homedecor then +    minetest.register_alias("elevator:placeholder", "homedecor:expansion_placeholder") +else +    -- Placeholder node, in the style of homedecor. +    minetest.register_node(placeholder, { +        description = "Expansion Placeholder", +        selection_box = { +            type = "fixed", +            fixed = {0, 0, 0, 0, 0, 0}, +        }, +        groups = { +            not_in_creative_inventory=1 +        }, +        drawtype = "airlike", +        paramtype = "light", +        sunlight_propagates = true, -    walkable = false, -    buildable_to = false, -    is_ground_content = false, +        walkable = false, +        buildable_to = false, +        is_ground_content = false, -    on_dig = function(pos, node, player) -        minetest.remove_node(pos) -        minetest.set_node(pos, {name=placeholder}) -    end -}) +        on_dig = function(pos, node, player) +            minetest.remove_node(pos) +            minetest.set_node(pos, {name=placeholder}) +        end +    }) +end  -- Cause <sender> to ride <motorhash> beginning at <pos> and targetting <target>.  local function create_box(motorhash, pos, target, sender) @@ -112,10 +126,12 @@ local function teleport_player_from_elevator(player)      end      local pos = vector.round(player:getpos())      local node = minetest.get_node(pos) +    -- elevator_off is like a shaft, so the player would already be falling.      if node.name == "elevator:elevator_on" then          local front = vector.subtract(pos, minetest.facedir_to_dir(node.param2))          local front_above = vector.add(front, {x=0, y=1, z=0})          local front_below = vector.subtract(front, {x=0, y=1, z=0}) +        -- If the front isn't solid, it's ok to teleport the player.          if not solid(front) and not solid(front_above) then              player:setpos(front)          end @@ -123,6 +139,7 @@ local function teleport_player_from_elevator(player)  end  minetest.register_globalstep(function(dtime) +    -- Don't want to run this too often.      time = time + dtime      if time < 0.5 then          return @@ -132,9 +149,11 @@ minetest.register_globalstep(function(dtime)      local newriding = {}      for _,p in ipairs(minetest.get_connected_players()) do          local pos = p:getpos() -        newriding[p:get_player_name()] = riding[p:get_player_name()] -        if newriding[p:get_player_name()] then -            newriding[p:get_player_name()].pos = pos +        local name = p:get_player_name() +        newriding[name] = riding[name] +        -- If the player is indeed riding, update their position. +        if newriding[name] then +            newriding[name].pos = pos          end      end      riding = newriding @@ -181,6 +200,10 @@ local function phash(pos)      return minetest.pos_to_string(pos)  end +local function punhash(pos) +    return minetest.string_to_pos(pos) +end +  -- Starting from <pos>, locate a motor hash.  local function locate_motor(pos)      local p = vector.new(pos) @@ -201,11 +224,13 @@ end  local function build_motor(hash)      local need_saving = false      local motor = elevator.motors[hash] +    -- Just ignore motors that don't exist.      if not motor then          return      end -    local p = minetest.string_to_pos(hash) +    local p = punhash(hash)      local node = get_node(p) +    -- And ignore motors that aren't motors.      if node.name ~= "elevator:motor" then          return      end @@ -234,7 +259,7 @@ local function build_motor(hash)      end      -- Set the elevators fully.      for i,m in ipairs(motor.elevators) do -        local pos = minetest.string_to_pos(m) +        local pos = punhash(m)          local meta = minetest.get_meta(pos)          meta:set_int("version", VERSION)          if meta:get_string("motor") ~= hash then @@ -255,6 +280,7 @@ local function unbuild(pos, add)      local need_saving = false      local p = table.copy(pos)      p.y = p.y - 1 +    -- Loop down through the network, set any elevators below this to the off position.      while true do          local node = get_node(p)          if node.name == "elevator:shaft" then @@ -303,6 +329,7 @@ minetest.register_node("elevator:motor", {      groups = {cracky=1},      sounds = default.node_sound_stone_defaults(),      after_place_node = function(pos, placer, itemstack) +        -- Set up the motor table.          elevator.motors[phash(pos)] = {              elevators = {},              pnames = {}, @@ -312,6 +339,7 @@ minetest.register_node("elevator:motor", {          build_motor(phash(pos))      end,      on_destruct = function(pos) +        -- Destroy everything related to this motor.          boxes[phash(pos)] = nil          elevator.motors[phash(pos)] = nil          save_elevator() @@ -319,154 +347,164 @@ minetest.register_node("elevator:motor", {  })  for _,mode in ipairs({"on", "off"}) do -local nodename = "elevator:elevator_"..mode -local on = (mode == "on") -local box -local cbox -if on then -    box = { - -        { 0.48, -0.5,-0.5,  0.5,  1.5, 0.5}, -        {-0.5 , -0.5, 0.48, 0.48, 1.5, 0.5}, -        {-0.5,  -0.5,-0.5 ,-0.48, 1.5, 0.5}, - -        { -0.5,-0.5,-0.5,0.5,-0.48, 0.5}, -        { -0.5, 1.45,-0.5,0.5, 1.5, 0.5}, -    } -    cbox = table.copy(box) -    cbox[5] = nil -else -    box = { +    local nodename = "elevator:elevator_"..mode +    local on = (mode == "on") +    local box +    local cbox +    if on then +        -- Active elevators have a ceiling and floor. +        box = { + +            { 0.48, -0.5,-0.5,  0.5,  1.5, 0.5}, +            {-0.5 , -0.5, 0.48, 0.48, 1.5, 0.5}, +            {-0.5,  -0.5,-0.5 ,-0.48, 1.5, 0.5}, + +            { -0.5,-0.5,-0.5,0.5,-0.48, 0.5}, +            { -0.5, 1.45,-0.5,0.5, 1.5, 0.5}, +        } +        cbox = table.copy(box) +        -- But you can enter them from the top. +        cbox[5] = nil +    else +        -- Inactive elevators are almost like shafts. +        box = { + +            { 0.48, -0.5,-0.5,  0.5,  1.5, 0.5}, +            {-0.5 , -0.5, 0.48, 0.48, 1.5, 0.5}, +            {-0.5,  -0.5,-0.5 ,-0.48, 1.5, 0.5}, +            {-0.5 , -0.5, -0.48, 0.5, 1.5, -0.5}, +        } +        cbox = box +    end +    minetest.register_node(nodename, { +        description = "Elevator", +        drawtype = "nodebox", +        sunlight_propagates = false, +        paramtype = "light", +        paramtype2 = "facedir", +        on_rotate = screwdriver.disallow, + +        selection_box = { +                type = "fixed", +                fixed = box, +        }, -        { 0.48, -0.5,-0.5,  0.5,  1.5, 0.5}, -        {-0.5 , -0.5, 0.48, 0.48, 1.5, 0.5}, -        {-0.5,  -0.5,-0.5 ,-0.48, 1.5, 0.5}, -        {-0.5 , -0.5, -0.48, 0.5, 1.5, -0.5}, -    } -    cbox = box -end -minetest.register_node(nodename, { -    description = "Elevator", -    drawtype = "nodebox", -    sunlight_propagates = false, -    paramtype = 'light', -    paramtype2 = "facedir", -    on_rotate = screwdriver.disallow, +        collision_box = { +                type = "fixed", +                fixed = cbox, +        }, -    selection_box = { -            type = "fixed", -            fixed = box, -    }, +        node_box = { +                type = "fixed", +                fixed = box, +        }, -    collision_box = { -            type = "fixed", -            fixed = cbox, -    }, +        tiles = on and { +                "default_steel_block.png", +                "default_steel_block.png", +                "elevator_box.png", +                "elevator_box.png", +                "elevator_box.png", +                "elevator_box.png", +        } or { +                "elevator_box.png", +                "elevator_box.png", +                "elevator_box.png", +                "elevator_box.png", +                "elevator_box.png", +                "elevator_box.png", +        }, +        groups = {cracky=1, choppy=1, snappy=1}, +        drop = "elevator:elevator_off", -    node_box = { -            type = "fixed", -            fixed = box, -    }, +        -- Emit a bit of light when active. +        light_source = (on and 4 or nil), -    tiles = on and { -            "default_steel_block.png", -            "default_steel_block.png", -            "elevator_box.png", -            "elevator_box.png", -            "elevator_box.png", -            "elevator_box.png", -    } or { -            "elevator_box.png", -            "elevator_box.png", -            "elevator_box.png", -            "elevator_box.png", -            "elevator_box.png", -            "elevator_box.png", -    }, -    groups = {cracky=1, choppy=1, snappy=1}, -    drop = "elevator:elevator_off", +        after_place_node  = function(pos, placer, itemstack) +            local meta = minetest.get_meta(pos) +            meta:set_int("version", VERSION) -    light_source = (on and 4 or nil), +            -- Add a placeholder to avoid nodes being placed in the top. +            local p = vector.add(pos, {x=0, y=1, z=0}) +            local p2 = minetest.dir_to_facedir(placer:get_look_dir()) +            minetest.set_node(p, {name=placeholder, paramtype2="facedir", param2=p2}) -    after_place_node  = function(pos, placer, itemstack) -        local meta = minetest.get_meta(pos) -        meta:set_int("version", VERSION) -        local p = {x=pos.x, y=pos.y+1, z=pos.z} -        local p2 = minetest.dir_to_facedir(placer:get_look_dir()) -        minetest.set_node(p, {name=placeholder, paramtype2="facedir", param2=p2}) -        local motor = locate_motor(pos) -        if motor then -            build_motor(motor) -        end -    end, - -    after_dig_node = function(pos, node, meta, digger) -        unbuild(pos, 2) -    end, +            -- Try to build a motor above. +            local motor = locate_motor(pos) +            if motor then +                build_motor(motor) +            end +        end, -    on_place = function(itemstack, placer, pointed_thing) -       local pos  = pointed_thing.above -       local node = minetest.get_node({x=pos.x, y=pos.y+1, z=pos.z}) -       if( node ~= nil and node.name ~= "air" and node.name ~= placeholder) then -          return -       end -       return minetest.item_place(itemstack, placer, pointed_thing); -    end, +        after_dig_node = function(pos, node, meta, digger) +            unbuild(pos, 2) +        end, -    on_rightclick = function(pos, node, sender) -        local meta = minetest.get_meta(pos) -        formspecs[sender:get_player_name()] = {pos} -        if on then -            if vector.distance(sender:get_pos(), pos) > 1 or minetest.get_node(sender:get_pos()).name ~= nodename then -                minetest.chat_send_player(sender:get_player_name(), "You are not inside the booth.") +        on_place = function(itemstack, placer, pointed_thing) +            local pos  = pointed_thing.above +            local node = minetest.get_node(vector.add(pos, {x=0, y=1, z=0})) +            if (node ~= nil and node.name ~= "air" and node.name ~= placeholder) then                  return              end -            -- Build the formspec from the motor table. -            local formspec -            local tpnames = {} -            local tpnames_l = {} -            local motorhash = meta:get_string("motor") -            local motor = elevator.motors[motorhash] -            for ji,jv in ipairs(motor.pnames) do -                if tonumber(jv) ~= pos.y then -                    table.insert(tpnames, jv) -                    table.insert(tpnames_l, (motor.labels[ji] and motor.labels[ji] ~= "") and (jv.." - "..motor.labels[ji]) or jv) +            return minetest.item_place(itemstack, placer, pointed_thing); +        end, + +        on_rightclick = function(pos, node, sender) +            local meta = minetest.get_meta(pos) +            formspecs[sender:get_player_name()] = {pos} +            if on then +                if vector.distance(sender:get_pos(), pos) > 1 or minetest.get_node(sender:get_pos()).name ~= nodename then +                    minetest.chat_send_player(sender:get_player_name(), "You are not inside the booth.") +                    return                  end -            end -            formspecs[sender:get_player_name()] = {pos, tpnames} -            if #tpnames > 0 then -                formspec = "size[4,6]" -                .."label[0,0;Click once to travel.]" -                .."textlist[-0.1,0.5;4,4;target;"..table.concat(tpnames_l, ",").."]" -                .."field[0.25,5.25;4,0;label;;"..minetest.formspec_escape(meta:get_string("label")).."]" -                .."button_exit[-0.05,5.5;4,1;setlabel;Set label]" -            else +                -- Build the formspec from the motor table. +                local formspec +                local tpnames = {} +                local tpnames_l = {} +                local motorhash = meta:get_string("motor") +                local motor = elevator.motors[motorhash] +                for ji,jv in ipairs(motor.pnames) do +                    if tonumber(jv) ~= pos.y then +                        table.insert(tpnames, jv) +                        table.insert(tpnames_l, (motor.labels[ji] and motor.labels[ji] ~= "") and (jv.." - "..motor.labels[ji]) or jv) +                    end +                end +                formspecs[sender:get_player_name()] = {pos, tpnames} +                if #tpnames > 0 then +                    formspec = "size[4,6]" +                    .."label[0,0;Click once to travel.]" +                    .."textlist[-0.1,0.5;4,4;target;"..table.concat(tpnames_l, ",").."]" +                    .."field[0.25,5.25;4,0;label;;"..minetest.formspec_escape(meta:get_string("label")).."]" +                    .."button_exit[-0.05,5.5;4,1;setlabel;Set label]" +                else +                    formspec = "size[4,2]" +                    .."label[0,0;No targets available.]" +                    .."field[0.25,1.25;4,0;label;;"..minetest.formspec_escape(meta:get_string("label")).."]" +                    .."button_exit[-0.05,1.5;4,1;setlabel;Set label]" +                end +                minetest.show_formspec(sender:get_player_name(), "elevator:elevator", formspec) +            elseif not elevator.motors[meta:get_string("motor")] then +                formspec = "size[4,2]" +                    .."label[0,0;This elevator is inactive.]" +                    .."field[0.25,1.25;4,0;label;;"..minetest.formspec_escape(meta:get_string("label")).."]" +                    .."button_exit[-0.05,1.5;4,1;setlabel;Set label]" +                minetest.show_formspec(sender:get_player_name(), "elevator:elevator", formspec) +            elseif boxes[meta:get_string("motor")] then                  formspec = "size[4,2]" -                .."label[0,0;No targets available.]" -                .."field[0.25,1.25;4,0;label;;"..minetest.formspec_escape(meta:get_string("label")).."]" -                .."button_exit[-0.05,1.5;4,1;setlabel;Set label]" +                    .."label[0,0;This elevator is in use.]" +                    .."field[0.25,1.25;4,0;label;;"..minetest.formspec_escape(meta:get_string("label")).."]" +                    .."button_exit[-0.05,1.5;4,1;setlabel;Set label]" +                minetest.show_formspec(sender:get_player_name(), "elevator:elevator", formspec)              end -            minetest.show_formspec(sender:get_player_name(), "elevator:elevator", formspec) -        elseif not elevator.motors[meta:get_string("motor")] then -            formspec = "size[4,2]" -                .."label[0,0;This elevator is inactive.]" -                .."field[0.25,1.25;4,0;label;;"..minetest.formspec_escape(meta:get_string("label")).."]" -                .."button_exit[-0.05,1.5;4,1;setlabel;Set label]" -            minetest.show_formspec(sender:get_player_name(), "elevator:elevator", formspec) -        elseif boxes[meta:get_string("motor")] then -            formspec = "size[4,2]" -                .."label[0,0;This elevator is in use.]" -                .."field[0.25,1.25;4,0;label;;"..minetest.formspec_escape(meta:get_string("label")).."]" -                .."button_exit[-0.05,1.5;4,1;setlabel;Set label]" -            minetest.show_formspec(sender:get_player_name(), "elevator:elevator", formspec) -        end -    end, +        end, -    on_destruct = function(pos) -        local p = {x=pos.x, y=pos.y+1, z=pos.z} -        minetest.remove_node(p) -    end, -}) +        on_destruct = function(pos) +            local p = vector.add(pos, {x=0, y=1, z=0}) +            if get_node(p).name == placeholder then +                minetest.remove_node(p) +            end +        end, +    })  end  minetest.register_on_player_receive_fields(function(sender, formname, fields) @@ -484,11 +522,13 @@ minetest.register_on_player_receive_fields(function(sender, formname, fields)          end          meta:set_string("label", fields.label)          meta:set_string("infotext", fields.label) +        -- Rebuild the elevator shaft so the other elevators can read this label.          local motorhash = meta:get_string("motor")          build_motor(elevator.motors[motorhash] and motorhash or locate_motor(pos))          return true      end -    if vector.distance(sender:get_pos(), pos) > 1 or boxes[meta:get_string("motor")] then +    -- Double check if it's ok to go. +    if vector.distance(sender:get_pos(), pos) > 1 then          return true      end      if fields.target then @@ -500,6 +540,7 @@ minetest.register_on_player_receive_fields(function(sender, formname, fields)          end          -- End hacky HACK.          minetest.after(0.2, minetest.show_formspec, sender:get_player_name(), "elevator:elevator", closeformspec) +        -- Ensure we're connected to a motor.          local motorhash = meta:get_string("motor")          local motor = elevator.motors[motorhash]          if not motor then @@ -516,13 +557,17 @@ minetest.register_on_player_receive_fields(function(sender, formname, fields)              minetest.chat_send_player(sender:get_player_name(), "This elevator is not attached to a motor.")              return true          end +        -- Locate our target elevator.          local target = nil +        local selected_target = formspecs[sender:get_player_name()][2][minetest.explode_textlist_event(fields.target).index]          for i,v in ipairs(motor.pnames) do -            if v == formspecs[sender:get_player_name()][2][minetest.explode_textlist_event(fields.target).index] then -                target = minetest.string_to_pos(motor.elevators[i]) +            if v == selected_target then +                target = punhash(motor.elevators[i])              end          end +        -- Found the elevator? Then go!          if target then +            -- Final check.              if boxes[motorhash] then                  minetest.chat_send_player(sender:get_player_name(), "This elevator is in use.")                  return true @@ -530,7 +575,7 @@ minetest.register_on_player_receive_fields(function(sender, formname, fields)              local obj = create_box(motorhash, pos, target, sender)              -- Teleport anyone standing within an on elevator out, or they'd fall through the off elevators.              for _,p in ipairs(motor.elevators) do -                local p = minetest.string_to_pos(p) +                local p = punhash(p)                  for _,object in ipairs(minetest.get_objects_inside_radius(p, 0.6)) do                      if object.is_player and object:is_player() then                          if object:get_player_name() ~= obj:get_luaentity().attached then @@ -548,11 +593,11 @@ minetest.register_on_player_receive_fields(function(sender, formname, fields)      return true  end) +-- Compatability with an older version.  minetest.register_alias("elevator:elevator", "elevator:elevator_off") --- Convert off to on when applicable. -local offabm = function(pos, node) -    local meta = minetest.get_meta(pos) +-- Ensure an elevator is up to the latest version. +local function upgrade_elevator(pos, meta)      if meta:get_int("version") ~= VERSION then          minetest.log("action", "[elevator] Updating elevator with old version at "..minetest.pos_to_string(pos))          minetest.after(0, function(pos) build_motor(locate_motor(pos)) end, pos) @@ -560,6 +605,12 @@ local offabm = function(pos, node)          meta:set_string("formspec", "")          meta:set_string("infotext", meta:get_string("label"))      end +end + +-- Convert off to on when applicable. +local offabm = function(pos, node) +    local meta = minetest.get_meta(pos) +    upgrade_elevator(pos, meta)      if not boxes[meta:get_string("motor")] and elevator.motors[meta:get_string("motor")] then          node.name = "elevator:elevator_on"          minetest.swap_node(pos, node) @@ -580,11 +631,7 @@ minetest.register_abm({      chance = 1,      action = function(pos, node)          local meta = minetest.get_meta(pos) -        if meta:get_int("version") ~= VERSION then -            minetest.log("action", "[elevator] Updating elevator with old version at "..minetest.pos_to_string(pos)) -            minetest.after(0, function(pos) build_motor(locate_motor(pos)) end, pos) -            meta:set_int("version", VERSION) -        end +        upgrade_elevator(pos, meta)          if boxes[meta:get_string("motor")] or not elevator.motors[meta:get_string("motor")] then              node.name = "elevator:elevator_off"              minetest.swap_node(pos, node) @@ -620,9 +667,11 @@ minetest.register_node("elevator:shaft", {          },      },      after_place_node = function(pos) +        -- We might have connected a motor above to an elevator below.          build_motor(locate_motor(pos))      end,      on_destruct = function(pos) +        -- Remove boxes and deactivate elevators below us.          unbuild(pos, 1)      end,  }) @@ -672,6 +721,7 @@ minetest.register_node("elevator:elevator_box", {      light_source = 4,  }) +-- Remove the player from self, and teleport them to pos if specified.  local function detach(self, pos)      local player = minetest.get_player_by_name(self.attached)      local attached = player:get_attach() @@ -706,11 +756,13 @@ local box_entity = {      vmult = 0,      on_activate = function(self, staticdata) +        -- Don't want the box being destroyed by anything except the elevator system.          self.object:set_armor_groups({immortal=1})      end,      on_step = function(self, dtime)          local pos = self.object:getpos() +        -- First, check if this box needs removed.          -- If the motor has a box and it isn't this box.          if boxes[self.motor] and boxes[self.motor] ~= self.object then              minetest.log("action", "[elevator] "..minetest.pos_to_string(pos).." broke due to duplication.") @@ -739,16 +791,20 @@ local box_entity = {              boxes[self.motor] = nil              return          end +          minetest.get_player_by_name(self.attached):setpos(pos) +        -- Ensure lastpos is set to something.          self.lastpos = self.lastpos or pos + +        -- Loop through all travelled nodes.          for y=self.lastpos.y,pos.y,((self.lastpos.y > pos.y) and -1 or 1) do              local p = vector.round({x=pos.x, y=y, z=pos.z}) -            --local above = vector.add(p, {x=0,y=1,z=0})              local below = vector.add(p, {x=0,y=-1,z=0})              local node = get_node(p)              if node.name == "elevator:shaft" then -                -- Nothing +                -- Nothing, just continue on our way.              elseif node.name == "elevator:elevator_on" or node.name == "elevator:elevator_off" then +                -- If this is our target, detach the player here, destroy this box, and update the target elevator without waiting for the abm.                  if vector.distance(p, self.target) < 1 then                      minetest.log("action", "[elevator] "..minetest.pos_to_string(p).." broke due to arrival.")                      detach(self, vector.add(self.target, {x=0, y=-0.4, z=0})) @@ -758,8 +814,10 @@ local box_entity = {                      return                  end              else +                -- Check if we're in the top part of an elevator, if so it's fine.                  local belownode = get_node(below)                  if belownode.name ~= "elevator:elevator_on" and belownode.name ~= "elevator:elevator_off" then +                    -- If we aren't, then break the box.                      minetest.log("action", "[elevator] "..minetest.pos_to_string(p).." broke on "..node.name)                      boxes[self.motor] = nil                      detach(self, p) @@ -768,6 +826,7 @@ local box_entity = {                  end              end          end +        -- Recreate the box every few seconds. This may not be necessary anymore, but does not seem to harm anything.          self.timer = (self.timer or 0) + dtime          if self.timer > 5 and self.motor and self.target and self.attached and pos then              self.object:remove() | 
