From 39e7d860400c8e5d9b58da731e7aa268e8f5b2cd Mon Sep 17 00:00:00 2001 From: BuckarooBanzay Date: Thu, 19 Nov 2020 19:57:19 +0100 Subject: [PATCH] modularization, cleanup part II --- add_target.lua | 111 ++++++ doors.lua | 2 +- elevator.lua | 2 +- functions.lua | 142 ++++++++ init.lua | 780 +----------------------------------------- on_receive_fields.lua | 243 +++++++++++++ travelnet.lua | 4 +- update_formspec.lua | 237 +++++++++++++ 8 files changed, 744 insertions(+), 777 deletions(-) create mode 100644 add_target.lua create mode 100644 on_receive_fields.lua create mode 100644 update_formspec.lua diff --git a/add_target.lua b/add_target.lua new file mode 100644 index 0000000..2d353e3 --- /dev/null +++ b/add_target.lua @@ -0,0 +1,111 @@ +local S = minetest.get_translator("travelnet") + + +-- add a new target; meta is optional +travelnet.add_target = function( station_name, network_name, pos, player_name, meta, owner_name ) + + -- if it is an elevator, determine the network name through x and z coordinates + local this_node = minetest.get_node( pos ); + local is_elevator = false; + + if( this_node.name == 'travelnet:elevator' ) then +-- owner_name = '*'; -- the owner name is not relevant here + is_elevator = true; + network_name = tostring( pos.x )..','..tostring( pos.z ); + if( not( station_name ) or station_name == '' ) then + station_name = S("at @1 m", tostring( pos.y )); + end + end + + if( station_name == "" or not(station_name )) then + travelnet.show_message( pos, player_name, S("Error"), S("Please provide a name for this station." )); + return; + end + + if( network_name == "" or not( network_name )) then + travelnet.show_message( pos, player_name, S("Error"), + S("Please provide the name of the network this station ought to be connected to.")); + return; + end + + if( owner_name == nil or owner_name == '' or owner_name == player_name) then + owner_name = player_name; + + elseif( is_elevator ) then -- elevator networks + owner_name = player_name; + + elseif( not( minetest.check_player_privs(player_name, {interact=true}))) then + + travelnet.show_message( pos, player_name, S("Error"), + S("There is no player with interact privilege named '@1'. Aborting.", tostring( player_name))); + return; + + elseif( not( minetest.check_player_privs(player_name, {travelnet_attach=true})) + and not( travelnet.allow_attach( player_name, owner_name, network_name ))) then + + travelnet.show_message( pos, player_name, S("Error"), + S("You do not have the travelnet_attach priv which is required to attach your box to ".. + "the network of someone else. Aborting.")); + return; + end + + -- first one by this player? + if( not( travelnet.targets[ owner_name ] )) then + travelnet.targets[ owner_name ] = {}; + end + + -- first station on this network? + if( not( travelnet.targets[ owner_name ][ network_name ] )) then + travelnet.targets[ owner_name ][ network_name ] = {}; + end + + -- lua doesn't allow efficient counting here + local anz = 0; + for k,v in pairs( travelnet.targets[ owner_name ][ network_name ] ) do + + if( k == station_name ) then + travelnet.show_message( pos, player_name, S("Error"), + S("A station named '@1' already exists on this network. Please choose a diffrent name!", station_name)); + return; + end + + anz = anz + 1; + end + + -- we don't want too many stations in the same network because that would get confusing when displaying the targets + if( anz+1 > travelnet.MAX_STATIONS_PER_NETWORK ) then + travelnet.show_message( pos, player_name, S("Error"), + S("Network '@1', already contains the maximum number (@2) of allowed stations per network. ".. + "Please choose a different/new network name.", network_name, travelnet.MAX_STATIONS_PER_NETWORK)); + return; + end + + -- add this station + travelnet.targets[ owner_name ][ network_name ][ station_name ] = {pos=pos, timestamp=os.time() }; + + -- do we have a new node to set up? (and are not just reading from a safefile?) + if( meta ) then + + minetest.chat_send_player(player_name, S("Station '@1'" .." ".. + "has been added to the network '@2'" .. + ", which now consists of @3 station(s).", station_name, network_name, anz+1)); + + meta:set_string( "station_name", station_name ); + meta:set_string( "station_network", network_name ); + meta:set_string( "owner", owner_name ); + meta:set_int( "timestamp", travelnet.targets[ owner_name ][ network_name ][ station_name ].timestamp); + + meta:set_string("formspec", + "size[12,10]".. + "field[0.3,0.6;6,0.7;station_name;"..S("Station:")..";".. + minetest.formspec_escape(meta:get_string("station_name")).."]".. + "field[0.3,3.6;6,0.7;station_network;"..S("Network:")..";".. + minetest.formspec_escape(meta:get_string("station_network")).."]" ); + + -- display a list of all stations that can be reached from here + travelnet.update_formspec( pos, player_name, nil ); + + -- save the updated network data in a savefile over server restart + travelnet.save_data(); + end +end diff --git a/doors.lua b/doors.lua index 35a17fb..e0213b7 100644 --- a/doors.lua +++ b/doors.lua @@ -2,7 +2,7 @@ -- All doors (not only these here) in front of a travelnet or elevator are opened automaticly when a player arrives -- and are closed when a player departs from the travelnet or elevator. -- Autor: Sokomine -local S = travelnet.S; +local S = minetest.get_translator("travelnet") travelnet.register_door = function( node_base_name, def_tiles, material ) diff --git a/elevator.lua b/elevator.lua index 65ad8d8..a4c8732 100644 --- a/elevator.lua +++ b/elevator.lua @@ -1,7 +1,7 @@ -- This version of the travelnet box allows to move up or down only. -- The network name is determined automaticly from the position (x/z coordinates). -- >utor: Sokomine -local S = travelnet.S; +local S = minetest.get_translator("travelnet") travelnet.show_nearest_elevator = function( pos, owner_name, param2 ) if( not( pos ) or not(pos.x) or not(pos.z) or not( owner_name )) then diff --git a/functions.lua b/functions.lua index b07fb54..18b91f3 100644 --- a/functions.lua +++ b/functions.lua @@ -1,3 +1,4 @@ +local S = minetest.get_translator("travelnet") -- punching the travelnet updates its formspec and shows it to the player; -- however, that would be very annoying when actually trying to dig the thing. @@ -25,3 +26,144 @@ travelnet.check_if_trying_to_dig = function( puncher, node ) -- tools which can dig cracky items can start digging immediately return true; end + + +-- allow doors to open +travelnet.open_close_door = function( pos, player, mode ) + + local this_node = minetest.get_node_or_nil( pos ); + -- give up if the area is *still* not loaded + if( this_node == nil ) then + return + end + local pos2 = {x=pos.x,y=pos.y,z=pos.z}; + + if( this_node.param2 == 0 ) then pos2 = {x=pos.x,y=pos.y,z=(pos.z-1)}; + elseif( this_node.param2 == 1 ) then pos2 = {x=(pos.x-1),y=pos.y,z=pos.z}; + elseif( this_node.param2 == 2 ) then pos2 = {x=pos.x,y=pos.y,z=(pos.z+1)}; + elseif( this_node.param2 == 3 ) then pos2 = {x=(pos.x+1),y=pos.y,z=pos.z}; + end + + local door_node = minetest.get_node( pos2 ); + if door_node ~= nil and + door_node.name ~= 'ignore' and + door_node.name ~= 'air' and + minetest.registered_nodes[ door_node.name ] ~= nil and + minetest.registered_nodes[ door_node.name ].on_rightclick ~= nil then + + -- at least for homedecor, same facedir would mean "door closed" + + -- do not close the elevator door if it is already closed + if( mode==1 and ( string.sub( door_node.name, -7 ) == '_closed' + -- handle doors that change their facedir + or ( door_node.param2 == ((this_node.param2 + 2)%4) + and door_node.name ~= 'travelnet:elevator_door_glass_open' + and door_node.name ~= 'travelnet:elevator_door_tin_open' + and door_node.name ~= 'travelnet:elevator_door_steel_open'))) then + return; + end + -- do not open the doors if they are already open (works only on elevator-doors; not on doors in general) + if( mode==2 and ( string.sub( door_node.name, -5 ) == '_open' + -- handle doors that change their facedir + or ( door_node.param2 ~= ((this_node.param2 + 2)%4) + and door_node.name ~= 'travelnet:elevator_door_glass_closed' + and door_node.name ~= 'travelnet:elevator_door_tin_closed' + and door_node.name ~= 'travelnet:elevator_door_steel_closed'))) then + return; + end + + if( mode==2 ) then + minetest.after( 1, minetest.registered_nodes[ door_node.name ].on_rightclick, pos2, door_node, player ); + else + minetest.registered_nodes[ door_node.name ].on_rightclick(pos2, door_node, player); + end + end +end + + +travelnet.rotate_player = function( target_pos, player, tries ) + -- try later when the box is loaded + local node2 = minetest.get_node_or_nil( target_pos ); + if( node2 == nil ) then + if( tries < 30 ) then + minetest.after( 0, travelnet.rotate_player, target_pos, player, tries+1 ) + end + return + end + + -- play sound at the target position as well + if( travelnet.travelnet_sound_enabled ) then + if ( node2.name == 'travelnet:elevator' ) then + minetest.sound_play("travelnet_bell", {pos = target_pos, gain = 0.75, max_hear_distance = 10,}); + else + minetest.sound_play("travelnet_travel", {pos = target_pos, gain = 0.75, max_hear_distance = 10,}); + end + end + + -- do this only on servers where the function exists + if( player.set_look_horizontal ) then + -- rotate the player so that he/she can walk straight out of the box + local yaw = 0; + local param2 = node2.param2; + if( param2==0 ) then + yaw = 180; + elseif( param2==1 ) then + yaw = 90; + elseif( param2==2 ) then + yaw = 0; + elseif( param2==3 ) then + yaw = 270; + end + + player:set_look_horizontal( math.rad( yaw )); + player:set_look_vertical( math.rad( 0 )); + end + + travelnet.open_close_door( target_pos, player, 2 ); +end + + +travelnet.remove_box = function( pos, oldnode, oldmetadata, digger ) + + if( not( oldmetadata ) or oldmetadata=="nil" or not(oldmetadata.fields)) then + minetest.chat_send_player( digger:get_player_name(), S("Error")..": ".. + S("Could not find information about the station that is to be removed.")); + return; + end + + local owner_name = oldmetadata.fields[ "owner" ]; + local station_name = oldmetadata.fields[ "station_name" ]; + local station_network = oldmetadata.fields[ "station_network" ]; + + -- station is not known? then just remove it + if( not( owner_name ) + or not( station_name ) + or not( station_network ) + or not( travelnet.targets[ owner_name ] ) + or not( travelnet.targets[ owner_name ][ station_network ] )) then + + minetest.chat_send_player( digger:get_player_name(), S("Error")..": ".. + S("Could not find the station that is to be removed.")); + return; + end + + travelnet.targets[ owner_name ][ station_network ][ station_name ] = nil; + + -- inform the owner + minetest.chat_send_player( owner_name, S("Station '@1'" .." ".. + "has been REMOVED from the network '@2'.", station_name, station_network)); + if( digger ~= nil and owner_name ~= digger:get_player_name() ) then + minetest.chat_send_player( digger:get_player_name(), S("Station '@1'" .." ".. + "has been REMOVED from the network '@2'.", station_name, station_network)); + end + + -- save the updated network data in a savefile over server restart + travelnet.save_data(); +end + + + +travelnet.can_dig = function( pos, player, description ) + -- forbid digging of the travelnet + return false; +end diff --git a/init.lua b/init.lua index cb084a2..a41fe4b 100644 --- a/init.lua +++ b/init.lua @@ -34,16 +34,11 @@ travelnet = {}; travelnet.targets = {}; travelnet.path = minetest.get_modpath(minetest.get_current_modname()) - --- Minetest Translator -local S = minetest.get_translator("travelnet") -travelnet.S = S - -- privs dofile(travelnet.path.."/privs.lua"); -- read the configuration -dofile(travelnet.path.."/config.lua"); -- the normal, default travelnet +dofile(travelnet.path.."/config.lua"); -- saving / reading dofile(travelnet.path.."/persistence.lua"); @@ -54,775 +49,14 @@ dofile(travelnet.path.."/functions.lua"); -- formspec stuff dofile(travelnet.path.."/formspecs.lua"); +-- travelnet / elevator update +dofile(travelnet.path.."/update_formspec.lua"); +-- add button +dofile(travelnet.path.."/add_target.lua"); - -travelnet.update_formspec = function( pos, puncher_name, fields ) - local meta = minetest.get_meta(pos); - - local this_node = minetest.get_node( pos ); - local is_elevator = false; - - if( this_node ~= nil and this_node.name == 'travelnet:elevator' ) then - is_elevator = true; - end - - if( not( meta )) then - return; - end - - local owner_name = meta:get_string( "owner" ); - local station_name = meta:get_string( "station_name" ); - local station_network = meta:get_string( "station_network" ); - - if( not( owner_name ) - or not( station_name ) or station_network == '' - or not( station_network )) then - - - if( is_elevator == true ) then - travelnet.add_target( nil, nil, pos, puncher_name, meta, owner_name ); - return; - end - - travelnet.reset_formspec( meta ); - travelnet.show_message( pos, puncher_name, "Error", S("Update failed! Resetting this box on the travelnet.")); - return; - end - - -- if the station got lost from the network for some reason (savefile corrupted?) then add it again - if( not( travelnet.targets[ owner_name ] ) - or not( travelnet.targets[ owner_name ][ station_network ] ) - or not( travelnet.targets[ owner_name ][ station_network ][ station_name ] )) then - - -- first one by this player? - if( not( travelnet.targets[ owner_name ] )) then - travelnet.targets[ owner_name ] = {}; - end - - -- first station on this network? - if( not( travelnet.targets[ owner_name ][ station_network ] )) then - travelnet.targets[ owner_name ][ station_network ] = {}; - end - - - local zeit = meta:get_int("timestamp"); - if( not( zeit) or type(zeit)~="number" or zeit<100000 ) then - zeit = os.time(); - end - - -- add this station - travelnet.targets[ owner_name ][ station_network ][ station_name ] = {pos=pos, timestamp=zeit }; - - minetest.chat_send_player(owner_name, S("Station '@1'" .." ".. - "has been reattached to the network '@2'.", station_name, station_network)); - travelnet.save_data(); - end - - - -- add name of station + network + owner + update-button - local zusatzstr = ""; - local trheight = "10"; - if( this_node and this_node.name=="locked_travelnet:travelnet" and locks) then - zusatzstr = "field[0.3,11;6,0.7;locks_sent_lock_command;"..S("Locked travelnet. Type /help for help:")..";]".. - locks.get_authorize_button(10,"10.5").. - locks.get_config_button(11,"10.5") - trheight = "11.5"; - end - local formspec = "size[12,"..trheight.."]".. - "label[3.3,0.0;"..S("Travelnet-Box")..":]".."label[6.3,0.0;".. - S("Punch box to update target list.").."]".. - "label[0.3,0.4;"..S("Name of this station:").."]".. - "label[6.3,0.4;"..minetest.formspec_escape(station_name or "?").."]".. - "label[0.3,0.8;"..S("Assigned to Network:").."]" .. - "label[6.3,0.8;"..minetest.formspec_escape(station_network or "?").."]".. - "label[0.3,1.2;"..S("Owned by:").."]".. - "label[6.3,1.2;"..minetest.formspec_escape(owner_name or "?").."]".. - "label[3.3,1.6;"..S("Click on target to travel there:").."]".. - zusatzstr; --- "button_exit[5.3,0.3;8,0.8;do_update;Punch box to update destination list. Click on target to travel there.]".. - local x = 0; - local y = 0; - local i = 0; - - - -- collect all station names in a table - local stations = {}; - - for k,v in pairs( travelnet.targets[ owner_name ][ station_network ] ) do - table.insert( stations, k ); - end - -- minetest.chat_send_player(puncher_name, "stations: "..minetest.serialize( stations )); - - local ground_level = 1; - if( is_elevator ) then - table.sort( stations, function(a,b) return travelnet.targets[ owner_name ][ station_network ][ a ].pos.y > - travelnet.targets[ owner_name ][ station_network ][ b ].pos.y end); - -- find ground level - local vgl_timestamp = 999999999999; - for index,k in ipairs( stations ) do - if( not( travelnet.targets[ owner_name ][ station_network ][ k ].timestamp )) then - travelnet.targets[ owner_name ][ station_network ][ k ].timestamp = os.time(); - end - if( travelnet.targets[ owner_name ][ station_network ][ k ].timestamp < vgl_timestamp ) then - vgl_timestamp = travelnet.targets[ owner_name ][ station_network ][ k ].timestamp; - ground_level = index; - end - end - for index,k in ipairs( stations ) do - if( index == ground_level ) then - travelnet.targets[ owner_name ][ station_network ][ k ].nr = S('G'); - else - travelnet.targets[ owner_name ][ station_network ][ k ].nr = tostring( ground_level - index ); - end - end - - else - -- sort the table according to the timestamp (=time the station was configured) - table.sort( stations, function(a,b) - return travelnet.targets[ owner_name ][ station_network ][ a ].timestamp < - travelnet.targets[ owner_name ][ station_network ][ b ].timestamp - end); - end - - -- does the player want to move this station one position up in the list? - -- only the owner and players with the travelnet_attach priv can change the order of the list - -- Note: With elevators, only the "G"(round) marking is actually moved - if( fields - and (fields.move_up or fields.move_down) - and owner_name - and owner_name ~= "" - and ((owner_name == puncher_name) - or (minetest.check_player_privs(puncher_name, {travelnet_attach=true}))) - ) then - - local current_pos = -1; - for index,k in ipairs( stations ) do - if( k==station_name ) then - current_pos = index; - end - end - - local swap_with_pos; - if( fields.move_up ) then - swap_with_pos = current_pos - 1; - else - swap_with_pos = current_pos + 1; - end - -- handle errors - if( swap_with_pos < 1) then - travelnet.show_message( pos, puncher_name, "Info", S("This station is already the first one on the list.")); - return; - elseif( swap_with_pos > #stations ) then - travelnet.show_message( pos, puncher_name, "Info", S("This station is already the last one on the list.")); - return; - else - -- swap the actual data by which the stations are sorted - local old_timestamp = travelnet.targets[ owner_name ][ station_network ][ stations[swap_with_pos]].timestamp; - travelnet.targets[ owner_name ][ station_network ][ stations[swap_with_pos]].timestamp = - travelnet.targets[ owner_name ][ station_network ][ stations[current_pos ]].timestamp; - travelnet.targets[ owner_name ][ station_network ][ stations[current_pos ]].timestamp = - old_timestamp; - - -- for elevators, only the "G"(round) marking is moved; no point in swapping stations - if( not( is_elevator )) then - -- actually swap the stations - local old_val = stations[ swap_with_pos ]; - stations[ swap_with_pos ] = stations[ current_pos ]; - stations[ current_pos ] = old_val; - end - - -- store the changed order - travelnet.save_data(); - end - end - - -- if there are only 8 stations (plus this one), center them in the formspec - if( #stations < 10 ) then - x = 4; - end - - for index,k in ipairs( stations ) do - - -- check if there is an elevator door in front that needs to be opened - local open_door_cmd = false; - if( k==station_name ) then - open_door_cmd = true; - end - - if( k ~= station_name or open_door_cmd) then - i = i+1; - - -- new column - if( y==8 ) then - x = x+4; - y = 0; - end - - if( open_door_cmd ) then - formspec = formspec .."button_exit["..(x)..","..(y+2.5)..";1,0.5;open_door;<>]".. - "label["..(x+0.9)..","..(y+2.35)..";"..tostring( k ).."]"; - elseif( is_elevator ) then - formspec = formspec .."button_exit["..(x)..","..(y+2.5)..";1,0.5;target;".. - tostring( travelnet.targets[ owner_name ][ station_network ][ k ].nr ).."]".. - "label["..(x+0.9)..","..(y+2.35)..";"..tostring( k ).."]"; - else - formspec = formspec .."button_exit["..(x)..","..(y+2.5)..";4,0.5;target;"..k.."]"; - end - - y = y+1; - --x = x+4; - end - end - formspec = formspec.. - "label[8.0,1.6;"..S("Position in list:").."]".. - "button_exit[11.3,0.0;1.0,0.5;station_exit;"..S("Exit").."]".. - "button_exit[10.0,0.5;2.2,0.7;station_dig;"..S("Remove station").."]".. - "button[9.6,1.6;1.4,0.5;move_up;"..S("move up").."]".. - "button[10.9,1.6;1.4,0.5;move_down;"..S("move down").."]"; - - meta:set_string( "formspec", formspec ); - - meta:set_string( "infotext", S("Station '@1'".." ".. - "on travelnet '@2' (owned by @3)" .." ".. - "ready for usage. Right-click to travel, punch to update.", - tostring(station_name), tostring(station_network), tostring(owner_name))); - - -- show the player the updated formspec - travelnet.show_current_formspec( pos, meta, puncher_name ); -end - - - --- add a new target; meta is optional -travelnet.add_target = function( station_name, network_name, pos, player_name, meta, owner_name ) - - -- if it is an elevator, determine the network name through x and z coordinates - local this_node = minetest.get_node( pos ); - local is_elevator = false; - - if( this_node.name == 'travelnet:elevator' ) then --- owner_name = '*'; -- the owner name is not relevant here - is_elevator = true; - network_name = tostring( pos.x )..','..tostring( pos.z ); - if( not( station_name ) or station_name == '' ) then - station_name = S("at @1 m", tostring( pos.y )); - end - end - - if( station_name == "" or not(station_name )) then - travelnet.show_message( pos, player_name, S("Error"), S("Please provide a name for this station." )); - return; - end - - if( network_name == "" or not( network_name )) then - travelnet.show_message( pos, player_name, S("Error"), - S("Please provide the name of the network this station ought to be connected to.")); - return; - end - - if( owner_name == nil or owner_name == '' or owner_name == player_name) then - owner_name = player_name; - - elseif( is_elevator ) then -- elevator networks - owner_name = player_name; - - elseif( not( minetest.check_player_privs(player_name, {interact=true}))) then - - travelnet.show_message( pos, player_name, S("Error"), - S("There is no player with interact privilege named '@1'. Aborting.", tostring( player_name))); - return; - - elseif( not( minetest.check_player_privs(player_name, {travelnet_attach=true})) - and not( travelnet.allow_attach( player_name, owner_name, network_name ))) then - - travelnet.show_message( pos, player_name, S("Error"), - S("You do not have the travelnet_attach priv which is required to attach your box to ".. - "the network of someone else. Aborting.")); - return; - end - - -- first one by this player? - if( not( travelnet.targets[ owner_name ] )) then - travelnet.targets[ owner_name ] = {}; - end - - -- first station on this network? - if( not( travelnet.targets[ owner_name ][ network_name ] )) then - travelnet.targets[ owner_name ][ network_name ] = {}; - end - - -- lua doesn't allow efficient counting here - local anz = 0; - for k,v in pairs( travelnet.targets[ owner_name ][ network_name ] ) do - - if( k == station_name ) then - travelnet.show_message( pos, player_name, S("Error"), - S("A station named '@1' already exists on this network. Please choose a diffrent name!", station_name)); - return; - end - - anz = anz + 1; - end - - -- we don't want too many stations in the same network because that would get confusing when displaying the targets - if( anz+1 > travelnet.MAX_STATIONS_PER_NETWORK ) then - travelnet.show_message( pos, player_name, S("Error"), - S("Network '@1', already contains the maximum number (@2) of allowed stations per network. ".. - "Please choose a different/new network name.", network_name, travelnet.MAX_STATIONS_PER_NETWORK)); - return; - end - - -- add this station - travelnet.targets[ owner_name ][ network_name ][ station_name ] = {pos=pos, timestamp=os.time() }; - - -- do we have a new node to set up? (and are not just reading from a safefile?) - if( meta ) then - - minetest.chat_send_player(player_name, S("Station '@1'" .." ".. - "has been added to the network '@2'" .. - ", which now consists of @3 station(s).", station_name, network_name, anz+1)); - - meta:set_string( "station_name", station_name ); - meta:set_string( "station_network", network_name ); - meta:set_string( "owner", owner_name ); - meta:set_int( "timestamp", travelnet.targets[ owner_name ][ network_name ][ station_name ].timestamp); - - meta:set_string("formspec", - "size[12,10]".. - "field[0.3,0.6;6,0.7;station_name;"..S("Station:")..";".. - minetest.formspec_escape(meta:get_string("station_name")).."]".. - "field[0.3,3.6;6,0.7;station_network;"..S("Network:")..";".. - minetest.formspec_escape(meta:get_string("station_network")).."]" ); - - -- display a list of all stations that can be reached from here - travelnet.update_formspec( pos, player_name, nil ); - - -- save the updated network data in a savefile over server restart - travelnet.save_data(); - end -end - - - --- allow doors to open -travelnet.open_close_door = function( pos, player, mode ) - - local this_node = minetest.get_node_or_nil( pos ); - -- give up if the area is *still* not loaded - if( this_node == nil ) then - return - end - local pos2 = {x=pos.x,y=pos.y,z=pos.z}; - - if( this_node.param2 == 0 ) then pos2 = {x=pos.x,y=pos.y,z=(pos.z-1)}; - elseif( this_node.param2 == 1 ) then pos2 = {x=(pos.x-1),y=pos.y,z=pos.z}; - elseif( this_node.param2 == 2 ) then pos2 = {x=pos.x,y=pos.y,z=(pos.z+1)}; - elseif( this_node.param2 == 3 ) then pos2 = {x=(pos.x+1),y=pos.y,z=pos.z}; - end - - local door_node = minetest.get_node( pos2 ); - if door_node ~= nil and - door_node.name ~= 'ignore' and - door_node.name ~= 'air' and - minetest.registered_nodes[ door_node.name ] ~= nil and - minetest.registered_nodes[ door_node.name ].on_rightclick ~= nil then - - -- at least for homedecor, same facedir would mean "door closed" - - -- do not close the elevator door if it is already closed - if( mode==1 and ( string.sub( door_node.name, -7 ) == '_closed' - -- handle doors that change their facedir - or ( door_node.param2 == ((this_node.param2 + 2)%4) - and door_node.name ~= 'travelnet:elevator_door_glass_open' - and door_node.name ~= 'travelnet:elevator_door_tin_open' - and door_node.name ~= 'travelnet:elevator_door_steel_open'))) then - return; - end - -- do not open the doors if they are already open (works only on elevator-doors; not on doors in general) - if( mode==2 and ( string.sub( door_node.name, -5 ) == '_open' - -- handle doors that change their facedir - or ( door_node.param2 ~= ((this_node.param2 + 2)%4) - and door_node.name ~= 'travelnet:elevator_door_glass_closed' - and door_node.name ~= 'travelnet:elevator_door_tin_closed' - and door_node.name ~= 'travelnet:elevator_door_steel_closed'))) then - return; - end - - if( mode==2 ) then - minetest.after( 1, minetest.registered_nodes[ door_node.name ].on_rightclick, pos2, door_node, player ); - else - minetest.registered_nodes[ door_node.name ].on_rightclick(pos2, door_node, player); - end - end -end - - -travelnet.on_receive_fields = function(pos, formname, fields, player) - if( not( pos )) then - return; - end - local meta = minetest.get_meta(pos); - - local name = player:get_player_name(); - - -- the player wants to quit/exit the formspec; do not save/update anything - if( fields and fields.station_exit and fields.station_exit ~= "" ) then - return; - end - - -- show special locks buttons if needed - if( locks and (fields.locks_config or fields.locks_authorize)) then - return locks:lock_handle_input( pos, formname, fields, player ) - end - - -- show help text - if( fields and fields.station_help_setup and fields.station_help_setup ~= "") then - -- simulate right-click - local node = minetest.get_node( pos ); - if( node and node.name and minetest.registered_nodes[ node.name ] ) then - travelnet.show_message( pos, name, S("--> Help <--"), --- TODO: actually add help page - S("No help available yet.")); - end - return; - end - - -- the player wants to remove the station - if( fields.station_dig ) then - local owner = meta:get_string( "owner" ); - local network_name = meta:get_string("station_network") - local node = minetest.get_node(pos) - local description - if( node and node.name and node.name == "travelnet:travelnet") then - description = "travelnet box" - elseif( node and node.name and node.name == "travelnet:elevator") then - description = "elevator" - elseif( node and node.name and node.name == "locked_travelnet:travelnet") then - description = "locked travelnet" - else - minetest.chat_send_player(name, "Error: Unkown node."); - return - end - -- players with travelnet_remove priv can dig the station - if( not(minetest.check_player_privs(name, {travelnet_remove=true})) - -- the function travelnet.allow_dig(..) may allow additional digging - and not(travelnet.allow_dig( name, owner, network_name, pos )) - -- the owner can remove the station - and owner ~= name - -- stations without owner can be removed by anybody - and owner ~= "") then - minetest.chat_send_player(name, - S("This %s belongs to %s. You can't remove it."):format( - description, - tostring( meta:get_string('owner')) - ) - ); - return - end - - -- abort if protected by another mod - if( minetest.is_protected(pos, name) - and not(minetest.check_player_privs(name, {protection_bypass=true})) ) then - minetest.record_protection_violation(pos, name) - return - end - - local pinv = player:get_inventory() - if(not(pinv:room_for_item("main", node.name))) then - minetest.chat_send_player(name, S("You do not have enough room in your inventory.")); - return - end - - -- give the player the box - pinv:add_item("main", node.name) - -- remove the box from the data structure - travelnet.remove_box( pos, nil, meta:to_table(), player ); - -- remove the node as such - minetest.remove_node(pos) - return; - end - - - - - -- if the box has not been configured yet - if( meta:get_string("station_network")=="" ) then - - travelnet.add_target( fields.station_name, fields.station_network, pos, name, meta, fields.owner ); - return; - end - - if( fields.open_door ) then - travelnet.open_close_door( pos, player, 0 ); - return; - end - - -- the owner or players with the travelnet_attach priv can move stations up or down in the list - if( fields.move_up or fields.move_down) then - travelnet.update_formspec( pos, name, fields ); - return; - end - - if( not( fields.target )) then - minetest.chat_send_player(name, S("Please click on the target you want to travel to.")); - return; - end - - - -- if there is something wrong with the data - local owner_name = meta:get_string( "owner" ); - local station_name = meta:get_string( "station_name" ); - local station_network = meta:get_string( "station_network" ); - - if( not( owner_name ) - or not( station_name ) - or not( station_network ) - or not( travelnet.targets[ owner_name ] ) - or not( travelnet.targets[ owner_name ][ station_network ] )) then - - - if( owner_name - and station_name - and station_network ) then - travelnet.add_target( station_name, station_network, pos, owner_name, meta, owner_name ); - else - minetest.chat_send_player(name, S("Error")..": ".. - S("There is something wrong with the configuration of this station.").. - " DEBUG DATA: owner: "..( owner_name or "?").. - " station_name: "..(station_name or "?").. - " station_network: "..(station_network or "?").."."); - return - end - end - - if( not( owner_name ) - or not( station_network ) - or not( travelnet.targets ) - or not( travelnet.targets[ owner_name ] ) - or not( travelnet.targets[ owner_name ][ station_network ] )) then - minetest.chat_send_player(name, S("Error")..": ".. - S("This travelnet is lacking data and/or improperly configured.")); - print( "ERROR: The travelnet at "..minetest.pos_to_string( pos ).." has a problem: ".. - " DATA: owner: "..( owner_name or "?").. - " station_name: "..(station_name or "?").. - " station_network: "..(station_network or "?").."."); - return; - end - - local this_node = minetest.get_node( pos ); - if( this_node ~= nil and this_node.name == 'travelnet:elevator' ) then - for k,v in pairs( travelnet.targets[ owner_name ][ station_network ] ) do - if( travelnet.targets[ owner_name ][ station_network ][ k ].nr - == fields.target) then - fields.target = k; - end - end - end - - - -- if the target station is gone - if( not( travelnet.targets[ owner_name ][ station_network ][ fields.target ] )) then - - minetest.chat_send_player(name, S("Station '@1' does not exist (anymore?)" .. - " " .. "on this network.", fields.target or "?")); - travelnet.update_formspec( pos, name, nil ); - return; - end - - - if( not( travelnet.allow_travel( name, owner_name, station_network, station_name, fields.target ))) then - return; - end - minetest.chat_send_player(name, S("Initiating transfer to station '@1'.", fields.target or "?")); - - - - if( travelnet.travelnet_sound_enabled ) then - if ( this_node.name == 'travelnet:elevator' ) then - minetest.sound_play("travelnet_bell", {pos = pos, gain = 0.75, max_hear_distance = 10,}); - else - minetest.sound_play("travelnet_travel", {pos = pos, gain = 0.75, max_hear_distance = 10,}); - end - end - if( travelnet.travelnet_effect_enabled ) then - minetest.add_entity( {x=pos.x,y=pos.y+0.5,z=pos.z}, "travelnet:effect"); -- it self-destructs after 20 turns - end - - -- close the doors at the sending station - travelnet.open_close_door( pos, player, 1 ); - - -- transport the player to the target location - - -- may be 0.0 for some versions of MT 5 player model - local player_model_bottom = tonumber(minetest.settings:get("player_model_bottom")) or -.5; - local player_model_vec = vector.new(0, player_model_bottom, 0); - local target_pos = travelnet.targets[ owner_name ][ station_network ][ fields.target ].pos; - - local top_pos = {x=pos.x, y=pos.y+1, z=pos.z} - local top_node = minetest.get_node(top_pos) - if top_node.name ~= "travelnet:hidden_top" then - local def = minetest.registered_nodes[top_node.name] - if def and def.buildable_to then - minetest.set_node(top_pos, {name="travelnet:hidden_top"}) - end - end - - player:move_to( vector.add(target_pos, player_model_vec), false); - - if( travelnet.enable_travelnet_effect ) then - -- it self-destructs after 20 turns - minetest.add_entity( {x=target_pos.x,y=target_pos.y+0.5,z=target_pos.z}, "travelnet:effect"); - end - - - -- check if the box has at the other end has been removed. - local node2 = minetest.get_node_or_nil( target_pos ); - if node2 ~= nil and - node2.name ~= 'ignore' and - node2.name ~= 'travelnet:travelnet' and - node2.name ~= 'travelnet:elevator' and - node2.name ~= "locked_travelnet:travelnet" and - node2.name ~= "travelnet:travelnet_private" then - - -- provide information necessary to identify the removed box - local oldmetadata = { fields = { owner = owner_name, - station_name = fields.target, - station_network = station_network }}; - - travelnet.remove_box( target_pos, nil, oldmetadata, player ); - -- send the player back as there's no receiving travelnet - player:move_to( pos, false ); - - else - travelnet.rotate_player( target_pos, player, 0 ) - end -end - -travelnet.rotate_player = function( target_pos, player, tries ) - -- try later when the box is loaded - local node2 = minetest.get_node_or_nil( target_pos ); - if( node2 == nil ) then - if( tries < 30 ) then - minetest.after( 0, travelnet.rotate_player, target_pos, player, tries+1 ) - end - return - end - - -- play sound at the target position as well - if( travelnet.travelnet_sound_enabled ) then - if ( node2.name == 'travelnet:elevator' ) then - minetest.sound_play("travelnet_bell", {pos = target_pos, gain = 0.75, max_hear_distance = 10,}); - else - minetest.sound_play("travelnet_travel", {pos = target_pos, gain = 0.75, max_hear_distance = 10,}); - end - end - - -- do this only on servers where the function exists - if( player.set_look_horizontal ) then - -- rotate the player so that he/she can walk straight out of the box - local yaw = 0; - local param2 = node2.param2; - if( param2==0 ) then - yaw = 180; - elseif( param2==1 ) then - yaw = 90; - elseif( param2==2 ) then - yaw = 0; - elseif( param2==3 ) then - yaw = 270; - end - - player:set_look_horizontal( math.rad( yaw )); - player:set_look_vertical( math.rad( 0 )); - end - - travelnet.open_close_door( target_pos, player, 2 ); -end - - -travelnet.remove_box = function( pos, oldnode, oldmetadata, digger ) - - if( not( oldmetadata ) or oldmetadata=="nil" or not(oldmetadata.fields)) then - minetest.chat_send_player( digger:get_player_name(), S("Error")..": ".. - S("Could not find information about the station that is to be removed.")); - return; - end - - local owner_name = oldmetadata.fields[ "owner" ]; - local station_name = oldmetadata.fields[ "station_name" ]; - local station_network = oldmetadata.fields[ "station_network" ]; - - -- station is not known? then just remove it - if( not( owner_name ) - or not( station_name ) - or not( station_network ) - or not( travelnet.targets[ owner_name ] ) - or not( travelnet.targets[ owner_name ][ station_network ] )) then - - minetest.chat_send_player( digger:get_player_name(), S("Error")..": ".. - S("Could not find the station that is to be removed.")); - return; - end - - travelnet.targets[ owner_name ][ station_network ][ station_name ] = nil; - - -- inform the owner - minetest.chat_send_player( owner_name, S("Station '@1'" .." ".. - "has been REMOVED from the network '@2'.", station_name, station_network)); - if( digger ~= nil and owner_name ~= digger:get_player_name() ) then - minetest.chat_send_player( digger:get_player_name(), S("Station '@1'" .." ".. - "has been REMOVED from the network '@2'.", station_name, station_network)); - end - - -- save the updated network data in a savefile over server restart - travelnet.save_data(); -end - - - -travelnet.can_dig = function( pos, player, description ) - -- forbid digging of the travelnet - return false; -end - --- obsolete function -travelnet.can_dig_old = function( pos, player, description ) - if( not( player )) then - return false; - end - local name = player:get_player_name(); - local meta = minetest.get_meta( pos ); - local owner = meta:get_string('owner'); - local network_name = meta:get_string( "station_network" ); - - -- in creative mode, accidental digging could happen too easily when trying to update the net - if(creative and creative.is_enabled_for(player:get_player_name())) then - -- only a diamond pick can dig the travelnet - if( not(player:get_wielded_item()) - or player:get_wielded_item():get_name()~="default:pick_diamond") then - return false; - end - end - - -- players with that priv can dig regardless of owner - if( minetest.check_player_privs(name, {travelnet_remove=true}) - or travelnet.allow_dig( name, owner, network_name, pos )) then - return true; - end - - if( not( meta ) or not( owner) or owner=='') then - minetest.chat_send_player(name, S("This @1 has not been configured yet. Please set it up first to claim it." .. - " " .. "Afterwards you can remove it because you are then the owner.", description)); - return false; - - elseif( owner ~= name ) then - minetest.chat_send_player(name, S("This @1 belongs to @2. You can't remove it.", - description, tostring(meta:get_string('owner')))); - return false; - end - return true; -end +-- receive fields handler +dofile(travelnet.path.."/on_receive_fields.lua"); -- invisible node to place inside top of travelnet box and elevator minetest.register_node("travelnet:hidden_top", { diff --git a/on_receive_fields.lua b/on_receive_fields.lua new file mode 100644 index 0000000..1b12d2f --- /dev/null +++ b/on_receive_fields.lua @@ -0,0 +1,243 @@ +local S = minetest.get_translator("travelnet") + + +travelnet.on_receive_fields = function(pos, formname, fields, player) + if( not( pos )) then + return; + end + local meta = minetest.get_meta(pos); + + local name = player:get_player_name(); + + -- the player wants to quit/exit the formspec; do not save/update anything + if( fields and fields.station_exit and fields.station_exit ~= "" ) then + return; + end + + -- show special locks buttons if needed + if( locks and (fields.locks_config or fields.locks_authorize)) then + return locks:lock_handle_input( pos, formname, fields, player ) + end + + -- show help text + if( fields and fields.station_help_setup and fields.station_help_setup ~= "") then + -- simulate right-click + local node = minetest.get_node( pos ); + if( node and node.name and minetest.registered_nodes[ node.name ] ) then + travelnet.show_message( pos, name, S("--> Help <--"), +-- TODO: actually add help page + S("No help available yet.")); + end + return; + end + + -- the player wants to remove the station + if( fields.station_dig ) then + local owner = meta:get_string( "owner" ); + local network_name = meta:get_string("station_network") + local node = minetest.get_node(pos) + local description + if( node and node.name and node.name == "travelnet:travelnet") then + description = "travelnet box" + elseif( node and node.name and node.name == "travelnet:elevator") then + description = "elevator" + elseif( node and node.name and node.name == "locked_travelnet:travelnet") then + description = "locked travelnet" + else + minetest.chat_send_player(name, "Error: Unkown node."); + return + end + -- players with travelnet_remove priv can dig the station + if( not(minetest.check_player_privs(name, {travelnet_remove=true})) + -- the function travelnet.allow_dig(..) may allow additional digging + and not(travelnet.allow_dig( name, owner, network_name, pos )) + -- the owner can remove the station + and owner ~= name + -- stations without owner can be removed by anybody + and owner ~= "") then + minetest.chat_send_player(name, + S("This %s belongs to %s. You can't remove it."):format( + description, + tostring( meta:get_string('owner')) + ) + ); + return + end + + -- abort if protected by another mod + if( minetest.is_protected(pos, name) + and not(minetest.check_player_privs(name, {protection_bypass=true})) ) then + minetest.record_protection_violation(pos, name) + return + end + + local pinv = player:get_inventory() + if(not(pinv:room_for_item("main", node.name))) then + minetest.chat_send_player(name, S("You do not have enough room in your inventory.")); + return + end + + -- give the player the box + pinv:add_item("main", node.name) + -- remove the box from the data structure + travelnet.remove_box( pos, nil, meta:to_table(), player ); + -- remove the node as such + minetest.remove_node(pos) + return; + end + + + + + -- if the box has not been configured yet + if( meta:get_string("station_network")=="" ) then + + travelnet.add_target( fields.station_name, fields.station_network, pos, name, meta, fields.owner ); + return; + end + + if( fields.open_door ) then + travelnet.open_close_door( pos, player, 0 ); + return; + end + + -- the owner or players with the travelnet_attach priv can move stations up or down in the list + if( fields.move_up or fields.move_down) then + travelnet.update_formspec( pos, name, fields ); + return; + end + + if( not( fields.target )) then + minetest.chat_send_player(name, S("Please click on the target you want to travel to.")); + return; + end + + + -- if there is something wrong with the data + local owner_name = meta:get_string( "owner" ); + local station_name = meta:get_string( "station_name" ); + local station_network = meta:get_string( "station_network" ); + + if( not( owner_name ) + or not( station_name ) + or not( station_network ) + or not( travelnet.targets[ owner_name ] ) + or not( travelnet.targets[ owner_name ][ station_network ] )) then + + + if( owner_name + and station_name + and station_network ) then + travelnet.add_target( station_name, station_network, pos, owner_name, meta, owner_name ); + else + minetest.chat_send_player(name, S("Error")..": ".. + S("There is something wrong with the configuration of this station.").. + " DEBUG DATA: owner: "..( owner_name or "?").. + " station_name: "..(station_name or "?").. + " station_network: "..(station_network or "?").."."); + return + end + end + + if( not( owner_name ) + or not( station_network ) + or not( travelnet.targets ) + or not( travelnet.targets[ owner_name ] ) + or not( travelnet.targets[ owner_name ][ station_network ] )) then + minetest.chat_send_player(name, S("Error")..": ".. + S("This travelnet is lacking data and/or improperly configured.")); + print( "ERROR: The travelnet at "..minetest.pos_to_string( pos ).." has a problem: ".. + " DATA: owner: "..( owner_name or "?").. + " station_name: "..(station_name or "?").. + " station_network: "..(station_network or "?").."."); + return; + end + + local this_node = minetest.get_node( pos ); + if( this_node ~= nil and this_node.name == 'travelnet:elevator' ) then + for k,v in pairs( travelnet.targets[ owner_name ][ station_network ] ) do + if( travelnet.targets[ owner_name ][ station_network ][ k ].nr + == fields.target) then + fields.target = k; + end + end + end + + + -- if the target station is gone + if( not( travelnet.targets[ owner_name ][ station_network ][ fields.target ] )) then + + minetest.chat_send_player(name, S("Station '@1' does not exist (anymore?)" .. + " " .. "on this network.", fields.target or "?")); + travelnet.update_formspec( pos, name, nil ); + return; + end + + + if( not( travelnet.allow_travel( name, owner_name, station_network, station_name, fields.target ))) then + return; + end + minetest.chat_send_player(name, S("Initiating transfer to station '@1'.", fields.target or "?")); + + + + if( travelnet.travelnet_sound_enabled ) then + if ( this_node.name == 'travelnet:elevator' ) then + minetest.sound_play("travelnet_bell", {pos = pos, gain = 0.75, max_hear_distance = 10,}); + else + minetest.sound_play("travelnet_travel", {pos = pos, gain = 0.75, max_hear_distance = 10,}); + end + end + if( travelnet.travelnet_effect_enabled ) then + minetest.add_entity( {x=pos.x,y=pos.y+0.5,z=pos.z}, "travelnet:effect"); -- it self-destructs after 20 turns + end + + -- close the doors at the sending station + travelnet.open_close_door( pos, player, 1 ); + + -- transport the player to the target location + + -- may be 0.0 for some versions of MT 5 player model + local player_model_bottom = tonumber(minetest.settings:get("player_model_bottom")) or -.5; + local player_model_vec = vector.new(0, player_model_bottom, 0); + local target_pos = travelnet.targets[ owner_name ][ station_network ][ fields.target ].pos; + + local top_pos = {x=pos.x, y=pos.y+1, z=pos.z} + local top_node = minetest.get_node(top_pos) + if top_node.name ~= "travelnet:hidden_top" then + local def = minetest.registered_nodes[top_node.name] + if def and def.buildable_to then + minetest.set_node(top_pos, {name="travelnet:hidden_top"}) + end + end + + player:move_to( vector.add(target_pos, player_model_vec), false); + + if( travelnet.enable_travelnet_effect ) then + -- it self-destructs after 20 turns + minetest.add_entity( {x=target_pos.x,y=target_pos.y+0.5,z=target_pos.z}, "travelnet:effect"); + end + + + -- check if the box has at the other end has been removed. + local node2 = minetest.get_node_or_nil( target_pos ); + if node2 ~= nil and + node2.name ~= 'ignore' and + node2.name ~= 'travelnet:travelnet' and + node2.name ~= 'travelnet:elevator' and + node2.name ~= "locked_travelnet:travelnet" and + node2.name ~= "travelnet:travelnet_private" then + + -- provide information necessary to identify the removed box + local oldmetadata = { fields = { owner = owner_name, + station_name = fields.target, + station_network = station_network }}; + + travelnet.remove_box( target_pos, nil, oldmetadata, player ); + -- send the player back as there's no receiving travelnet + player:move_to( pos, false ); + + else + travelnet.rotate_player( target_pos, player, 0 ) + end +end diff --git a/travelnet.lua b/travelnet.lua index d91e694..796df7a 100644 --- a/travelnet.lua +++ b/travelnet.lua @@ -4,7 +4,8 @@ -- travelnet_remove priv (useful for admins to clean up) -- (this can be overrided in config.lua) -- Author: Sokomine -local S = travelnet.S; + +local S = minetest.get_translator("travelnet") minetest.register_node("travelnet:travelnet", { @@ -98,7 +99,6 @@ minetest.register_node("travelnet:travelnet", { end }) ---[ minetest.register_craft({ output = "travelnet:travelnet", recipe = travelnet.travelnet_recipe, diff --git a/update_formspec.lua b/update_formspec.lua new file mode 100644 index 0000000..90ba40a --- /dev/null +++ b/update_formspec.lua @@ -0,0 +1,237 @@ +local S = minetest.get_translator("travelnet") + +-- called "on_punch" of travelnet and elevator +travelnet.update_formspec = function( pos, puncher_name, fields ) + local meta = minetest.get_meta(pos); + + local this_node = minetest.get_node( pos ); + local is_elevator = false; + + if( this_node ~= nil and this_node.name == 'travelnet:elevator' ) then + is_elevator = true; + end + + if( not( meta )) then + return; + end + + local owner_name = meta:get_string( "owner" ); + local station_name = meta:get_string( "station_name" ); + local station_network = meta:get_string( "station_network" ); + + if( not( owner_name ) + or not( station_name ) or station_network == '' + or not( station_network )) then + + + if( is_elevator == true ) then + travelnet.add_target( nil, nil, pos, puncher_name, meta, owner_name ); + return; + end + + travelnet.reset_formspec( meta ); + travelnet.show_message( pos, puncher_name, "Error", S("Update failed! Resetting this box on the travelnet.")); + return; + end + + -- if the station got lost from the network for some reason (savefile corrupted?) then add it again + if( not( travelnet.targets[ owner_name ] ) + or not( travelnet.targets[ owner_name ][ station_network ] ) + or not( travelnet.targets[ owner_name ][ station_network ][ station_name ] )) then + + -- first one by this player? + if( not( travelnet.targets[ owner_name ] )) then + travelnet.targets[ owner_name ] = {}; + end + + -- first station on this network? + if( not( travelnet.targets[ owner_name ][ station_network ] )) then + travelnet.targets[ owner_name ][ station_network ] = {}; + end + + + local zeit = meta:get_int("timestamp"); + if( not( zeit) or type(zeit)~="number" or zeit<100000 ) then + zeit = os.time(); + end + + -- add this station + travelnet.targets[ owner_name ][ station_network ][ station_name ] = {pos=pos, timestamp=zeit }; + + minetest.chat_send_player(owner_name, S("Station '@1'" .." ".. + "has been reattached to the network '@2'.", station_name, station_network)); + travelnet.save_data(); + end + + + -- add name of station + network + owner + update-button + local zusatzstr = ""; + local trheight = "10"; + if( this_node and this_node.name=="locked_travelnet:travelnet" and locks) then + zusatzstr = "field[0.3,11;6,0.7;locks_sent_lock_command;"..S("Locked travelnet. Type /help for help:")..";]".. + locks.get_authorize_button(10,"10.5").. + locks.get_config_button(11,"10.5") + trheight = "11.5"; + end + local formspec = "size[12,"..trheight.."]".. + "label[3.3,0.0;"..S("Travelnet-Box")..":]".."label[6.3,0.0;".. + S("Punch box to update target list.").."]".. + "label[0.3,0.4;"..S("Name of this station:").."]".. + "label[6.3,0.4;"..minetest.formspec_escape(station_name or "?").."]".. + "label[0.3,0.8;"..S("Assigned to Network:").."]" .. + "label[6.3,0.8;"..minetest.formspec_escape(station_network or "?").."]".. + "label[0.3,1.2;"..S("Owned by:").."]".. + "label[6.3,1.2;"..minetest.formspec_escape(owner_name or "?").."]".. + "label[3.3,1.6;"..S("Click on target to travel there:").."]".. + zusatzstr; +-- "button_exit[5.3,0.3;8,0.8;do_update;Punch box to update destination list. Click on target to travel there.]".. + local x = 0; + local y = 0; + local i = 0; + + + -- collect all station names in a table + local stations = {}; + + for k,v in pairs( travelnet.targets[ owner_name ][ station_network ] ) do + table.insert( stations, k ); + end + -- minetest.chat_send_player(puncher_name, "stations: "..minetest.serialize( stations )); + + local ground_level = 1; + if( is_elevator ) then + table.sort( stations, function(a,b) return travelnet.targets[ owner_name ][ station_network ][ a ].pos.y > + travelnet.targets[ owner_name ][ station_network ][ b ].pos.y end); + -- find ground level + local vgl_timestamp = 999999999999; + for index,k in ipairs( stations ) do + if( not( travelnet.targets[ owner_name ][ station_network ][ k ].timestamp )) then + travelnet.targets[ owner_name ][ station_network ][ k ].timestamp = os.time(); + end + if( travelnet.targets[ owner_name ][ station_network ][ k ].timestamp < vgl_timestamp ) then + vgl_timestamp = travelnet.targets[ owner_name ][ station_network ][ k ].timestamp; + ground_level = index; + end + end + for index,k in ipairs( stations ) do + if( index == ground_level ) then + travelnet.targets[ owner_name ][ station_network ][ k ].nr = S('G'); + else + travelnet.targets[ owner_name ][ station_network ][ k ].nr = tostring( ground_level - index ); + end + end + + else + -- sort the table according to the timestamp (=time the station was configured) + table.sort( stations, function(a,b) + return travelnet.targets[ owner_name ][ station_network ][ a ].timestamp < + travelnet.targets[ owner_name ][ station_network ][ b ].timestamp + end); + end + + -- does the player want to move this station one position up in the list? + -- only the owner and players with the travelnet_attach priv can change the order of the list + -- Note: With elevators, only the "G"(round) marking is actually moved + if( fields + and (fields.move_up or fields.move_down) + and owner_name + and owner_name ~= "" + and ((owner_name == puncher_name) + or (minetest.check_player_privs(puncher_name, {travelnet_attach=true}))) + ) then + + local current_pos = -1; + for index,k in ipairs( stations ) do + if( k==station_name ) then + current_pos = index; + end + end + + local swap_with_pos; + if( fields.move_up ) then + swap_with_pos = current_pos - 1; + else + swap_with_pos = current_pos + 1; + end + -- handle errors + if( swap_with_pos < 1) then + travelnet.show_message( pos, puncher_name, "Info", S("This station is already the first one on the list.")); + return; + elseif( swap_with_pos > #stations ) then + travelnet.show_message( pos, puncher_name, "Info", S("This station is already the last one on the list.")); + return; + else + -- swap the actual data by which the stations are sorted + local old_timestamp = travelnet.targets[ owner_name ][ station_network ][ stations[swap_with_pos]].timestamp; + travelnet.targets[ owner_name ][ station_network ][ stations[swap_with_pos]].timestamp = + travelnet.targets[ owner_name ][ station_network ][ stations[current_pos ]].timestamp; + travelnet.targets[ owner_name ][ station_network ][ stations[current_pos ]].timestamp = + old_timestamp; + + -- for elevators, only the "G"(round) marking is moved; no point in swapping stations + if( not( is_elevator )) then + -- actually swap the stations + local old_val = stations[ swap_with_pos ]; + stations[ swap_with_pos ] = stations[ current_pos ]; + stations[ current_pos ] = old_val; + end + + -- store the changed order + travelnet.save_data(); + end + end + + -- if there are only 8 stations (plus this one), center them in the formspec + if( #stations < 10 ) then + x = 4; + end + + for index,k in ipairs( stations ) do + + -- check if there is an elevator door in front that needs to be opened + local open_door_cmd = false; + if( k==station_name ) then + open_door_cmd = true; + end + + if( k ~= station_name or open_door_cmd) then + i = i+1; + + -- new column + if( y==8 ) then + x = x+4; + y = 0; + end + + if( open_door_cmd ) then + formspec = formspec .."button_exit["..(x)..","..(y+2.5)..";1,0.5;open_door;<>]".. + "label["..(x+0.9)..","..(y+2.35)..";"..tostring( k ).."]"; + elseif( is_elevator ) then + formspec = formspec .."button_exit["..(x)..","..(y+2.5)..";1,0.5;target;".. + tostring( travelnet.targets[ owner_name ][ station_network ][ k ].nr ).."]".. + "label["..(x+0.9)..","..(y+2.35)..";"..tostring( k ).."]"; + else + formspec = formspec .."button_exit["..(x)..","..(y+2.5)..";4,0.5;target;"..k.."]"; + end + + y = y+1; + --x = x+4; + end + end + formspec = formspec.. + "label[8.0,1.6;"..S("Position in list:").."]".. + "button_exit[11.3,0.0;1.0,0.5;station_exit;"..S("Exit").."]".. + "button_exit[10.0,0.5;2.2,0.7;station_dig;"..S("Remove station").."]".. + "button[9.6,1.6;1.4,0.5;move_up;"..S("move up").."]".. + "button[10.9,1.6;1.4,0.5;move_down;"..S("move down").."]"; + + meta:set_string( "formspec", formspec ); + + meta:set_string( "infotext", S("Station '@1'".." ".. + "on travelnet '@2' (owned by @3)" .." ".. + "ready for usage. Right-click to travel, punch to update.", + tostring(station_name), tostring(station_network), tostring(owner_name))); + + -- show the player the updated formspec + travelnet.show_current_formspec( pos, meta, puncher_name ); +end