summaryrefslogtreecommitdiff
path: root/travelnet
diff options
context:
space:
mode:
Diffstat (limited to 'travelnet')
-rw-r--r--travelnet/README.md11
-rw-r--r--travelnet/config.lua67
-rw-r--r--travelnet/doors.lua142
-rw-r--r--travelnet/elevator.lua112
-rw-r--r--travelnet/init.lua699
-rw-r--r--travelnet/models/travelnet.obj63
-rw-r--r--travelnet/models/travelnet_elevator.obj64
-rw-r--r--travelnet/restore_network_via_abm.lua24
-rw-r--r--travelnet/textures/travelnet_elevator_door_glass.pngbin0 -> 952 bytes
-rw-r--r--travelnet/textures/travelnet_elevator_front.pngbin0 -> 756 bytes
-rw-r--r--travelnet/textures/travelnet_elevator_inside_ceiling.pngbin0 -> 292 bytes
-rw-r--r--travelnet/textures/travelnet_elevator_inside_controls.pngbin0 -> 832 bytes
-rw-r--r--travelnet/textures/travelnet_elevator_inside_floor.pngbin0 -> 102 bytes
-rw-r--r--travelnet/textures/travelnet_elevator_inv.pngbin0 -> 4946 bytes
-rw-r--r--travelnet/textures/travelnet_elevator_sides_outside.pngbin0 -> 347 bytes
-rw-r--r--travelnet/textures/travelnet_flash.pngbin0 -> 1439 bytes
-rw-r--r--travelnet/textures/travelnet_inv.pngbin0 -> 5680 bytes
-rw-r--r--travelnet/textures/travelnet_travelnet_back.pngbin0 -> 533 bytes
-rw-r--r--travelnet/textures/travelnet_travelnet_front.pngbin0 -> 904 bytes
-rw-r--r--travelnet/textures/travelnet_travelnet_side.pngbin0 -> 731 bytes
-rw-r--r--travelnet/travelnet.lua99
21 files changed, 1281 insertions, 0 deletions
diff --git a/travelnet/README.md b/travelnet/README.md
new file mode 100644
index 0000000..d9bd775
--- /dev/null
+++ b/travelnet/README.md
@@ -0,0 +1,11 @@
+
+How this works:
+
+- craft it by filling the right and left row with glass; place in the middle row (from top to bottom): steel, mese, steel
+- place the travelnet box somewhere
+- right-click on it; enter name of the station (e.g. "my house", "center of desert city") and name of the network (e.g. "intresting towns","my buildings")
+- punch it to update the list of stations on that network
+- right-click to use the travelbox
+
+An unconfigured travelnet box can be configured by anyone. If it is misconfigured, just dig it and place it anew.
+All stations that have the same network name set and are owned by the same user connect to the same network.
diff --git a/travelnet/config.lua b/travelnet/config.lua
new file mode 100644
index 0000000..7673833
--- /dev/null
+++ b/travelnet/config.lua
@@ -0,0 +1,67 @@
+
+travelnet.MAX_STATIONS_PER_NETWORK = 24;
+
+-- set this to true if you want a simulated beam effect
+travelnet.travelnet_effect_enabled = false;
+-- set this to true if you want a sound to be played when the travelnet is used
+travelnet.travelnet_sound_enabled = false;
+
+-- if you set this to false, travelnets cannot be created
+-- (this may be useful if you want nothing but the elevators on your server)
+travelnet.travelnet_enabled = true;
+-- if you set travelnet.elevator_enabled to false, you will not be able to
+-- craft, place or use elevators
+travelnet.elevator_enabled = true;
+-- if you set this to false, doors will be disabled
+travelnet.doors_enabled = true;
+
+-- starts an abm which re-adds travelnet stations to networks in case the savefile got lost
+travelnet.abm_enabled = false;
+
+-- change these if you want other receipes for travelnet or elevator
+travelnet.travelnet_recipe = {
+ {"default:glass", "default:steel_ingot", "default:glass", },
+ {"default:glass", "default:mese", "default:glass", },
+ {"default:glass", "default:steel_ingot", "default:glass", }
+}
+travelnet.elevator_recipe = {
+ {"default:steel_ingot", "default:glass", "default:steel_ingot", },
+ {"default:steel_ingot", "", "default:steel_ingot", },
+ {"default:steel_ingot", "default:glass", "default:steel_ingot", }
+}
+
+-- if this function returns true, the player with the name player_name is
+-- allowed to add a box to the network named network_name, which is owned
+-- by the player owner_name;
+-- if you want to allow *everybody* to attach stations to all nets, let the
+-- function always return true;
+-- if the function returns false, players with the travelnet_attach priv
+-- can still add stations to that network
+
+travelnet.allow_attach = function( player_name, owner_name, network_name )
+ return false;
+end
+
+
+-- if this returns true, a player named player_name can remove a travelnet station
+-- from network_name (owned by owner_name) even though he is neither the owner nor
+-- has the travelnet_remove priv
+travelnet.allow_dig = function( player_name, owner_name, network_name )
+ return false;
+end
+
+
+-- if this function returns false, then player player_name will not be allowed to use
+-- the travelnet station_name_start on networ network_name owned by owner_name to travel to
+-- the station station_name_target on the same network;
+-- if this function returns true, the player will be transfered to the target station;
+-- you can use this code to i.e. charge the player money for the transfer or to limit
+-- usage of stations to players in the same fraction on PvP servers
+travelnet.allow_travel = function( player_name, owner_name, network_name, station_name_start, station_name_target )
+
+ --minetest.chat_send_player( player_name, "Player "..tostring( player_name ).." tries to use station "..tostring( station_name_start )..
+ -- " on network "..tostring( network_name ).." owned by "..tostring( owner_name ).." in order to travel to "..
+ -- tostring( station_name_target )..".");
+
+ return true;
+end
diff --git a/travelnet/doors.lua b/travelnet/doors.lua
new file mode 100644
index 0000000..a45a9f6
--- /dev/null
+++ b/travelnet/doors.lua
@@ -0,0 +1,142 @@
+-- Doors that are especially useful for travelnet elevators but can also be used in other situations.
+-- 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
+
+minetest.register_node("travelnet:elevator_door_steel_open", {
+ description = "elevator door (open)",
+ drawtype = "nodebox",
+ -- top, bottom, side1, side2, inner, outer
+ tiles = {"default_stone.png"},
+ paramtype = "light",
+ paramtype2 = "facedir",
+ is_ground_content = true,
+ groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2,not_in_creative_inventory=1},
+ -- larger than one node but slightly smaller than a half node so that wallmounted torches pose no problem
+ node_box = {
+ type = "fixed",
+ fixed = {
+ {-0.90, -0.5, 0.4, -0.49, 1.5, 0.5},
+ { 0.49, -0.5, 0.4, 0.9, 1.5, 0.5},
+ },
+ },
+ selection_box = {
+ type = "fixed",
+ fixed = {
+ {-0.9, -0.5, 0.4, 0.9, 1.5, 0.5},
+ },
+ },
+ drop = "travelnet:elevator_door_steel_closed",
+ on_rightclick = function(pos, node, puncher)
+ minetest.add_node(pos, {name = "travelnet:elevator_door_steel_closed", param2 = node.param2})
+ end,
+})
+
+minetest.register_node("travelnet:elevator_door_steel_closed", {
+ description = "elevator door (closed)",
+ drawtype = "nodebox",
+ -- top, bottom, side1, side2, inner, outer
+ tiles = {"default_stone.png"},
+ paramtype = "light",
+ paramtype2 = "facedir",
+ is_ground_content = true,
+ groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2},
+ node_box = {
+ type = "fixed",
+ fixed = {
+ {-0.5, -0.5, 0.4, -0.01, 1.5, 0.5},
+ { 0.01, -0.5, 0.4, 0.5, 1.5, 0.5},
+ },
+ },
+ selection_box = {
+ type = "fixed",
+ fixed = {
+ {-0.5, -0.5, 0.4, 0.5, 1.5, 0.5},
+ },
+ },
+ on_rightclick = function(pos, node, puncher)
+ minetest.add_node(pos, {name = "travelnet:elevator_door_steel_open", param2 = node.param2})
+ end,
+})
+
+
+
+
+minetest.register_node("travelnet:elevator_door_glass_open", {
+ description = "elevator door (open)",
+ drawtype = "nodebox",
+ -- top, bottom, side1, side2, inner, outer
+ tiles = {"travelnet_elevator_door_glass.png"},
+ paramtype = "light",
+ paramtype2 = "facedir",
+ is_ground_content = true,
+ groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2,not_in_creative_inventory=1},
+ -- larger than one node but slightly smaller than a half node so that wallmounted torches pose no problem
+ node_box = {
+ type = "fixed",
+ fixed = {
+ {-0.99, -0.5, 0.4, -0.49, 1.5, 0.5},
+ { 0.49, -0.5, 0.4, 0.99, 1.5, 0.5},
+ },
+ },
+ selection_box = {
+ type = "fixed",
+ fixed = {
+ {-0.9, -0.5, 0.4, 0.9, 1.5, 0.5},
+ },
+ },
+ drop = "travelnet:elevator_door_glass_closed",
+ on_rightclick = function(pos, node, puncher)
+ minetest.add_node(pos, {name = "travelnet:elevator_door_glass_closed", param2 = node.param2})
+ end,
+})
+
+minetest.register_node("travelnet:elevator_door_glass_closed", {
+ description = "elevator door (closed)",
+ drawtype = "nodebox",
+ -- top, bottom, side1, side2, inner, outer
+ tiles = {"travelnet_elevator_door_glass.png"},
+ paramtype = "light",
+ paramtype2 = "facedir",
+ is_ground_content = true,
+ groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2},
+ node_box = {
+ type = "fixed",
+ fixed = {
+ {-0.5, -0.5, 0.4, -0.01, 1.5, 0.5},
+ { 0.01, -0.5, 0.4, 0.5, 1.5, 0.5},
+ },
+ },
+ selection_box = {
+ type = "fixed",
+ fixed = {
+ {-0.5, -0.5, 0.4, 0.5, 1.5, 0.5},
+ },
+ },
+ on_rightclick = function(pos, node, puncher)
+ minetest.add_node(pos, {name = "travelnet:elevator_door_glass_open", param2 = node.param2})
+ end,
+})
+
+minetest.register_craft({
+ output = "travelnet:elevator_door_glass_closed",
+ recipe = {
+ {"default:glass", "", "default:glass", },
+ {"default:glass", "", "default:glass", },
+ {"default:glass", "", "default:glass", }
+ }
+ })
+
+minetest.register_craft({
+ output = "travelnet:elevator_door_steel_closed",
+ recipe = {
+ {"default:steel_ingot", "", "default:steel_ingot", },
+ {"default:steel_ingot", "", "default:steel_ingot", },
+ {"default:steel_ingot", "", "default:steel_ingot", }
+ }
+ })
+-- local old_node = minetest.get_node( pos );
+-- minetest.add_node(pos, {name = "travelnet:elevator_door_glass_closed", param2 = old_node.param2})
+
+
+
diff --git a/travelnet/elevator.lua b/travelnet/elevator.lua
new file mode 100644
index 0000000..a407d33
--- /dev/null
+++ b/travelnet/elevator.lua
@@ -0,0 +1,112 @@
+-- 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
+
+minetest.register_node("travelnet:elevator", {
+ description = "Elevator",
+ drawtype = "mesh",
+ mesh = "travelnet_elevator.obj",
+ sunlight_propagates = true,
+ paramtype = 'light',
+ paramtype2 = "facedir",
+ wield_scale = {x=0.6, y=0.6, z=0.6},
+
+ selection_box = {
+ type = "fixed",
+ fixed = { -0.5, -0.5, -0.5, 0.5, 1.5, 0.5 }
+ },
+
+ collision_box = {
+ type = "fixed",
+ fixed = {
+
+ { 0.48, -0.5,-0.5, 0.5, 0.5, 0.5},
+ {-0.5 , -0.5, 0.48, 0.48, 0.5, 0.5},
+ {-0.5, -0.5,-0.5 ,-0.48, 0.5, 0.5},
+
+ --groundplate to stand on
+ { -0.5,-0.5,-0.5,0.5,-0.48, 0.5},
+ },
+ },
+
+ tiles = {
+ "travelnet_elevator_front.png",
+ "travelnet_elevator_inside_controls.png",
+ "travelnet_elevator_sides_outside.png",
+ "travelnet_elevator_inside_ceiling.png",
+ "travelnet_elevator_inside_floor.png",
+ "default_steel_block.png"
+ },
+ inventory_image = "travelnet_elevator_inv.png",
+ groups = {cracky=1,choppy=1,snappy=1},
+
+ light_source = 10,
+
+ after_place_node = function(pos, placer, itemstack)
+ local meta = minetest.get_meta(pos);
+ meta:set_string("infotext", "Elevator (unconfigured)");
+ meta:set_string("station_name", "");
+ meta:set_string("station_network","");
+ meta:set_string("owner", placer:get_player_name() );
+ -- request initinal data
+ meta:set_string("formspec",
+ "size[12,10]"..
+ "field[0.3,5.6;6,0.7;station_name;Name of this station:;]"..
+-- "field[0.3,6.6;6,0.7;station_network;Assign to Network:;]"..
+-- "field[0.3,7.6;6,0.7;owner_name;(optional) owned by:;]"..
+ "button_exit[6.3,6.2;1.7,0.7;station_set;Store]" );
+
+ local p = {x=pos.x, y=pos.y+1, z=pos.z}
+ local p2 = minetest.dir_to_facedir(placer:get_look_dir())
+ minetest.add_node(p, {name="travelnet:elevator_top", paramtype2="facedir", param2=p2})
+ end,
+
+ on_receive_fields = travelnet.on_receive_fields,
+ on_punch = function(pos, node, puncher)
+ travelnet.update_formspec(pos, puncher:get_player_name())
+ end,
+
+ can_dig = function( pos, player )
+ return travelnet.can_dig( pos, player, 'elevator' )
+ end,
+
+ after_dig_node = function(pos, oldnode, oldmetadata, digger)
+ travelnet.remove_box( pos, oldnode, oldmetadata, digger )
+ end,
+
+ -- taken from VanessaEs homedecor fridge
+ 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});
+ -- leftover elevator_top nodes can be removed by placing a new elevator underneath
+ if( node ~= nil and node.name ~= "air" and node.name ~= 'travelnet:elevator_top') then
+ minetest.chat_send_player( placer:get_player_name(), 'Not enough vertical space to place the travelnet box!' )
+ return;
+ end
+ return minetest.item_place(itemstack, placer, pointed_thing);
+ end,
+
+ on_destruct = function(pos)
+ local p = {x=pos.x, y=pos.y+1, z=pos.z}
+ minetest.remove_node(p)
+ end
+})
+
+minetest.register_alias("travelnet:elevator_top", "air")
+
+--if( minetest.get_modpath("technic") ~= nil ) then
+-- minetest.register_craft({
+-- output = "travelnet:elevator",
+-- recipe = {
+-- {"default:steel_ingot", "technic:motor", "default:steel_ingot", },
+-- {"default:steel_ingot", "technic:control_logic_unit", "default:steel_ingot", },
+-- {"default:steel_ingot", "moreores:copper_ingot", "default:steel_ingot", }
+-- }
+-- })
+--else
+ minetest.register_craft({
+ output = "travelnet:elevator",
+ recipe = travelnet.elevator_recipe,
+ })
+--end
+
diff --git a/travelnet/init.lua b/travelnet/init.lua
new file mode 100644
index 0000000..3eeb949
--- /dev/null
+++ b/travelnet/init.lua
@@ -0,0 +1,699 @@
+
+
+--[[
+ Teleporter networks that allow players to choose a destination out of a list
+ Copyright (C) 2013 Sokomine
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ Version: 2.2 (with optional abm for self-healing)
+
+ Please configure this mod in config.lua
+
+ Changelog:
+ 05.10.14 - Added an optional abm so that the travelnet network can heal itshelf in case of loss of the savefile.
+ If you want to use this, set
+ travelnet.enable_abm = true
+ in config.lua and edit the interval in the abm to suit your needs.
+ 19.11.13 - moved doors and travelnet definition into an extra file
+ - moved configuration to config.lua
+ 05.08.13 - fixed possible crash when the node in front of the travelnet is unknown
+ 26.06.13 - added inventory image for elevator (created by VanessaE)
+ 21.06.13 - bugfix: wielding an elevator while digging a door caused the elevator_top to be placed
+ - leftover floating elevator_top nodes can be removed by placing a new travelnet:elevator underneath them and removing that afterwards
+ - homedecor-doors are now opened and closed correctly as well
+ - removed nodes that are not intended for manual use from creative inventory
+ - improved naming of station levels for the elevator
+ 21.06.13 - elevator stations are sorted by height instead of date of creation as is the case with travelnet boxes
+ - elevator stations are named automaticly
+ 20.06.13 - doors can be opened and closed from inside the travelnet box/elevator
+ - the elevator can only move vertically; the network name is defined by its x and z coordinate
+ 13.06.13 - bugfix
+ - elevator added (written by kpoppel) and placed into extra file
+ - elevator doors added
+ - groups changed to avoid accidental dig/drop on dig of node beneath
+ - added new priv travelnet_remove for digging of boxes owned by other players
+ - only the owner of a box or players with the travelnet_remove priv can now dig it
+ - entering your own name as owner_name does no longer abort setup
+ 22.03.13 - added automatic detection if yaw can be set
+ - beam effect is disabled by default
+ 20.03.13 - added inventory image provided by VanessaE
+ - fixed bug that made it impossible to remove stations from the net
+ - if the station a player beamed to no longer exists, the station will be removed automaticly
+ - with the travelnet_attach priv, you can now attach your box to the nets of other players
+ - in newer versions of Minetest, the players yaw is set so that he/she looks out of the receiving box
+ - target list is now centered if there are less than 9 targets
+--]]
+
+
+minetest.register_privilege("travelnet_attach", { description = "allows to attach travelnet boxes to travelnets of other players", give_to_singleplayer = false});
+minetest.register_privilege("travelnet_remove", { description = "allows to dig travelnet boxes which belog to nets of other players", give_to_singleplayer = false});
+
+travelnet = {};
+
+travelnet.targets = {};
+
+
+-- read the configuration
+dofile(minetest.get_modpath("travelnet").."/config.lua"); -- the normal, default travelnet
+
+
+
+-- TODO: save and restore ought to be library functions and not implemented in each individual mod!
+-- called whenever a station is added or removed
+travelnet.save_data = function()
+
+ local data = minetest.serialize( travelnet.targets );
+ local path = minetest.get_worldpath().."/mod_travelnet.data";
+
+ local file = io.open( path, "w" );
+ if( file ) then
+ file:write( data );
+ file:close();
+ else
+ print("[Mod travelnet] Error: Savefile '"..tostring( path ).."' could not be written.");
+ end
+end
+
+
+travelnet.restore_data = function()
+
+ local path = minetest.get_worldpath().."/mod_travelnet.data";
+
+ local file = io.open( path, "r" );
+ if( file ) then
+ local data = file:read("*all");
+ travelnet.targets = minetest.deserialize( data );
+ file:close();
+ else
+ print("[Mod travelnet] Error: Savefile '"..tostring( path ).."' not found.");
+ end
+end
+
+
+
+
+travelnet.update_formspec = function( pos, puncher_name )
+
+ 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
+
+-- minetest.chat_send_player(puncher_name, "DEBUG DATA: owner: "..(owner_name or "?")..
+-- " station_name: "..(station_name or "?")..
+-- " station_network: "..(station_network or "?")..".");
+-- minetest.chat_send_player(puncher_name, "data: "..minetest.serialize( travelnet.targets ));
+
+
+ meta:set_string("infotext", "Travelnet-box (unconfigured)");
+ meta:set_string("station_name", "");
+ meta:set_string("station_network","");
+ meta:set_string("owner", "");
+ -- request initinal data
+ meta:set_string("formspec",
+ "size[12,10]"..
+ "field[0.3,7.6;9,0.9;station_name;Name of this station:;"..(station_name or "?").."]"..
+ "field[0.3,8.6;9,0.9;station_network;Assign to Network:;"..(station_network or "?").."]"..
+ "field[0.3,9.6;9,0.9;owner;Owned by:;"..(owner_name or "?").."]"..
+ "button_exit[6.3,8.2;1.7,0.7;station_set;Store]" );
+
+ minetest.chat_send_player(puncher_name, "Error: 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, "Station '"..station_name.."' has been reattached to the network '"..station_network.."'.");
+
+ end
+
+
+ -- add name of station + network + owner + update-button
+ local formspec = "size[12,10]"..
+ "label[3.3,0.0;Travelnet-Box:]".."label[6.3,0.0;Punch box to update target list.]"..
+ "label[0.3,0.4;Name of this station:]".."label[6.3,0.4;"..(station_name or "?").."]"..
+ "label[0.3,0.8;Assigned to Network:]" .."label[6.3,0.8;"..(station_network or "?").."]"..
+ "label[0.3,1.2;Owned by:]" .."label[6.3,1.2;"..(owner_name or "?").."]"..
+ "label[3.3,1.6;Click on target to travel there:]";
+-- "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 = '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
+
+ -- 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
+
+-- if( is_elevator ) then
+-- formspec = formspec ..' ('..tostring( travelnet.targets[ owner_name ][ station_network ][ k ].pos.y )..'m)';
+-- end
+-- formspec = formspec .. ']';
+
+ y = y+1;
+ --x = x+4;
+ end
+ end
+
+ meta:set_string( "formspec", formspec );
+
+ meta:set_string( "infotext", "Station '"..tostring( station_name ).."' on travelnet '"..tostring( station_network )..
+ "' (owned by "..tostring( owner_name )..") ready for usage. Right-click to travel, punch to update.");
+
+ minetest.chat_send_player(puncher_name, "The target list of this box on the travelnet has been updated.");
+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 = 'at '..tostring( pos.y )..'m';
+ end
+ end
+
+ if( station_name == "" or not(station_name )) then
+ minetest.chat_send_player(player_name, "Please provide a name for this station.");
+ return;
+ end
+
+ if( network_name == "" or not( network_name )) then
+ minetest.chat_send_player(player_name, "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( travelnet.targets[ owner_name ] )
+ or not( travelnet.targets[ owner_name ][ network_name ] )) then
+
+ minetest.chat_send_player(player_name, "There is no network named "..tostring( network_name ).." owned by "..tostring( owner_name )..". Aborting.");
+ return;
+
+ elseif( not( minetest.check_player_privs(player_name, {travelnet_attach=true}))
+ and not( travelnet.allow_attach( player_name, owner_name, network_name ))) then
+
+ minetest.chat_send_player(player_name, "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
+ minetest.chat_send_player(player_name, "Error: A station named '"..station_name.."' already exists on this network. Please choose a diffrent 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
+ minetest.chat_send_player(player_name, "Error: Network '"..network_name.."' already contains the maximum number (="
+ ..(travelnet.MAX_STATIONS_PER_NETWORK)..") of allowed stations per network. Please choose a diffrent/new network name.");
+ 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, "Station '"..station_name.."' has been added to the network '"
+ ..network_name.."', which now consists of "..( anz+1 ).." station(s).");
+
+ 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;Station:;".. meta:get_string("station_name").."]"..
+ "field[0.3,3.6;6,0.7;station_network;Network:;"..meta:get_string("station_network").."]" );
+
+ -- display a list of all stations that can be reached from here
+ travelnet.update_formspec( pos, player_name );
+
+ -- 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( pos );
+ 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 ( door_node.name == 'travelnet:elevator_door_glass_closed'
+ or door_node.name == 'travelnet:elevator_door_steel_closed'
+ -- handle doors that change their facedir
+ or ( door_node.param2 == this_node.param2
+ and door_node.name ~= 'travelnet:elevator_door_glass_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 ( door_node.name == 'travelnet:elevator_door_glass_open'
+ or door_node.name == 'travelnet:elevator_door_steel_open'
+ -- handle doors that change their facedir
+ or ( door_node.param2 ~= this_node.param2
+ and door_node.name ~= 'travelnet:elevator_door_glass_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)
+ local meta = minetest.get_meta(pos);
+
+ local name = player:get_player_name();
+
+ -- 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_name );
+ return;
+ end
+
+ if( fields.open_door ) then
+ travelnet.open_close_door( pos, player, 0 );
+ return;
+ end
+
+
+ if( not( fields.target )) then
+ minetest.chat_send_player(name, "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, "Error: 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, "Error: 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 --..' ('..tostring( travelnet.targets[ owner_name ][ station_network ][ k ].pos.y )..'m)'
+ == 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, "Station '"..( fields.target or "?").." does not exist (anymore?) on this network.");
+ travelnet.update_formspec( pos, name );
+ return;
+ end
+
+
+ if( not( travelnet.allow_travel( name, owner_name, station_network, station_name, fields.target ))) then
+ return;
+ end
+ minetest.chat_send_player(name, "Initiating transfer to station '"..( fields.target or "?").."'.'");
+
+
+
+ if( travelnet.travelnet_sound_enabled ) then
+ minetest.sound_play("128590_7037-lq.mp3", {pos = pos, gain = 1.0, max_hear_distance = 10,})
+ 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
+ local target_pos = travelnet.targets[ owner_name ][ station_network ][ fields.target ].pos;
+ player:moveto( target_pos, false);
+
+ if( travelnet.travelnet_sound_enabled ) then
+ minetest.sound_play("travelnet_travel.wav", {pos = target_pos, gain = 1.0, max_hear_distance = 10,})
+ end
+ if( travelnet.travelnet_effect_enabled ) then
+ minetest.add_entity( {x=target_pos.x,y=target_pos.y+0.5,z=target_pos.z}, "travelnet:effect"); -- it self-destructs after 20 turns
+ end
+
+
+ -- check if the box has at the other end has been removed.
+ local node2 = minetest.get_node( target_pos );
+ if( node2 ~= nil and node2.name ~= 'ignore' and node2.name ~= 'travelnet:travelnet' and node2.name ~= 'travelnet:elevator') 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 );
+
+ -- do this only on servers where the function exists
+ elseif( player.set_look_yaw ) 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_yaw( math.rad( yaw )); -- this is only supported in recent versions of MT
+ player:set_look_pitch( math.rad( 0 )); -- this is only supported in recent versions of MT
+ 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(), "Error: 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(), "Error: 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, "Station '"..station_name.."' has been REMOVED from the network '"..station_network.."'.");
+ if( digger ~= nil and owner_name ~= digger:get_player_name() ) then
+ minetest.chat_send_player( digger:get_player_name(), "Station '"..station_name.."' has been REMOVED from the network '"..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 )
+
+ if( not( player )) then
+ return false;
+ end
+ local name = player:get_player_name();
+
+ -- players with that priv can dig regardless of owner
+ if( minetest.check_player_privs(name, {travelnet_remove=true})
+ or travelnet.allow_dig( player_name, owner_name, network_name )) then
+ return true;
+ end
+
+ local meta = minetest.get_meta( pos );
+ local owner = meta:get_string('owner');
+
+ if( not( meta ) or not( owner) or owner=='') then
+ minetest.chat_send_player(name, "This "..description.." has not been configured yet. Please set it up first to claim it. Afterwards you can remove it because you are then the owner.");
+ return false;
+
+ elseif( owner ~= name ) then
+ minetest.chat_send_player(name, "This "..description.." belongs to "..tostring( meta:get_string('owner'))..". You can't remove it.");
+ return false;
+ end
+ return true;
+end
+
+
+
+
+
+if( travelnet.travelnet_effect_enabled ) then
+ minetest.register_entity( 'travelnet:effect', {
+
+ hp_max = 1,
+ physical = false,
+ weight = 5,
+ collisionbox = {-0.4,-0.5,-0.4, 0.4,1.5,0.4},
+ visual = "upright_sprite",
+ visual_size = {x=1, y=2},
+-- mesh = "model",
+ textures = { "travelnet_flash.png" }, -- number of required textures depends on visual
+-- colors = {}, -- number of required colors depends on visual
+ spritediv = {x=1, y=1},
+ initial_sprite_basepos = {x=0, y=0},
+ is_visible = true,
+ makes_footstep_sound = false,
+ automatic_rotate = true,
+
+ anz_rotations = 0,
+
+ on_step = function( self, dtime )
+ -- this is supposed to be more flickering than smooth animation
+ self.object:setyaw( self.object:getyaw()+1);
+ self.anz_rotations = self.anz_rotations + 1;
+ -- eventually self-destruct
+ if( self.anz_rotations > 15 ) then
+ self.object:remove();
+ end
+ end
+ })
+end
+
+
+if( travelnet.travelnet_enabled ) then
+ dofile(minetest.get_modpath("travelnet").."/travelnet.lua"); -- the travelnet node definition
+end
+if( travelnet.elevator_enabled ) then
+ dofile(minetest.get_modpath("travelnet").."/elevator.lua"); -- allows up/down transfers only
+end
+if( travelnet.doors_enabled ) then
+ dofile(minetest.get_modpath("travelnet").."/doors.lua"); -- doors that open and close automaticly when the travelnet or elevator is used
+end
+
+if( travelnet.abm_enabled ) then
+ dofile(minetest.get_modpath("travelnet").."/restore_network_via_abm.lua"); -- restore travelnet data when players pass by broken networks
+end
+
+-- upon server start, read the savefile
+travelnet.restore_data();
+
diff --git a/travelnet/models/travelnet.obj b/travelnet/models/travelnet.obj
new file mode 100644
index 0000000..50e5afd
--- /dev/null
+++ b/travelnet/models/travelnet.obj
@@ -0,0 +1,63 @@
+# Blender v2.73 (sub 0) OBJ File: 'travelnet.blend'
+# www.blender.org
+o Cylinder
+v -0.499016 -0.499034 0.499022
+v -0.499016 -0.499034 -0.498989
+v 0.499035 -0.499034 -0.498989
+v 0.499035 -0.499034 0.499022
+v -0.499016 1.498990 0.499022
+v -0.499016 1.498990 -0.498989
+v 0.499035 1.498990 -0.498989
+v 0.499035 1.498990 0.499022
+v 0.437500 -0.437500 0.437500
+v -0.499016 1.437500 -0.498989
+v 0.499035 1.437500 -0.498989
+v -0.437500 -0.437500 0.437500
+v 0.437500 1.437500 0.437500
+v -0.499016 -0.437500 -0.498989
+v 0.499035 -0.437500 -0.498989
+v -0.437500 1.437500 0.437500
+v -0.437500 -0.437500 -0.498989
+v 0.437500 -0.437500 -0.498989
+v -0.437500 1.437500 -0.498989
+v 0.437500 1.437500 -0.498989
+vt 0.000000 0.968750
+vt 1.000000 0.968750
+vt 1.000000 1.000000
+vt 0.000000 1.000000
+vt 0.062500 0.031250
+vt 0.062500 0.968750
+vt 0.000000 0.031250
+vt 0.937500 0.031250
+vt 1.000000 0.031250
+vt 0.937500 0.968750
+vt 1.000000 -0.000000
+vt 0.000000 -0.000000
+vt 0.062500 -0.000000
+vt 0.937500 -0.000000
+vt 0.937500 0.937500
+vt 0.062500 0.937500
+vt 0.062500 1.000000
+vt 0.062500 0.062500
+vt 0.937500 0.062500
+vt 0.937500 1.000000
+g Cylinder_Cylinder_front
+s off
+f 11/1 10/2 6/3 7/4
+f 18/5 20/6 11/1 15/7
+f 17/8 14/9 10/2 19/10
+f 13/6 9/5 12/8 16/10
+f 2/11 14/9 15/7 3/12
+g Cylinder_Cylinder_back
+f 8/4 5/3 1/11 4/12
+g Cylinder_Cylinder_sides
+f 18/7 9/8 13/10 20/1
+f 17/7 19/1 16/10 12/8
+f 8/3 4/11 3/12 7/4
+f 6/4 2/12 1/11 5/3
+g Cylinder_Cylinder_top
+f 5/12 8/11 7/3 6/4
+f 19/13 20/14 13/15 16/16
+g Cylinder_Cylinder_bottom
+f 17/17 12/18 9/19 18/20
+f 2/12 3/11 4/3 1/4
diff --git a/travelnet/models/travelnet_elevator.obj b/travelnet/models/travelnet_elevator.obj
new file mode 100644
index 0000000..cc006e2
--- /dev/null
+++ b/travelnet/models/travelnet_elevator.obj
@@ -0,0 +1,64 @@
+# Blender v2.73 (sub 0) OBJ File: 'travelnet_elevator.blend'
+# www.blender.org
+o Cylinder
+v -0.499016 -0.499034 0.499022
+v -0.499016 -0.499034 -0.498989
+v 0.499035 -0.499034 -0.498989
+v 0.499035 -0.499034 0.499022
+v -0.499016 1.498990 0.499022
+v -0.499016 1.498990 -0.498989
+v 0.499035 1.498990 -0.498989
+v 0.499035 1.498990 0.499022
+v 0.437500 -0.437500 0.437500
+v -0.499016 1.437500 -0.498989
+v 0.499035 1.437500 -0.498989
+v -0.437500 -0.437500 0.437500
+v 0.437500 1.437500 0.437500
+v -0.499016 -0.437500 -0.498989
+v 0.499035 -0.437500 -0.498989
+v -0.437500 1.437500 0.437500
+v -0.437500 -0.437500 -0.498989
+v 0.437500 -0.437500 -0.498989
+v -0.437500 1.437500 -0.498989
+v 0.437500 1.437500 -0.498989
+vt 0.000000 0.968750
+vt 1.000000 0.968750
+vt 1.000000 1.000000
+vt 0.000000 1.000000
+vt 0.062500 0.031250
+vt 0.062500 0.968750
+vt 0.000000 0.031250
+vt 0.937500 0.031250
+vt 1.000000 0.031250
+vt 0.937500 0.968750
+vt 1.000000 -0.000000
+vt 0.000000 -0.000000
+vt 0.062500 -0.000000
+vt 0.937500 -0.000000
+vt 0.937500 0.937500
+vt 0.062500 0.937500
+vt 0.062500 1.000000
+vt 0.062500 0.062500
+vt 0.937500 0.062500
+vt 0.937500 1.000000
+g Cylinder_Cylinder_front
+s off
+f 11/1 10/2 6/3 7/4
+f 18/5 20/6 11/1 15/7
+f 17/8 14/9 10/2 19/10
+f 13/6 9/5 12/8 16/10
+f 2/11 14/9 15/7 3/12
+f 17/7 19/1 16/10 12/8
+g Cylinder_Cylinder_controls
+f 18/7 9/8 13/10 20/1
+g Cylinder_Cylinder_outside
+f 8/3 4/11 3/12 7/4
+f 6/4 2/12 1/11 5/3
+f 8/4 5/3 1/11 4/12
+g Cylinder_Cylinder_ceiling
+f 19/13 20/14 13/15 16/16
+g Cylinder_Cylinder_floor
+f 17/17 12/18 9/19 18/20
+g Cylinder_Cylinder_top-bottom
+f 5/12 8/11 7/3 6/4
+f 2/12 3/11 4/3 1/4
diff --git a/travelnet/restore_network_via_abm.lua b/travelnet/restore_network_via_abm.lua
new file mode 100644
index 0000000..3bd1dda
--- /dev/null
+++ b/travelnet/restore_network_via_abm.lua
@@ -0,0 +1,24 @@
+
+minetest.register_abm({
+ nodenames = {"travelnet:travelnet"},
+ interval = 20,
+ chance = 1,
+ action = function(pos, node)
+ local meta = minetest.get_meta( pos );
+
+ local owner_name = meta:get_string( "owner" );
+ local station_name = meta:get_string( "station_name" );
+ local station_network = meta:get_string( "station_network" );
+
+ if( owner_name and station_name and station_network
+ and ( not( travelnet.targets )
+ or not( travelnet.targets[ owner_name ] )
+ or not( travelnet.targets[ owner_name ][ station_network ] )
+ or not( travelnet.targets[ owner_name ][ station_network ][ station_name ] ))) then
+
+ travelnet.add_target( station_name, station_network, pos, owner_name, meta, owner_name );
+ print( 'TRAVELNET: re-adding '..tostring( station_name )..' to '..tostring( station_network )..' owned by '..tostring( owner_name ));
+ end
+ end
+})
+
diff --git a/travelnet/textures/travelnet_elevator_door_glass.png b/travelnet/textures/travelnet_elevator_door_glass.png
new file mode 100644
index 0000000..ae775c4
--- /dev/null
+++ b/travelnet/textures/travelnet_elevator_door_glass.png
Binary files differ
diff --git a/travelnet/textures/travelnet_elevator_front.png b/travelnet/textures/travelnet_elevator_front.png
new file mode 100644
index 0000000..60ec49e
--- /dev/null
+++ b/travelnet/textures/travelnet_elevator_front.png
Binary files differ
diff --git a/travelnet/textures/travelnet_elevator_inside_ceiling.png b/travelnet/textures/travelnet_elevator_inside_ceiling.png
new file mode 100644
index 0000000..f35dd07
--- /dev/null
+++ b/travelnet/textures/travelnet_elevator_inside_ceiling.png
Binary files differ
diff --git a/travelnet/textures/travelnet_elevator_inside_controls.png b/travelnet/textures/travelnet_elevator_inside_controls.png
new file mode 100644
index 0000000..725c39b
--- /dev/null
+++ b/travelnet/textures/travelnet_elevator_inside_controls.png
Binary files differ
diff --git a/travelnet/textures/travelnet_elevator_inside_floor.png b/travelnet/textures/travelnet_elevator_inside_floor.png
new file mode 100644
index 0000000..7874bac
--- /dev/null
+++ b/travelnet/textures/travelnet_elevator_inside_floor.png
Binary files differ
diff --git a/travelnet/textures/travelnet_elevator_inv.png b/travelnet/textures/travelnet_elevator_inv.png
new file mode 100644
index 0000000..a390d75
--- /dev/null
+++ b/travelnet/textures/travelnet_elevator_inv.png
Binary files differ
diff --git a/travelnet/textures/travelnet_elevator_sides_outside.png b/travelnet/textures/travelnet_elevator_sides_outside.png
new file mode 100644
index 0000000..82c0a03
--- /dev/null
+++ b/travelnet/textures/travelnet_elevator_sides_outside.png
Binary files differ
diff --git a/travelnet/textures/travelnet_flash.png b/travelnet/textures/travelnet_flash.png
new file mode 100644
index 0000000..47a6365
--- /dev/null
+++ b/travelnet/textures/travelnet_flash.png
Binary files differ
diff --git a/travelnet/textures/travelnet_inv.png b/travelnet/textures/travelnet_inv.png
new file mode 100644
index 0000000..6f7df22
--- /dev/null
+++ b/travelnet/textures/travelnet_inv.png
Binary files differ
diff --git a/travelnet/textures/travelnet_travelnet_back.png b/travelnet/textures/travelnet_travelnet_back.png
new file mode 100644
index 0000000..f08c9eb
--- /dev/null
+++ b/travelnet/textures/travelnet_travelnet_back.png
Binary files differ
diff --git a/travelnet/textures/travelnet_travelnet_front.png b/travelnet/textures/travelnet_travelnet_front.png
new file mode 100644
index 0000000..2b0c3a2
--- /dev/null
+++ b/travelnet/textures/travelnet_travelnet_front.png
Binary files differ
diff --git a/travelnet/textures/travelnet_travelnet_side.png b/travelnet/textures/travelnet_travelnet_side.png
new file mode 100644
index 0000000..bd6092e
--- /dev/null
+++ b/travelnet/textures/travelnet_travelnet_side.png
Binary files differ
diff --git a/travelnet/travelnet.lua b/travelnet/travelnet.lua
new file mode 100644
index 0000000..5d6f284
--- /dev/null
+++ b/travelnet/travelnet.lua
@@ -0,0 +1,99 @@
+-- contains the node definition for a general travelnet that can be used by anyone
+-- further travelnets can only be installed by the owner or by people with the travelnet_attach priv
+-- digging of such a travelnet is limited to the owner and to people with the travelnet_remove priv (useful for admins to clean up)
+-- (this can be overrided in config.lua)
+-- Autor: Sokomine
+minetest.register_node("travelnet:travelnet", {
+
+ description = "Travelnet box",
+
+ drawtype = "mesh",
+ mesh = "travelnet.obj",
+ sunlight_propagates = true,
+ paramtype = 'light',
+ paramtype2 = "facedir",
+ wield_scale = {x=0.6, y=0.6, z=0.6},
+ selection_box = {
+ type = "fixed",
+ fixed = { -0.5, -0.5, -0.5, 0.5, 1.5, 0.5 }
+ },
+
+ collision_box = {
+ type = "fixed",
+ fixed = {
+
+ { 0.45, -0.5,-0.5, 0.5, 1.45, 0.5},
+ {-0.5 , -0.5, 0.45, 0.45, 1.45, 0.5},
+ {-0.5, -0.5,-0.5 ,-0.45, 1.45, 0.5},
+
+ --groundplate to stand on
+ { -0.5,-0.5,-0.5,0.5,-0.45, 0.5},
+ --roof
+ { -0.5, 1.45,-0.5,0.5, 1.5, 0.5},
+
+ -- control panel
+ -- { -0.2, 0.6, 0.3, 0.2, 1.1, 0.5},
+
+ },
+ },
+
+ tiles = {
+ "travelnet_travelnet_front.png", -- backward view
+ "travelnet_travelnet_back.png", -- front view
+ "travelnet_travelnet_side.png", -- sides :)
+ "default_steel_block.png", -- view from top
+ "default_clay.png", -- view from bottom
+ },
+ inventory_image = "travelnet_inv.png",
+
+ groups = {cracky=1,choppy=1,snappy=1},
+
+ light_source = 10,
+
+ after_place_node = function(pos, placer, itemstack)
+ local meta = minetest.get_meta(pos);
+ meta:set_string("infotext", "Travelnet-box (unconfigured)");
+ meta:set_string("station_name", "");
+ meta:set_string("station_network","");
+ meta:set_string("owner", placer:get_player_name() );
+ -- request initinal data
+ meta:set_string("formspec",
+ "size[12,10]"..
+ "field[0.3,5.6;6,0.7;station_name;Name of this station:;]"..
+ "field[0.3,6.6;6,0.7;station_network;Assign to Network:;]"..
+ "field[0.3,7.6;6,0.7;owner_name;(optional) owned by:;]"..
+ "button_exit[6.3,6.2;1.7,0.7;station_set;Store]" );
+ end,
+
+ on_receive_fields = travelnet.on_receive_fields,
+ on_punch = function(pos, node, puncher)
+ travelnet.update_formspec(pos, puncher:get_player_name())
+ end,
+
+ can_dig = function( pos, player )
+ return travelnet.can_dig( pos, player, 'travelnet box' )
+ end,
+
+ after_dig_node = function(pos, oldnode, oldmetadata, digger)
+ travelnet.remove_box( pos, oldnode, oldmetadata, digger )
+ end,
+
+ -- taken from VanessaEs homedecor fridge
+ on_place = function(itemstack, placer, pointed_thing)
+
+ local pos = pointed_thing.above;
+ if( minetest.get_node({x=pos.x, y=pos.y+1, z=pos.z}).name ~= "air" ) then
+
+ minetest.chat_send_player( placer:get_player_name(), 'Not enough vertical space to place the travelnet box!' )
+ return;
+ end
+ return minetest.item_place(itemstack, placer, pointed_thing);
+ end,
+
+})
+
+--[
+minetest.register_craft({
+ output = "travelnet:travelnet",
+ recipe = travelnet.travelnet_recipe,
+})