aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBeha <shacknetisp@mail.com>2020-04-02 00:13:33 -0400
committerGitHub <noreply@github.com>2020-04-02 00:13:33 -0400
commit4924457eac47fc3a1c6c47834ed064b1b2089923 (patch)
treed514005ca26b792ce3f9f33050970945b06e2e63
parentffedde3bd611a8f29398f9db71b198be5b23c4dc (diff)
parent13f7c692cbddb53618e904170c6ac1d6762cfa4f (diff)
downloadelevator-4924457eac47fc3a1c6c47834ed064b1b2089923.tar.gz
elevator-4924457eac47fc3a1c6c47834ed064b1b2089923.tar.bz2
elevator-4924457eac47fc3a1c6c47834ed064b1b2089923.zip
Merge pull request #10 from S-S-X/refactor
Refactoring mod structure
-rw-r--r--.github/workflows/luacheck.yml17
-rw-r--r--.luacheckrc24
-rw-r--r--components.lua334
-rw-r--r--crafts.lua87
-rw-r--r--formspecs.lua90
-rw-r--r--helpers.lua38
-rw-r--r--hooks.lua61
-rw-r--r--init.lua739
-rw-r--r--storage.lua33
9 files changed, 739 insertions, 684 deletions
diff --git a/.github/workflows/luacheck.yml b/.github/workflows/luacheck.yml
new file mode 100644
index 0000000..a03fe92
--- /dev/null
+++ b/.github/workflows/luacheck.yml
@@ -0,0 +1,17 @@
+name: luacheck
+
+on: [push]
+
+jobs:
+ build:
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v1
+ - name: apt
+ run: sudo apt-get install -y luarocks
+ - name: luacheck install
+ run: luarocks install --local luacheck
+ - name: luacheck run
+ run: $HOME/.luarocks/bin/luacheck ./
diff --git a/.luacheckrc b/.luacheckrc
new file mode 100644
index 0000000..db7f279
--- /dev/null
+++ b/.luacheckrc
@@ -0,0 +1,24 @@
+unused_args = false
+
+ignore = {
+ "631",
+}
+
+globals = {
+ "elevator",
+}
+
+read_globals = {
+ -- Stdlib
+ string = {fields = {"split"}},
+ table = {fields = {"copy", "getn"}},
+
+ -- Minetest
+ "minetest",
+ "vector",
+ "VoxelManip",
+
+ -- deps
+ "default", "screwdriver",
+ "farming", "armor",
+}
diff --git a/components.lua b/components.lua
new file mode 100644
index 0000000..d018ee0
--- /dev/null
+++ b/components.lua
@@ -0,0 +1,334 @@
+
+local phash = elevator.phash
+local get_node = elevator.get_node
+
+local homedecor_path = minetest.get_modpath("homedecor")
+
+-- Use homedecor's placeholder if possible.
+if homedecor_path then
+ minetest.register_alias("elevator:placeholder", "homedecor:expansion_placeholder")
+else
+ -- Placeholder node, in the style of homedecor.
+ minetest.register_node("elevator: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,
+
+ on_dig = function(pos, node, player)
+ minetest.remove_node(pos)
+ minetest.set_node(pos, {name="elevator:placeholder"})
+ end
+ })
+end
+
+minetest.register_node("elevator:shaft", {
+ description = "Elevator Shaft",
+ tiles = { "elevator_shaft.png" },
+ drawtype = "nodebox",
+ paramtype = "light",
+ on_rotate = screwdriver.disallow,
+ sunlight_propagates = true,
+ groups = {cracky=2, oddly_breakable_by_hand=1},
+ sounds = default.node_sound_stone_defaults(),
+ node_box = {
+ type = "fixed",
+ fixed = {
+ {-8/16,-8/16,-8/16,-7/16,8/16,8/16},
+ {7/16,-8/16,-8/16,8/16,8/16,8/16},
+ {-7/16,-8/16,-8/16,7/16,8/16,-7/16},
+ {-7/16,-8/16,8/16,7/16,8/16,7/16},
+ },
+ },
+ collisionbox = {
+ type = "fixed",
+ fixed = {
+ {-8/16,-8/16,-8/16,-7/16,8/16,8/16},
+ {7/16,-8/16,-8/16,8/16,8/16,8/16},
+ {-7/16,-8/16,-8/16,7/16,8/16,-7/16},
+ {-7/16,-8/16,8/16,7/16,8/16,7/16},
+ },
+ },
+ after_place_node = function(pos)
+ -- We might have connected a motor above to an elevator below.
+ elevator.build_motor(elevator.locate_motor(pos))
+ end,
+ on_destruct = function(pos)
+ -- Remove boxes and deactivate elevators below us.
+ elevator.unbuild(pos, 1)
+ end,
+})
+
+local 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},
+ { -0.5,-0.5,-0.5,0.5,-0.48, 0.5},
+ { -0.5, 1.45,-0.5,0.5, 1.5, 0.5},
+}
+
+-- Elevator box node. Not intended to be placeable.
+minetest.register_node("elevator:elevator_box", {
+ description = "Elevator",
+ drawtype = "nodebox",
+ paramtype = 'light',
+ paramtype2 = "facedir",
+ wield_scale = {x=0.6, y=0.6, z=0.6},
+
+ selection_box = {
+ type = "fixed",
+ fixed = { -0.5, -0.5, -0.5, 0.5, 1.5, 0.5 }
+ },
+
+ collision_box = {
+ type = "fixed",
+ fixed = box,
+ },
+
+ node_box = {
+ type = "fixed",
+ fixed = box,
+ },
+
+ tiles = {
+ "default_steel_block.png",
+ "default_steel_block.png",
+ "elevator_box.png",
+ "elevator_box.png",
+ "elevator_box.png",
+ "elevator_box.png",
+ },
+ groups = {not_in_creative_inventory = 1},
+
+ light_source = 4,
+})
+
+minetest.register_node("elevator:motor", {
+ description = "Elevator Motor",
+ tiles = {
+ "default_steel_block.png",
+ "default_steel_block.png",
+ "elevator_motor.png",
+ "elevator_motor.png",
+ "elevator_motor.png",
+ "elevator_motor.png",
+ },
+ 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 = {},
+ labels = {},
+ }
+ elevator.save_elevator()
+ elevator.build_motor(phash(pos))
+ end,
+ on_destruct = function(pos)
+ -- Destroy everything related to this motor.
+ elevator.boxes[phash(pos)] = nil
+ elevator.motors[phash(pos)] = nil
+ elevator.save_elevator()
+ end,
+})
+
+for _,mode in ipairs({"on", "off"}) do
+ 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,
+ },
+
+ collision_box = {
+ type = "fixed",
+ fixed = cbox,
+ },
+
+ node_box = {
+ type = "fixed",
+ fixed = box,
+ },
+
+ 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",
+
+ -- Emit a bit of light when active.
+ light_source = (on and 4 or nil),
+
+ after_place_node = function(pos, placer, itemstack)
+ local meta = minetest.get_meta(pos)
+ meta:set_int("version", elevator.VERSION)
+
+ -- 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="elevator:placeholder", paramtype2="facedir", param2=p2})
+
+ -- Try to build a motor above.
+ local motor = elevator.locate_motor(pos)
+ if motor then
+ elevator.build_motor(motor)
+ end
+ end,
+
+ after_dig_node = function(pos, node, meta, digger)
+ elevator.unbuild(pos, 2)
+ end,
+
+ 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 ~= "elevator:placeholder") then
+ return
+ end
+ return minetest.item_place(itemstack, placer, pointed_thing)
+ end,
+
+ on_rightclick = function(pos, node, sender)
+ if not sender or not sender:is_player() then
+ return
+ end
+ local formspec
+ local meta = minetest.get_meta(pos)
+ elevator.formspecs[sender:get_player_name()] = {pos}
+ if on then
+ if vector.distance(sender:getpos(), pos) > 1 or minetest.get_node(sender:getpos()).name ~= nodename then
+ minetest.chat_send_player(sender:get_player_name(), "You are not inside the booth.")
+ return
+ end
+ -- Build the formspec from the motor table.
+ 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.." - "..minetest.formspec_escape(motor.labels[ji])) or jv)
+ end
+ end
+ elevator.formspecs[sender:get_player_name()] = {pos, tpnames}
+ if #tpnames > 0 then
+ if not minetest.is_protected(pos, sender:get_player_name()) 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,4.4]"
+ .."label[0,0;Click once to travel.]"
+ .."textlist[-0.1,0.5;4,4;target;"..table.concat(tpnames_l, ",").."]"
+ end
+ else
+ if not minetest.is_protected(pos, sender:get_player_name()) 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]"
+ else
+ formspec = "size[4,0.4]"
+ .."label[0,0;No targets available.]"
+ end
+ end
+ minetest.show_formspec(sender:get_player_name(), "elevator:elevator", formspec)
+ elseif not elevator.motors[meta:get_string("motor")] then
+ if not minetest.is_protected(pos, sender:get_player_name()) 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]"
+ else
+ formspec = "size[4,0.4]"
+ .."label[0,0;This elevator is inactive.]"
+ end
+ minetest.show_formspec(sender:get_player_name(), "elevator:elevator", formspec)
+ elseif elevator.boxes[meta:get_string("motor")] then
+ if not minetest.is_protected(pos, sender:get_player_name()) 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]"
+ else
+ formspec = "size[4,0.4]"
+ .."label[0,0;This elevator is in use.]"
+ end
+ minetest.show_formspec(sender:get_player_name(), "elevator:elevator", formspec)
+ end
+ end,
+
+ on_destruct = function(pos)
+ local p = vector.add(pos, {x=0, y=1, z=0})
+ if get_node(p).name == "elevator:placeholder" then
+ minetest.remove_node(p)
+ end
+ end,
+ })
+end
+
+-- Compatability with an older version.
+minetest.register_alias("elevator:elevator", "elevator:elevator_off")
diff --git a/crafts.lua b/crafts.lua
new file mode 100644
index 0000000..5f5831a
--- /dev/null
+++ b/crafts.lua
@@ -0,0 +1,87 @@
+-- Detect optional mods.
+local technic_path = minetest.get_modpath("technic")
+local chains_path = minetest.get_modpath("chains")
+
+if technic_path and chains_path then
+ minetest.register_craft({
+ output = "elevator:elevator",
+ recipe = {
+ {"technic:cast_iron_ingot", "chains:chain", "technic:cast_iron_ingot"},
+ {"technic:cast_iron_ingot", "default:mese_crystal", "technic:cast_iron_ingot"},
+ {"technic:stainless_steel_ingot", "default:glass", "technic:stainless_steel_ingot"},
+ },
+ })
+
+ minetest.register_craft({
+ output = "elevator:shaft",
+ recipe = {
+ {"technic:cast_iron_ingot", "default:glass"},
+ {"default:glass", "glooptest:chainlink"},
+ },
+ })
+
+ minetest.register_craft({
+ output = "elevator:motor",
+ recipe = {
+ {"default:diamond", "technic:control_logic_unit", "default:diamond"},
+ {"default:steelblock", "technic:motor", "default:steelblock"},
+ {"chains:chain", "default:diamond", "chains:chain"}
+ },
+ })
+elseif technic_path and farming and farming.mod and farming.mod == "redo" then
+ -- add alternative recipe with hemp rope
+ minetest.register_craft({
+ output = "elevator:elevator",
+ recipe = {
+ {"technic:cast_iron_ingot", "farming:hemp_rope", "technic:cast_iron_ingot"},
+ {"technic:cast_iron_ingot", "default:mese_crystal", "technic:cast_iron_ingot"},
+ {"technic:stainless_steel_ingot", "default:glass", "technic:stainless_steel_ingot"},
+ },
+ })
+
+ minetest.register_craft({
+ output = "elevator:shaft",
+ recipe = {
+ {"technic:cast_iron_ingot", "default:glass"},
+ {"default:glass", "farming:hemp_rope"},
+ },
+ })
+
+ minetest.register_craft({
+ output = "elevator:motor",
+ recipe = {
+ {"default:diamond", "technic:control_logic_unit", "default:diamond"},
+ {"default:steelblock", "technic:motor", "default:steelblock"},
+ {"farming:hemp_rope", "default:diamond", "farming:hemp_rope"}
+ },
+ })
+
+-- Recipes without technic & chains required.
+-- Recipes for default dependency fallback.
+else
+ minetest.register_craft({
+ output = "elevator:elevator",
+ recipe = {
+ {"default:steel_ingot", "farming:cotton", "default:steel_ingot"},
+ {"default:steel_ingot", "default:mese_crystal", "default:steel_ingot"},
+ {"xpanes:pane_flat", "default:glass", "xpanes:pane_flat"},
+ },
+ })
+
+ minetest.register_craft({
+ output = "elevator:shaft",
+ recipe = {
+ {"default:steel_ingot", "default:obsidian_glass"},
+ {"default:obsidian_glass", "default:steel_ingot"},
+ },
+ })
+
+ minetest.register_craft({
+ output = "elevator:motor",
+ recipe = {
+ {"default:diamond", "default:copper_ingot", "default:diamond"},
+ {"default:steelblock", "default:furnace", "default:steelblock"},
+ {"farming:cotton", "default:diamond", "farming:cotton"}
+ },
+ })
+end
diff --git a/formspecs.lua b/formspecs.lua
new file mode 100644
index 0000000..64bd020
--- /dev/null
+++ b/formspecs.lua
@@ -0,0 +1,90 @@
+
+local punhash = elevator.punhash
+
+minetest.register_on_player_receive_fields(function(sender, formname, fields)
+ if formname ~= "elevator:elevator" then
+ return
+ end
+ local pos = elevator.formspecs[sender:get_player_name()] and elevator.formspecs[sender:get_player_name()][1] or nil
+ if not pos then
+ return true
+ end
+ local meta = minetest.get_meta(pos)
+ if fields.setlabel then
+ if minetest.is_protected(pos, sender:get_player_name()) then
+ return true
+ 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")
+ elevator.build_motor(elevator.motors[motorhash] and motorhash or elevator.locate_motor(pos))
+ return true
+ end
+ -- Double check if it's ok to go.
+ if vector.distance(sender:getpos(), pos) > 1 then
+ return true
+ end
+ if fields.target then
+ local closeformspec = ""
+ -- HACK: With player information extensions enabled, we can check if closing formspecs are now allowed. This is specifically used on Survival in Ethereal.
+ local pi = minetest.get_player_information(sender:get_player_name())
+ if (not (pi.major == 0 and pi.minor == 4 and pi.patch == 15)) and (pi.protocol_version or 29) < 29 then
+ closeformspec = "size[4,2] label[0,0;You are now using the elevator.\nUpgrade Minetest to avoid this dialog.] button_exit[0,1;4,1;close;Close]"
+ 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
+ motorhash = elevator.locate_motor(pos)
+ motor = elevator.motors[motorhash]
+ if motor then
+ meta:set_string("motor", "")
+ elevator.build_motor(motorhash)
+ minetest.chat_send_player(sender:get_player_name(), "Recalibrated to a new motor, please try again.")
+ return true
+ end
+ end
+ if not motor then
+ minetest.chat_send_player(sender:get_player_name(), "This elevator is not attached to a motor.")
+ return true
+ end
+ if not elevator.formspecs[sender:get_player_name()][2] or not elevator.formspecs[sender:get_player_name()][2][minetest.explode_textlist_event(fields.target).index] then
+ return true
+ end
+ -- Locate our target elevator.
+ local target = nil
+ local selected_target = elevator.formspecs[sender:get_player_name()][2][minetest.explode_textlist_event(fields.target).index]
+ for i,v in ipairs(motor.pnames) do
+ if v == selected_target then
+ target = punhash(motor.elevators[i])
+ end
+ end
+ -- Found the elevator? Then go!
+ if target then
+ -- Final check.
+ if elevator.boxes[motorhash] then
+ minetest.chat_send_player(sender:get_player_name(), "This elevator is in use.")
+ return true
+ end
+ local obj = elevator.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
+ for _,object in ipairs(minetest.get_objects_inside_radius(punhash(p), 0.6)) do
+ if object.is_player and object:is_player() then
+ if object:get_player_name() ~= obj:get_luaentity().attached then
+ elevator.teleport_player_from_elevator(object)
+ end
+ end
+ end
+ end
+ else
+ minetest.chat_send_player(sender:get_player_name(), "This target is invalid.")
+ return true
+ end
+ return true
+ end
+ return true
+end)
diff --git a/helpers.lua b/helpers.lua
new file mode 100644
index 0000000..ccd8ebb
--- /dev/null
+++ b/helpers.lua
@@ -0,0 +1,38 @@
+
+-- Try to teleport player away from any closed (on) elevator node.
+elevator.teleport_player_from_elevator = function(player)
+ local function solid(pos)
+ if not minetest.registered_nodes[minetest.get_node(pos).name] then
+ return true
+ end
+ return minetest.registered_nodes[minetest.get_node(pos).name].walkable
+ 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
+ end
+end
+
+elevator.phash = function(pos)
+ return minetest.pos_to_string(pos)
+end
+
+elevator.punhash = function(pos)
+ return minetest.string_to_pos(pos)
+end
+
+-- Helper function to read unloaded nodes.
+elevator.get_node = function(pos)
+ local node = minetest.get_node_or_nil(pos)
+ if node then return node end
+ local _,_ = VoxelManip():read_from_map(pos, pos)
+ return minetest.get_node_or_nil(pos)
+end
diff --git a/hooks.lua b/hooks.lua
new file mode 100644
index 0000000..609f0e9
--- /dev/null
+++ b/hooks.lua
@@ -0,0 +1,61 @@
+
+-- Globalstep timer.
+local time = 0
+
+minetest.register_globalstep(function(dtime)
+ -- Don't want to run this too often.
+ time = time + dtime
+ if time < 0.5 then
+ return
+ end
+ time = 0
+ -- Only count riders who are still logged in.
+ local newriding = {}
+ for _,p in ipairs(minetest.get_connected_players()) do
+ local pos = p:getpos()
+ local name = p:get_player_name()
+ newriding[name] = elevator.riding[name]
+ -- If the player is indeed riding, update their position.
+ if newriding[name] then
+ newriding[name].pos = pos
+ end
+ end
+ elevator.riding = newriding
+ for name,r in pairs(elevator.riding) do
+ -- If the box is no longer loaded or existent, create another.
+ local ok = r.box and r.box.getpos and r.box:getpos() and r.box:get_luaentity() and r.box:get_luaentity().attached == name
+ if not ok then
+ minetest.log("action", "[elevator] "..minetest.pos_to_string(r.pos).." created due to lost rider.")
+ minetest.after(0, elevator.create_box, r.motor, r.pos, r.target, minetest.get_player_by_name(name))
+ end
+ end
+ -- Ensure boxes are deleted after <PTIMEOUT> seconds if there are no players nearby.
+ for motor,obj in pairs(elevator.boxes) do
+ if type(obj) ~= "table" then
+ return
+ end
+ elevator.lastboxes[motor] = elevator.lastboxes[motor] and math.min(elevator.lastboxes[motor], elevator.PTIMEOUT) or elevator.PTIMEOUT
+ elevator.lastboxes[motor] = math.max(elevator.lastboxes[motor] - 1, 0)
+ local pos = obj:getpos()
+ if pos then
+ for _,object in ipairs(minetest.get_objects_inside_radius(pos, 5)) do
+ if object.is_player and object:is_player() then
+ elevator.lastboxes[motor] = elevator.PTIMEOUT
+ break
+ end
+ end
+ if elevator.lastboxes[motor] < 1 then
+ minetest.log("action", "[elevator] "..minetest.pos_to_string(pos).." broke due to lack of players.")
+ elevator.boxes[motor] = false
+ end
+ else
+ minetest.log("action", "[elevator] "..minetest.pos_to_string(pos).." broke due to lack of position during player check.")
+ elevator.boxes[motor] = false
+ end
+ end
+end)
+
+minetest.register_on_leaveplayer(function(player)
+ -- We don't want players potentially logging into open elevators.
+ elevator.teleport_player_from_elevator(player)
+end)
diff --git a/init.lua b/init.lua
index 84ea482..b462b5b 100644
--- a/init.lua
+++ b/init.lua
@@ -1,104 +1,36 @@
--- 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_path = minetest.get_modpath("homedecor")
local armor_path = minetest.get_modpath("3d_armor")
--- Central "network" table.
-local elevator = {
- motors = {},
+-- global runtime storage for data and references
+-- contains .motors loaded from mod storage
+-- runtime variables and api functions
+elevator = {
+ SPEED = 10, -- Initial speed of a box.
+ ACCEL = 0.1, -- Acceleration of a box.
+ VISUAL_INCREASE = 1.75,
+ VERSION = 8, -- Elevator interface/database version.
+ PTIMEOUT = 120, -- Maximum time a box can go without players nearby.
+
+ boxes = {}, -- Elevator boxes in action.
+ lastboxes = {}, -- Player near box timeout.
+ riding = {}, -- Players riding boxes.
+ formspecs = {}, -- Player formspecs.
}
-local str = minetest.get_mod_storage and minetest.get_mod_storage()
-
-local elevator_file = minetest.get_worldpath() .. "/elevator"
-
-local function load_elevator()
- if str and ((str.contains and str:contains("data")) or (str:get_string("data") and str:get_string("data") ~= "")) then
- elevator = minetest.deserialize(str:get_string("data"))
- return
- end
- local file = io.open(elevator_file)
- if file then
- elevator = minetest.deserialize(file:read("*all")) or {}
- file:close()
- end
-end
-
-local function save_elevator()
- if str then
- str:set_string("data", minetest.serialize(elevator))
- return
- end
- local f = io.open(elevator_file, "w")
- f:write(minetest.serialize(elevator))
- f:close()
-end
-
-load_elevator()
-
--- Elevator boxes in action.
-local boxes = {}
--- Player formspecs.
-local formspecs = {}
--- Player near box timeout.
-local lastboxes = {}
--- Players riding boxes.
-local riding = {}
--- Globalstep timer.
-local time = 0
-
--- Helper function to read unloaded nodes.
-local function get_node(pos)
- local node = minetest.get_node_or_nil(pos)
- if node then return node end
- local _,_ = VoxelManip():read_from_map(pos, pos)
- return minetest.get_node_or_nil(pos)
-end
-
--- Use homedecor's placeholder if possible.
-local placeholder = homedecor_path and "homedecor:expansion_placeholder" or "elevator:placeholder"
-if homedecor_path 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,
+local MP = minetest.get_modpath(minetest.get_current_modname())
+dofile(MP .. "/helpers.lua")
+dofile(MP .. "/storage.lua")
+dofile(MP .. "/crafts.lua")
+dofile(MP .. "/components.lua")
+dofile(MP .. "/hooks.lua")
+dofile(MP .. "/formspecs.lua")
- 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
- })
-end
-
-local VISUAL_INCREASE = 1.75
+local phash = elevator.phash
+local punhash = elevator.punhash
+local get_node = elevator.get_node
-- Cause <sender> to ride <motorhash> beginning at <pos> and targetting <target>.
-local function create_box(motorhash, pos, target, sender)
+elevator.create_box = function(motorhash, pos, target, sender)
-- First create the box.
local obj = minetest.add_entity(pos, "elevator:box")
obj:setpos(pos)
@@ -106,7 +38,7 @@ local function create_box(motorhash, pos, target, sender)
sender:setpos(pos)
sender:set_attach(obj, "", {x=0, y=9, z=0}, {x=0, y=0, z=0})
sender:set_eye_offset({x=0, y=-9, z=0},{x=0, y=-9, z=0})
- sender:set_properties({visual_size = {x=VISUAL_INCREASE, y=VISUAL_INCREASE}})
+ sender:set_properties({visual_size = {x=elevator.VISUAL_INCREASE, y=elevator.VISUAL_INCREASE}})
if armor_path then
armor:update_player_visuals(sender)
end
@@ -119,11 +51,11 @@ local function create_box(motorhash, pos, target, sender)
obj:get_luaentity().halfway = {x=pos.x, y=(pos.y+target.y)/2, z=pos.z}
obj:get_luaentity().vmult = (target.y < pos.y) and -1 or 1
-- Set the speed.
- obj:setvelocity({x=0, y=SPEED*obj:get_luaentity().vmult, z=0})
- obj:setacceleration({x=0, y=ACCEL*obj:get_luaentity().vmult, z=0})
+ obj:setvelocity({x=0, y=elevator.SPEED*obj:get_luaentity().vmult, z=0})
+ obj:setacceleration({x=0, y=elevator.ACCEL*obj:get_luaentity().vmult, z=0})
-- Set the tables.
- boxes[motorhash] = obj
- riding[sender:get_player_name()] = {
+ elevator.boxes[motorhash] = obj
+ elevator.riding[sender:get_player_name()] = {
motor = motorhash,
pos = pos,
target = target,
@@ -132,96 +64,8 @@ local function create_box(motorhash, pos, target, sender)
return obj
end
--- Try to teleport player away from any closed (on) elevator node.
-local function teleport_player_from_elevator(player)
- local function solid(pos)
- if not minetest.registered_nodes[minetest.get_node(pos).name] then
- return true
- end
- return minetest.registered_nodes[minetest.get_node(pos).name].walkable
- 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
- end
-end
-
-minetest.register_globalstep(function(dtime)
- -- Don't want to run this too often.
- time = time + dtime
- if time < 0.5 then
- return
- end
- time = 0
- -- Only count riders who are still logged in.
- local newriding = {}
- for _,p in ipairs(minetest.get_connected_players()) do
- local pos = p:getpos()
- 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
- for name,r in pairs(riding) do
- -- If the box is no longer loaded or existent, create another.
- local ok = r.box and r.box.getpos and r.box:getpos() and r.box:get_luaentity() and r.box:get_luaentity().attached == name
- if not ok then
- minetest.log("action", "[elevator] "..minetest.pos_to_string(r.pos).." created due to lost rider.")
- minetest.after(0, create_box, r.motor, r.pos, r.target, minetest.get_player_by_name(name))
- end
- end
- -- Ensure boxes are deleted after <PTIMEOUT> seconds if there are no players nearby.
- for motor,obj in pairs(boxes) do
- if type(obj) ~= "table" then
- return
- end
- lastboxes[motor] = lastboxes[motor] and math.min(lastboxes[motor], PTIMEOUT) or PTIMEOUT
- lastboxes[motor] = math.max(lastboxes[motor] - 1, 0)
- local pos = obj:getpos()
- if pos then
- for _,object in ipairs(minetest.get_objects_inside_radius(pos, 5)) do
- if object.is_player and object:is_player() then
- lastboxes[motor] = PTIMEOUT
- break
- end
- end
- if lastboxes[motor] < 1 then
- minetest.log("action", "[elevator] "..minetest.pos_to_string(pos).." broke due to lack of players.")
- boxes[motor] = false
- end
- else
- minetest.log("action", "[elevator] "..minetest.pos_to_string(pos).." broke due to lack of position during player check.")
- boxes[motor] = false
- end
- end
-end)
-
-minetest.register_on_leaveplayer(function(player)
- -- We don't want players potentially logging into open elevators.
- teleport_player_from_elevator(player)
-end)
-
-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)
+elevator.locate_motor = function(pos)
local p = vector.new(pos)
while true do
local node = get_node(p)
@@ -237,7 +81,7 @@ local function locate_motor(pos)
end
end
-local function build_motor(hash)
+elevator.build_motor = function(hash)
local need_saving = false
local motor = elevator.motors[hash]
-- Just ignore motors that don't exist.
@@ -277,9 +121,9 @@ local function build_motor(hash)
for i,m in ipairs(motor.elevators) do
local pos = punhash(m)
local meta = minetest.get_meta(pos)
- meta:set_int("version", VERSION)
+ meta:set_int("version", elevator.VERSION)
if meta:get_string("motor") ~= hash then
- build_motor(meta:get_string("motor"))
+ elevator.build_motor(meta:get_string("motor"))
end
motor.labels[i] = meta:get_string("label")
meta:set_string("motor", hash)
@@ -288,11 +132,11 @@ local function build_motor(hash)
end
end
if need_saving then
- save_elevator()
+ elevator.save_elevator()
end
end
-local function unbuild(pos, add)
+elevator.unbuild = function(pos, add)
local need_saving = false
local p = table.copy(pos)
p.y = p.y - 1
@@ -319,332 +163,25 @@ local function unbuild(pos, add)
return
end
p2.y = p2.y + add
- local motorhash = locate_motor(p2)
- build_motor(motorhash)
+ local motorhash = elevator.locate_motor(p2)
+ elevator.build_motor(motorhash)
-- If there's a box below this point, break it.
- if boxes[motorhash] and boxes[motorhash]:getpos() and p2.y >= boxes[motorhash]:getpos().y then
- boxes[motorhash] = nil
+ if elevator.boxes[motorhash] and elevator.boxes[motorhash]:getpos() and p2.y >= elevator.boxes[motorhash]:getpos().y then
+ elevator.boxes[motorhash] = nil
end
-- If the box does not exist, just clear it.
- if boxes[motorhash] and not boxes[motorhash]:getpos() then
- boxes[motorhash] = nil
+ if elevator.boxes[motorhash] and not elevator.boxes[motorhash]:getpos() then
+ elevator.boxes[motorhash] = nil
end
end, table.copy(pos), add)
end
-minetest.register_node("elevator:motor", {
- description = "Elevator Motor",
- tiles = {
- "default_steel_block.png",
- "default_steel_block.png",
- "elevator_motor.png",
- "elevator_motor.png",
- "elevator_motor.png",
- "elevator_motor.png",
- },
- 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 = {},
- labels = {},
- }
- save_elevator()
- 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()
- end,
-})
-
-for _,mode in ipairs({"on", "off"}) do
- 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,
- },
-
- collision_box = {
- type = "fixed",
- fixed = cbox,
- },
-
- node_box = {
- type = "fixed",
- fixed = box,
- },
-
- 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",
-
- -- Emit a bit of light when active.
- light_source = (on and 4 or nil),
-
- after_place_node = function(pos, placer, itemstack)
- local meta = minetest.get_meta(pos)
- meta:set_int("version", VERSION)
-
- -- 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})
-
- -- Try to build a motor above.
- 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,
-
- 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
- return minetest.item_place(itemstack, placer, pointed_thing)
- end,
-
- on_rightclick = function(pos, node, sender)
- if not sender or not sender:is_player() then
- return
- end
- local formspec
- local meta = minetest.get_meta(pos)
- formspecs[sender:get_player_name()] = {pos}
- if on then
- if vector.distance(sender:getpos(), pos) > 1 or minetest.get_node(sender:getpos()).name ~= nodename then
- minetest.chat_send_player(sender:get_player_name(), "You are not inside the booth.")
- return
- end
- -- Build the formspec from the motor table.
- 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.." - "..minetest.formspec_escape(motor.labels[ji])) or jv)
- end
- end
- formspecs[sender:get_player_name()] = {pos, tpnames}
- if #tpnames > 0 then
- if not minetest.is_protected(pos, sender:get_player_name()) 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,4.4]"
- .."label[0,0;Click once to travel.]"
- .."textlist[-0.1,0.5;4,4;target;"..table.concat(tpnames_l, ",").."]"
- end
- else
- if not minetest.is_protected(pos, sender:get_player_name()) 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]"
- else
- formspec = "size[4,0.4]"
- .."label[0,0;No targets available.]"
- end
- end
- minetest.show_formspec(sender:get_player_name(), "elevator:elevator", formspec)
- elseif not elevator.motors[meta:get_string("motor")] then
- if not minetest.is_protected(pos, sender:get_player_name()) 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]"
- else
- formspec = "size[4,0.4]"
- .."label[0,0;This elevator is inactive.]"
- end
- minetest.show_formspec(sender:get_player_name(), "elevator:elevator", formspec)
- elseif boxes[meta:get_string("motor")] then
- if not minetest.is_protected(pos, sender:get_player_name()) 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]"
- else
- formspec = "size[4,0.4]"
- .."label[0,0;This elevator is in use.]"
- end
- minetest.show_formspec(sender:get_player_name(), "elevator:elevator", formspec)
- end
- 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)
- if formname ~= "elevator:elevator" then
- return
- end
- local pos = formspecs[sender:get_player_name()] and formspecs[sender:get_player_name()][1] or nil
- if not pos then
- return true
- end
- local meta = minetest.get_meta(pos)
- if fields.setlabel then
- if minetest.is_protected(pos, sender:get_player_name()) then
- return true
- 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
- -- Double check if it's ok to go.
- if vector.distance(sender:getpos(), pos) > 1 then
- return true
- end
- if fields.target then
- local closeformspec = ""
- -- HACK: With player information extensions enabled, we can check if closing formspecs are now allowed. This is specifically used on Survival in Ethereal.
- local pi = minetest.get_player_information(sender:get_player_name())
- if (not (pi.major == 0 and pi.minor == 4 and pi.patch == 15)) and (pi.protocol_version or 29) < 29 then
- closeformspec = "size[4,2] label[0,0;You are now using the elevator.\nUpgrade Minetest to avoid this dialog.] button_exit[0,1;4,1;close;Close]"
- 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
- motorhash = locate_motor(pos)
- motor = elevator.motors[motorhash]
- if motor then
- meta:set_string("motor", "")
- build_motor(motorhash)
- minetest.chat_send_player(sender:get_player_name(), "Recalibrated to a new motor, please try again.")
- return true
- end
- end
- if not motor then
- minetest.chat_send_player(sender:get_player_name(), "This elevator is not attached to a motor.")
- return true
- end
- if not formspecs[sender:get_player_name()][2] or not formspecs[sender:get_player_name()][2][minetest.explode_textlist_event(fields.target).index] then
- 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 == 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
- end
- 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 = 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
- teleport_player_from_elevator(object)
- end
- end
- end
- end
- else
- minetest.chat_send_player(sender:get_player_name(), "This target is invalid.")
- return true
- end
- return true
- end
- return true
-end)
-
--- Compatability with an older version.
-minetest.register_alias("elevator:elevator", "elevator:elevator_off")
-
-- Ensure an elevator is up to the latest version.
local function upgrade_elevator(pos, meta)
- if meta:get_int("version") ~= VERSION then
+ if meta:get_int("version") ~= elevator.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)
+ minetest.after(0, function(pos) elevator.build_motor(elevator.locate_motor(pos)) end, pos)
+ meta:set_int("version", elevator.VERSION)
meta:set_string("formspec", "")
meta:set_string("infotext", meta:get_string("label"))
end
@@ -654,7 +191,7 @@ end
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
+ if not elevator.boxes[meta:get_string("motor")] and elevator.motors[meta:get_string("motor")] then
node.name = "elevator:elevator_on"
minetest.swap_node(pos, node)
end
@@ -676,7 +213,7 @@ minetest.register_abm({
action = function(pos, node)
local meta = minetest.get_meta(pos)
upgrade_elevator(pos, meta)
- if boxes[meta:get_string("motor")] or not elevator.motors[meta:get_string("motor")] then
+ if elevator.boxes[meta:get_string("motor")] or not elevator.motors[meta:get_string("motor")] then
node.name = "elevator:elevator_off"
minetest.swap_node(pos, node)
end
@@ -684,88 +221,6 @@ minetest.register_abm({
label = "Elevator (On)",
})
-minetest.register_node("elevator:shaft", {
- description = "Elevator Shaft",
- tiles = { "elevator_shaft.png" },
- drawtype = "nodebox",
- paramtype = "light",
- on_rotate = screwdriver.disallow,
- sunlight_propagates = true,
- groups = {cracky=2, oddly_breakable_by_hand=1},
- sounds = default.node_sound_stone_defaults(),
- node_box = {
- type = "fixed",
- fixed = {
- {-8/16,-8/16,-8/16,-7/16,8/16,8/16},
- {7/16,-8/16,-8/16,8/16,8/16,8/16},
- {-7/16,-8/16,-8/16,7/16,8/16,-7/16},
- {-7/16,-8/16,8/16,7/16,8/16,7/16},
- },
- },
- collisionbox = {
- type = "fixed",
- fixed = {
- {-8/16,-8/16,-8/16,-7/16,8/16,8/16},
- {7/16,-8/16,-8/16,8/16,8/16,8/16},
- {-7/16,-8/16,-8/16,7/16,8/16,-7/16},
- {-7/16,-8/16,8/16,7/16,8/16,7/16},
- },
- },
- 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,
-})
-
-local 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},
- { -0.5,-0.5,-0.5,0.5,-0.48, 0.5},
- { -0.5, 1.45,-0.5,0.5, 1.5, 0.5},
-}
-
--- Elevator box node. Not intended to be placeable.
-minetest.register_node("elevator:elevator_box", {
- description = "Elevator",
- drawtype = "nodebox",
- paramtype = 'light',
- paramtype2 = "facedir",
- wield_scale = {x=0.6, y=0.6, z=0.6},
-
- selection_box = {
- type = "fixed",
- fixed = { -0.5, -0.5, -0.5, 0.5, 1.5, 0.5 }
- },
-
- collision_box = {
- type = "fixed",
- fixed = box,
- },
-
- node_box = {
- type = "fixed",
- fixed = box,
- },
-
- tiles = {
- "default_steel_block.png",
- "default_steel_block.png",
- "elevator_box.png",
- "elevator_box.png",
- "elevator_box.png",
- "elevator_box.png",
- },
- groups = {not_in_creative_inventory = 1},
-
- 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)
@@ -785,7 +240,7 @@ local function detach(self, pos)
pl:setpos(p)
end, player, pos)
end
- riding[self.attached] = nil
+ elevator.riding[self.attached] = nil
end
local box_entity = {
@@ -813,7 +268,7 @@ local box_entity = {
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
+ if elevator.boxes[self.motor] and elevator.boxes[self.motor] ~= self.object then
minetest.log("action", "[elevator] "..minetest.pos_to_string(pos).." broke due to duplication.")
self.object:remove()
return
@@ -822,22 +277,22 @@ local box_entity = {
if not minetest.get_player_by_name(self.attached) then
minetest.log("action", "[elevator] "..minetest.pos_to_string(pos).." broke due to lack of attachee logged in.")
self.object:remove()
- boxes[self.motor] = nil
+ elevator.boxes[self.motor] = nil
return
end
-- If our attached player is no longer with us.
if not minetest.get_player_by_name(self.attached):get_attach() or minetest.get_player_by_name(self.attached):get_attach():get_luaentity().uid ~= self.uid then
minetest.log("action", "[elevator] "..minetest.pos_to_string(pos).." broke due to lack of attachee.")
self.object:remove()
- boxes[self.motor] = nil
+ elevator.boxes[self.motor] = nil
return
end
-- If our motor's box is nil, we should self-destruct.
- if not boxes[self.motor] then
+ if not elevator.boxes[self.motor] then
minetest.log("action", "[elevator] "..minetest.pos_to_string(pos).." broke due to nil entry in boxes.")
detach(self)
self.object:remove()
- boxes[self.motor] = nil
+ elevator.boxes[self.motor] = nil
return
end
@@ -857,7 +312,7 @@ local box_entity = {
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}))
self.object:remove()
- boxes[self.motor] = nil
+ elevator.boxes[self.motor] = nil
offabm(self.target, node)
return
end
@@ -868,7 +323,7 @@ local box_entity = {
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
+ elevator.boxes[self.motor] = nil
detach(self, p)
self.object:remove()
return
@@ -880,87 +335,3 @@ local box_entity = {
}
minetest.register_entity("elevator:box", box_entity)
-
-if technic_path and chains_path then
- minetest.register_craft({
- output = "elevator:elevator",
- recipe = {
- {"technic:cast_iron_ingot", "chains:chain", "technic:cast_iron_ingot"},
- {"technic:cast_iron_ingot", "default:mese_crystal", "technic:cast_iron_ingot"},
- {"technic:stainless_steel_ingot", "default:glass", "technic:stainless_steel_ingot"},
- },
- })
-
- minetest.register_craft({
- output = "elevator:shaft",
- recipe = {
- {"technic:cast_iron_ingot", "default:glass"},
- {"default:glass", "glooptest:chainlink"},
- },
- })
-
- minetest.register_craft({
- output = "elevator:motor",
- recipe = {
- {"default:diamond", "technic:control_logic_unit", "default:diamond"},
- {"default:steelblock", "technic:motor", "default:steelblock"},
- {"chains:chain", "default:diamond", "chains:chain"}
- },
- })
-elseif technic_path and farming and farming.mod and farming.mod == "redo" then
- -- add alternative recipe with hemp rope
- minetest.register_craft({
- output = "elevator:elevator",
- recipe = {
- {"technic:cast_iron_ingot", "farming:hemp_rope", "technic:cast_iron_ingot"},
- {"technic:cast_iron_ingot", "default:mese_crystal", "technic:cast_iron_ingot"},
- {"technic:stainless_steel_ingot", "default:glass", "technic:stainless_steel_ingot"},
- },
- })
-
- minetest.register_craft({
- output = "elevator:shaft",
- recipe = {
- {"technic:cast_iron_ingot", "default:glass"},
- {"default:glass", "farming:hemp_rope"},
- },
- })
-
- minetest.register_craft({
- output = "elevator:motor",
- recipe = {
- {"default:diamond", "technic:control_logic_unit", "default:diamond"},
- {"default:steelblock", "technic:motor", "default:steelblock"},
- {"farming:hemp_rope", "default:diamond", "farming:hemp_rope"}
- },
- })
-
- -- Recipes without technic & chains required.
--- Recipes for default dependency fallback.
-else
- minetest.register_craft({
- output = "elevator:elevator",
- recipe = {
- {"default:steel_ingot", "farming:cotton", "default:steel_ingot"},
- {"default:steel_ingot", "default:mese_crystal", "default:steel_ingot"},
- {"xpanes:pane_flat", "default:glass", "xpanes:pane_flat"},
- },
- })
-
- minetest.register_craft({
- output = "elevator:shaft",
- recipe = {
- {"default:steel_ingot", "default:obsidian_glass"},
- {"default:obsidian_glass", "default:steel_ingot"},
- },
- })
-
- minetest.register_craft({
- output = "elevator:motor",
- recipe = {
- {"default:diamond", "default:copper_ingot", "default:diamond"},
- {"default:steelblock", "default:furnace", "default:steelblock"},
- {"farming:cotton", "default:diamond", "farming:cotton"}
- },
- })
-end
diff --git a/storage.lua b/storage.lua
new file mode 100644
index 0000000..e923e5d
--- /dev/null
+++ b/storage.lua
@@ -0,0 +1,33 @@
+
+local elevator_file = minetest.get_worldpath() .. "/elevator"
+
+local str = minetest.get_mod_storage and minetest.get_mod_storage()
+
+-- Central "network" table.
+elevator.motors = {}
+
+local function load_elevator()
+ local data = nil
+ if str and ((str.contains and str:contains("data")) or (str:get_string("data") and str:get_string("data") ~= "")) then
+ data = minetest.deserialize(str:get_string("data"))
+ else
+ local file = io.open(elevator_file)
+ if file then
+ data = minetest.deserialize(file:read("*all")) or {}
+ file:close()
+ end
+ end
+ elevator.motors = (data and data.motors) and data.motors or {}
+end
+
+elevator.save_elevator = function()
+ if str then
+ str:set_string("data", minetest.serialize({motors = elevator.motors}))
+ return
+ end
+ local f = io.open(elevator_file, "w")
+ f:write(minetest.serialize({motors = elevator.motors}))
+ f:close()
+end
+
+load_elevator()