From df542c5a167906dfcfc5a23d4b9b5318d1481f5d Mon Sep 17 00:00:00 2001 From: Beha Date: Wed, 22 Mar 2017 09:15:17 -0400 Subject: More cleanups, minor fixes. --- init.lua | 401 ++++++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 230 insertions(+), 171 deletions(-) (limited to 'init.lua') diff --git a/init.lua b/init.lua index b3caadf..2e73573 100644 --- a/init.lua +++ b/init.lua @@ -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 to ride beginning at and targetting . 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 , 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() -- cgit v1.2.3