travelnet/init.lua

512 lines
19 KiB
Lua
Raw Normal View History

2013-03-20 18:15:14 +01:00
--[[
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/>.
Changelog:
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
--]]
2013-02-22 05:42:09 +01:00
2013-02-10 04:42:26 +01:00
local MAX_STATIONS_PER_NETWORK = 24;
2013-03-20 03:17:50 +01:00
minetest.register_privilege("travelnet_attach", { description = "allows to attach travelnet boxes to travelnets of other players", give_to_singleplayer = false});
2013-02-10 04:42:26 +01:00
travelnet = {};
travelnet.targets = {};
2013-02-16 05:32:29 +01:00
-- 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
2013-02-10 04:42:26 +01:00
end
2013-02-16 05:32:29 +01:00
2013-02-10 04:42:26 +01:00
travelnet.update_formspec = function( pos, puncher_name )
local meta = minetest.env:get_meta(pos);
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 not( station_network )) then
2013-03-20 03:17:50 +01:00
-- minetest.chat_send_player(puncher_name, "DEBUG DATA: owner: "..(owner_name or "?")..
-- " station_name: "..(station_name or "?")..
-- " station_network: "..(station_network or "?")..".");
2013-02-10 04:42:26 +01:00
-- minetest.chat_send_player(puncher_name, "data: "..minetest.serialize( travelnet.targets ));
2013-02-16 05:32:29 +01:00
meta:set_string("infotext", "Travelnet-box (unconfigured)");
2013-02-10 04:42:26 +01:00
meta:set_string("station_name", "");
meta:set_string("station_network","");
meta:set_string("owner", "");
-- request initinal data
meta:set_string("formspec",
"size[12,10]"..
2013-03-20 03:17:50 +01:00
"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]" );
2013-02-10 04:42:26 +01:00
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 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]"..
2013-03-20 03:17:50 +01:00
"label[3.3,0.0;Travelnet-Box:]".."label[6.3,0.0;Punch box to update target list.]"..
2013-02-10 04:42:26 +01:00
"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 ));
-- 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);
2013-03-20 03:17:50 +01:00
-- if there are only 8 stations (plus this one), center them in the formspec
if( #stations < 10 ) then
x = 4;
end
2013-02-10 04:42:26 +01:00
for index,k in ipairs( stations ) do
if( k ~= station_name ) then
i = i+1;
-- new column
if( y==8 ) then
x = x+4;
y = 0;
end
formspec = formspec .."button_exit["..(x)..","..(y+2.5)..";4,0.5;target;"..k.."]"
y = y+1;
--x = x+4;
end
end
meta:set_string( "formspec", formspec );
2013-02-16 05:32:29 +01:00
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.");
2013-02-10 04:42:26 +01:00
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
2013-03-20 03:17:50 +01:00
travelnet.add_target = function( station_name, network_name, pos, player_name, meta, owner_name )
2013-02-10 04:42:26 +01:00
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
2013-03-20 03:17:50 +01:00
if( owner_name == nil or owner_name == '' ) then
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}))) 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
2013-02-10 04:42:26 +01:00
-- first one by this player?
2013-03-20 03:17:50 +01:00
if( not( travelnet.targets[ owner_name ] )) then
travelnet.targets[ owner_name ] = {};
2013-02-10 04:42:26 +01:00
end
-- first station on this network?
2013-03-20 03:17:50 +01:00
if( not( travelnet.targets[ owner_name ][ network_name ] )) then
travelnet.targets[ owner_name ][ network_name ] = {};
2013-02-10 04:42:26 +01:00
end
-- lua doesn't allow efficient counting here
local anz = 0;
2013-03-20 03:17:50 +01:00
for k,v in pairs( travelnet.targets[ owner_name ][ network_name ] ) do
2013-02-10 04:42:26 +01:00
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 > MAX_STATIONS_PER_NETWORK ) then
minetest.chat_send_player(player_name, "Error: Network '"..network_name.."' already contains the maximum number (="
..(MAX_STATIONS_PER_NETWORK)..") of allowed stations per network. Please choose a diffrent/new network name.");
return;
end
-- add this station
2013-03-20 03:17:50 +01:00
travelnet.targets[ owner_name ][ network_name ][ station_name ] = {pos=pos, timestamp=os.time() };
2013-02-10 04:42:26 +01:00
-- 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 );
2013-03-20 03:17:50 +01:00
meta:set_string( "owner", owner_name );
meta:set_int( "timestamp", travelnet.targets[ owner_name ][ network_name ][ station_name ].timestamp);
2013-02-10 04:42:26 +01:00
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 );
2013-02-16 05:32:29 +01:00
-- save the updated network data in a savefile over server restart
travelnet.save_data();
2013-02-10 04:42:26 +01:00
end
end
travelnet.on_receive_fields = function(pos, formname, fields, player)
local meta = minetest.env:get_meta(pos);
local name = player:get_player_name();
-- if the box has not been configured yet
if( meta:get_string("station_network")=="" ) then
2013-03-20 03:17:50 +01:00
travelnet.add_target( fields.station_name, fields.station_network, pos, name, meta, fields.owner_name );
2013-02-10 04:42:26 +01:00
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
2013-03-20 03:17:50 +01:00
local owner_name = meta:get_string( "owner" );
2013-02-10 04:42:26 +01:00
local station_name = meta:get_string( "station_name" );
local station_network = meta:get_string( "station_network" );
2013-03-20 03:17:50 +01:00
if( not( owner_name )
2013-02-10 04:42:26 +01:00
or not( station_name )
or not( station_network )
2013-03-20 03:17:50 +01:00
or not( travelnet.targets[ owner_name ] )
or not( travelnet.targets[ owner_name ][ station_network ] )) then
2013-02-10 04:42:26 +01:00
minetest.chat_send_player(puncher_name, "Error: There is something wrong with the configuration of this station. "..
2013-03-20 03:17:50 +01:00
" DEBUG DATA: owner: "..( owner_name or "?")..
2013-02-10 04:42:26 +01:00
" station_name: "..(station_name or "?")..
" station_network: "..(station_network or "?")..".");
end
-- if the target station is gone
2013-03-20 03:17:50 +01:00
if( not( travelnet.targets[ owner_name ][ station_network ][ fields.target ] )) then
2013-02-10 04:42:26 +01:00
minetest.chat_send_player(name, "Station '"..( fields.target or "?").." does not exist (anymore?) on this network.");
travelnet.update_formspec( pos, name );
return;
end
minetest.chat_send_player(name, "Initiating transfer to station '"..( fields.target or "?").."'.'");
-- TODO
--minetest.sound_play("teleporter_teleport", {pos = pos, gain = 1.0, max_hear_distance = 10,})
-- transport the player to the target location
2013-03-20 03:17:50 +01:00
local target_pos = travelnet.targets[ owner_name ][ station_network ][ fields.target ].pos;
player:moveto( target_pos, false);
--minetest.sound_play("teleporter_teleport", {pos = travelnet.targets[ owner_name ][ station_network ][ fields.target ].pos, gain = 1.0, max_hear_distance = 10,})
-- check if the box has at the other end has been removed
local node2 = minetest.env:get_node( target_pos );
if( node2 ~= nil and node2.name ~= 'ignore' and node2.name ~= 'travelnet:travelnet' ) 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 );
else
-- rotate the player so that he/she can walk straight out of the box
2013-03-20 18:31:52 +01:00
local yaw = 0;
local param2 = node2.param2;
2013-03-20 03:17:50 +01:00
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
2013-03-20 18:25:10 +01:00
player:set_look_yaw( yaw ); -- this is only supported in recent versions of MT
2013-03-20 03:17:50 +01:00
end
2013-02-10 04:42:26 +01:00
end
2013-02-16 05:32:29 +01:00
travelnet.remove_box = function( pos, oldnode, oldmetadata, digger )
if( not( oldmetadata ) or oldmetadata=="nil" or not(oldmetadata.fields)) then
2013-03-20 03:17:50 +01:00
minetest.chat_send_player( digger:get_player_name(), "Error: Could not find information about the station that is to be removed.");
2013-02-16 05:32:29 +01:00
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 )
2013-03-20 03:17:50 +01:00
or not( travelnet.targets[ owner_name ] )
or not( travelnet.targets[ owner_name ][ station_network ] )) then
2013-02-16 05:32:29 +01:00
2013-03-20 03:17:50 +01:00
minetest.chat_send_player( digger:get_player_name(), "Error: Could not find the station that is to be removed.");
2013-02-16 05:32:29 +01:00
return;
end
2013-03-20 03:17:50 +01:00
travelnet.targets[ owner_name ][ station_network ][ station_name ] = nil;
2013-02-16 05:32:29 +01:00
2013-03-20 03:17:50 +01:00
-- 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
2013-02-16 05:32:29 +01:00
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
2013-02-10 04:42:26 +01:00
minetest.register_node("travelnet:travelnet", {
2013-02-16 05:32:29 +01:00
description = "Travelnet box",
2013-02-10 04:42:26 +01:00
drawtype = "nodebox",
sunlight_propagates = true,
paramtype = 'light',
paramtype2 = "facedir",
selection_box = {
type = "fixed",
fixed = { -0.5, -0.5, -0.5, 0.5, 1.5, 0.5 }
},
node_box = {
type = "fixed",
fixed = {
2013-03-15 04:48:21 +01:00
{ 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},
2013-02-10 04:42:26 +01:00
--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
2013-02-22 05:42:09 +01:00
-- { -0.2, 0.6, 0.3, 0.2, 1.1, 0.5},
2013-02-10 04:42:26 +01:00
},
},
tiles = {
"default_clay.png", -- view from top
"default_clay.png", -- view from bottom
2013-02-23 01:38:48 +01:00
"travelnet_travelnet_side.png", -- side
"travelnet_travelnet_side.png", -- side
2013-02-10 04:42:26 +01:00
2013-02-23 01:38:48 +01:00
"travelnet_travelnet_back.png", -- front view
"travelnet_travelnet_front.png", -- backward view
2013-02-10 04:42:26 +01:00
},
2013-03-20 18:11:54 +01:00
inventory_image = "travelnet_inv.png",
2013-02-10 04:42:26 +01:00
groups = {choppy=2,dig_immediate=2,attached_node=1},
2013-02-23 01:38:48 +01:00
light_source = 10,
2013-02-10 04:42:26 +01:00
after_place_node = function(pos, placer, itemstack)
local meta = minetest.env:get_meta(pos);
2013-02-16 05:32:29 +01:00
meta:set_string("infotext", "Travelnet-box (unconfigured)");
2013-02-10 04:42:26 +01:00
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]"..
2013-03-20 03:17:50 +01:00
"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]" );
2013-02-10 04:42:26 +01:00
end,
on_receive_fields = travelnet.on_receive_fields,
on_punch = function(pos, node, puncher)
travelnet.update_formspec(pos, puncher:get_player_name())
end,
2013-02-16 05:32:29 +01:00
after_dig_node = function(pos, oldnode, oldmetadata, digger)
travelnet.remove_box( pos, oldnode, oldmetadata, digger )
end,
2013-02-22 05:42:09 +01:00
-- taken from VanessaEs homedecor fridge
on_place = function(itemstack, placer, pointed_thing)
local pos = pointed_thing.above;
if( minetest.env: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,
2013-02-10 04:42:26 +01:00
})
2013-02-22 05:42:09 +01:00
minetest.register_craft({
output = "travelnet:travelnet",
recipe = {
{"default:glass", "default:steel_ingot", "default:glass", },
2013-02-23 01:38:48 +01:00
{"default:glass", "default:mese", "default:glass", },
2013-02-22 05:42:09 +01:00
{"default:glass", "default:steel_ingot", "default:glass", }
}
})
2013-02-10 04:42:26 +01:00
2013-02-16 05:32:29 +01:00
-- upon server start, read the savefile
travelnet.restore_data();
2013-02-22 05:42:09 +01:00