aboutsummaryrefslogtreecommitdiff
path: root/init.lua
diff options
context:
space:
mode:
authorSX <sx@minetest>2020-02-14 02:07:10 +0200
committerSX <sx@minetest>2020-02-14 02:07:10 +0200
commita3966d1a029cbeaaf6778313ee44dd6ada9ed369 (patch)
tree47d2a069141b60d27b9021b095dcf523ba0d5b22 /init.lua
parent469b50633862b4838e4304750ef01195fd9850e8 (diff)
downloadelevator-a3966d1a029cbeaaf6778313ee44dd6ada9ed369.tar.gz
elevator-a3966d1a029cbeaaf6778313ee44dd6ada9ed369.tar.bz2
elevator-a3966d1a029cbeaaf6778313ee44dd6ada9ed369.zip
Refactoring crafts formspecs components helpers
Diffstat (limited to 'init.lua')
-rw-r--r--init.lua390
1 files changed, 23 insertions, 367 deletions
diff --git a/init.lua b/init.lua
index 905e5e3..b462b5b 100644
--- a/init.lua
+++ b/init.lua
@@ -1,43 +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 armor_path = minetest.get_modpath("3d_armor")
-- global runtime storage for data and references
--- contains .motors loaded from mod storage and api functions
+-- 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 MP = minetest.get_modpath(minetest.get_current_modname())
+dofile(MP .. "/helpers.lua")
dofile(MP .. "/storage.lua")
-dofile(MP .. "/register.lua")
+dofile(MP .. "/crafts.lua")
+dofile(MP .. "/components.lua")
dofile(MP .. "/hooks.lua")
+dofile(MP .. "/formspecs.lua")
--- Player formspecs.
-local formspecs = {}
-
--- 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
-
-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)
@@ -45,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
@@ -58,8 +51,8 @@ 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.
elevator.boxes[motorhash] = obj
elevator.riding[sender:get_player_name()] = {
@@ -71,36 +64,6 @@ local function create_box(motorhash, pos, target, sender)
return obj
end
--- 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
-
-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.
elevator.locate_motor = function(pos)
local p = vector.new(pos)
@@ -158,7 +121,7 @@ elevator.build_motor = function(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
elevator.build_motor(meta:get_string("motor"))
end
@@ -213,319 +176,12 @@ elevator.unbuild = function(pos, add)
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 = {},
- }
- 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", 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)
- 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 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
-
-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")
- 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 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 elevator.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
- 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)
-
--- 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) elevator.build_motor(elevator.locate_motor(pos)) end, pos)
- meta:set_int("version", VERSION)
+ meta:set_int("version", elevator.VERSION)
meta:set_string("formspec", "")
meta:set_string("infotext", meta:get_string("label"))
end