added support for shared locked chest; uses set_node instead of swap_node for cleaner operation; preparation for more versatile support of other chest types

This commit is contained in:
Sokomine 2018-07-27 19:08:41 +02:00
parent 4125be6ba4
commit 89beb85a6d
1 changed files with 119 additions and 90 deletions

209
init.lua
View File

@ -1,7 +1,23 @@
-- 27.07.18 Added support for shared locked chests and moved to set_node
-- with inventory copying for cleaner operation.
-- 05.10.14 Fixed bug in protection/access -- 05.10.14 Fixed bug in protection/access
chesttools = {} chesttools = {}
-- data structure: new_node_name = { item_that_acts_as_price,
-- amount_of_price_item,
-- name_for_field_in_menu,
-- index_for_display_in_menu,
-- name of price item for showing the player,
-- new formspec string}
-- prices always refer to upgrading a default:chest to the desired new model
chesttools.update_price = {
{'default:chest', 'default:steel_ingot', 0, 'normal', 1, 'nothing'},
{'default:chest_locked', 'default:steel_ingot', 1, 'locked', 2, 'steel ingot'},
{'chesttools:shared_chest', 'default:steel_ingot', 2, 'shared', 3, 'steel ingot(s)'},
{'locks:shared_locked_chest', 'default:steel_ingot', 3, 'locks', 4, 'steel ingot(s)'},
};
chesttools.chest_add = {}; chesttools.chest_add = {};
chesttools.chest_add.tiles = { chesttools.chest_add.tiles = {
"chesttools_blue_chest_top.png", "chesttools_blue_chest_top.png", "chesttools_blue_chest_side.png", "chesttools_blue_chest_top.png", "chesttools_blue_chest_top.png", "chesttools_blue_chest_side.png",
@ -9,6 +25,7 @@ chesttools.chest_add.tiles = {
chesttools.chest_add.groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2}; chesttools.chest_add.groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2};
chesttools.chest_add.tube = {}; chesttools.chest_add.tube = {};
-- additional/changed definitions for pipeworks; -- additional/changed definitions for pipeworks;
-- taken from pipeworks/compat.lua -- taken from pipeworks/compat.lua
if( minetest.get_modpath( 'pipeworks' )) then if( minetest.get_modpath( 'pipeworks' )) then
@ -46,7 +63,8 @@ chesttools.formspec = "size[9,10]"..
"button[7.0,4.5;0.5,0.5;drop_all;DA]".. "button[7.0,4.5;0.5,0.5;drop_all;DA]"..
"button[7.5,4.5;0.5,0.5;take_all;TA]".. "button[7.5,4.5;0.5,0.5;take_all;TA]"..
"button[8.0,4.5;0.5,0.5;swap_all;SA]".. "button[8.0,4.5;0.5,0.5;swap_all;SA]"..
"button[8.5,4.5;0.5,0.5;filter_all;FA]"; "button[8.5,4.5;0.5,0.5;filter_all;FA]"..
"list[current_player;main;0.5,5.5;8,4;]";
if( minetest.get_modpath( 'unified_inventory')) then if( minetest.get_modpath( 'unified_inventory')) then
chesttools.formspec = chesttools.formspec.. chesttools.formspec = chesttools.formspec..
@ -90,8 +108,7 @@ chesttools.on_receive_fields = function(pos, formname, fields, player)
meta:set_string("infotext", "\""..chestname.."\" Chest (owned by "..meta:get_string("owner")..")") meta:set_string("infotext", "\""..chestname.."\" Chest (owned by "..meta:get_string("owner")..")")
-- update the normal formspec -- update the normal formspec
meta:set_string("formspec", chesttools.formspec.. meta:set_string("formspec", chesttools.formspec..
"field[1.8,10.0;6,0.5;chestname;;"..chestname.."]".. "field[1.8,10.0;6,0.5;chestname;;"..chestname.."]");
"list[current_player;main;0.5,5.5;8,4;]");
end end
local formspec = "size[9,10]".. local formspec = "size[9,10]"..
@ -114,12 +131,14 @@ chesttools.on_receive_fields = function(pos, formname, fields, player)
if( fields.drop_all or fields.take_all or fields.swap_all or fields.filter_all ) then if( fields.drop_all or fields.take_all or fields.swap_all or fields.filter_all ) then
-- check if the player has sufficient access to the chest -- check if the player has sufficient access to the chest
local node = minetest.get_node( pos ); local node = minetest.get_node( pos );
local pname = player:get_player_name();
-- deny access for unsupported chests -- deny access for unsupported chests
if( not( node ) if( not( node )
or (node.name == 'chesttools:shared_chest' and not( chesttools.may_use( pos, player ))) or (node.name == 'chesttools:shared_chest' and not( chesttools.may_use( pos, player )))
or (node.name == 'default:chest_locked'and player:get_player_name() ~= meta:get_string('owner' ))) then or (node.name == 'locks:shared_locked_chest'and pname ~= meta:get_string('owner' ))
or (node.name == 'default:chest_locked'and pname ~= meta:get_string('owner' ))) then
if( node.name ~= 'default:chest' ) then if( node.name ~= 'default:chest' ) then
minetest.chat_send_player( player:get_player_name(), 'Sorry, you do not have access to the content of this chest.'); minetest.chat_send_player( pname, 'Sorry, you do not have access to the content of this chest.');
return; return;
end end
end end
@ -259,94 +278,103 @@ chesttools.update_chest = function(pos, formname, fields, player)
end end
local node = minetest.get_node( pos ); local node = minetest.get_node( pos );
local price = 1; local old_nr = -1;
if( node.name=='default:chest' ) then local new_nr = -1;
if( fields.normal) then for nr, update_data in ipairs( chesttools.update_price ) do
return; local link = tostring(update_data[4]);
local chest_node_name = update_data[1];
if( chest_node_name == node.name ) then
old_nr = nr;
elseif( fields[ link ] and fields[ link ] ~= "") then
new_nr = nr;
end end
if( fields.locked ) then end
price = 1; -- no change necessary
elseif( fields.shared ) then if( old_nr == -1 or new_nr == -1 or old_nr == new_nr ) then
price = 2;
end
elseif( node.name=='default:chest_locked' ) then
if( fields.locked) then
return;
end
if( fields.normal ) then
price = -1;
elseif( fields.shared ) then
price = 1;
end
elseif( node.name=='chesttools:shared_chest') then
if( fields.shared) then
return;
end
if( fields.normal ) then
price = -2;
elseif( fields.locked ) then
price = -1;
end
else
return; return;
end end
local new_node_name= chesttools.update_price[ new_nr ][1];
local player_inv = player:get_inventory(); local price_item = chesttools.update_price[ new_nr ][2];
if( price>0 and not( player_inv:contains_item( 'main', 'default:steel_ingot '..tostring( price )))) then local price_amount = chesttools.update_price[ new_nr ][3];
minetest.chat_send_player( pname, 'Sorry. You do not have '..tostring( price )..' steel ingots for the update.'); local price_name = chesttools.update_price[ new_nr ][6];
return; -- do they both use the same price?
if( chesttools.update_price[ old_nr ][2] == price_item ) then
-- the price for the old chest type gets substracted
price_amount = price_amount - chesttools.update_price[ old_nr ][3];
end end
-- only work on chests owned by the player (or unlocked ones) -- only work on chests owned by the player (or unlocked ones)
local meta = minetest.get_meta( pos ); local meta = minetest.get_meta( pos );
if( node.name ~= 'default:chest' and meta:get_string( 'owner' ) ~= pname ) then local owner = meta:get_string( 'owner' );
if( node.name ~= 'default:chest' and owner and owner ~= pname and owner ~= "") then
minetest.chat_send_player( pname, 'You can only upgrade your own chests.'); minetest.chat_send_player( pname, 'You can only upgrade your own chests.');
return; return;
end end
-- check if steel ingot is present -- can the player build here (and thus change this chest)?
if( minetest.is_protected(pos, pname )) then if( minetest.is_protected(pos, pname )) then
minetest.chat_send_player( pname, 'This chest is protected from digging.'); minetest.chat_send_player( pname, 'This chest is protected from digging.');
return; return;
end end
if( price > 0 ) then local player_inv = player:get_inventory();
player_inv:remove_item( 'main', 'default:steel_ingot '..tostring( price )); if( price_amount>0 and not( player_inv:contains_item( 'main', price_item..' '..price_amount))) then
elseif( price < 0 ) then minetest.chat_send_player( pname, 'Sorry. You do not have '..tostring( price_amount )..
price = price * -1; ' '..price_name..' for the update.');
player_inv:add_item( 'main', 'default:steel_ingot '..tostring( price )); return;
end
if( price_amount > 0 ) then
player_inv:remove_item( 'main', price_item..' '..tostring(price_amount));
elseif( price_amount < 0 ) then
price_amount = price_amount * -1;
player_inv:add_item( 'main', price_item..' '..tostring(price_amount));
end
-- if the old chest type had a diffrent price: return that price
if( chesttools.update_price[ old_nr ][2] ~= price_item ) then
local old_price_item = chesttools.update_price[ old_nr ][2];
local old_price_amount = chesttools.update_price[ old_nr ][3];
player_inv:add_item( 'main', old_price_item..' '..tostring(old_price_amount));
end end
-- set the owner field -- set the owner field
meta:set_string( 'owner', pname ); meta:set_string( 'owner', pname );
target = node.name;
if( fields.locked ) then if( fields.locked ) then
target = 'default:chest_locked';
meta:set_string("infotext", "Locked Chest (owned by "..meta:get_string("owner")..")") meta:set_string("infotext", "Locked Chest (owned by "..meta:get_string("owner")..")")
elseif( fields.shared ) then elseif( fields.shared ) then
target = 'chesttools:shared_chest';
meta:set_string("infotext", "Shared Chest (owned by "..meta:get_string("owner")..")") meta:set_string("infotext", "Shared Chest (owned by "..meta:get_string("owner")..")")
else else
target = 'default:chest';
meta:set_string("infotext", "Chest") meta:set_string("infotext", "Chest")
end end
if( not( fields.shared )) then -- copy the old inventory
meta:set_string("formspec", "size[9,10]".. local inv = meta:get_inventory();
"list[current_name;main;0.5,0.3;8,4;]".. local main_inv = {};
"list[current_player;main;0.5,5.5;8,4;]"); local inv_size = inv:get_size("main");
else for i=1, inv_size do
meta:set_string("formspec", chesttools.formspec.. main_inv[ i ] = inv:get_stack( "main", i);
"field[1.8,10.0;6,0.5;chestname;;"..tostring( meta:get_string("chestname") or "unconfigured").."]".. print("Found: "..tostring( main_inv[ i ]:get_name()));
"list[current_player;main;0.5,5.5;8,4;]");
end end
minetest.swap_node( pos, { name = target, param2 = node.param2 });
minetest.chat_send_player( pname, 'Chest changed to '..tostring( minetest.registered_nodes[ target].description ).. -- actually change and initialize the new chest
' for '..tostring( price )..' steel ingots.'); minetest.set_node( pos, { name = new_node_name, param2 = node.param2 });
-- make sure the player owns the new chest
meta:set_string("owner", pname);
-- put the inventory back
local new_inv = meta:get_inventory();
local new_inv_size = inv:get_size("main");
for i=1, math.min( inv_size, new_inv_size ) do
new_inv:set_stack( "main", i, main_inv[ i ]);
end
if( new_inv_size < inv_size ) then
-- TODO: problem here...where to put all that surplus inventory?
end
minetest.chat_send_player( pname, 'Chest changed to '..tostring( minetest.registered_nodes[ new_node_name].description )..
' for '..tostring( price_amount )..' '..price_name..'.');
end end
@ -450,6 +478,7 @@ minetest.register_node( 'chesttools:shared_chest', {
chesttools.on_receive_fields( pos, formname, fields, sender); chesttools.on_receive_fields( pos, formname, fields, sender);
end, end,
-- show chest upgrade formspec
on_use = function(itemstack, user, pointed_thing) on_use = function(itemstack, user, pointed_thing)
if( user == nil or pointed_thing == nil or pointed_thing.type ~= 'node') then if( user == nil or pointed_thing == nil or pointed_thing.type ~= 'node') then
return nil; return nil;
@ -463,35 +492,35 @@ minetest.register_node( 'chesttools:shared_chest', {
return nil; return nil;
end end
if( node.name=='default:chest' local formspec = "label[2,0.4;Change chest type:]"..
or node.name=='default:chest_locked' "field[20,20;0.1,0.1;pos2str;Pos;"..minetest.pos_to_string( pos ).."]"..
or node.name=='chesttools:shared_chest') then "button_exit[2,3.5;1.5,0.5;abort;Abort]";
local formspec = "size[8,4]".. local can_be_upgraded = false;
"label[2,0.4;Change chest type:]".. local offset = 1;
"field[20,20;0.1,0.1;pos2str;Pos;"..minetest.pos_to_string( pos ).."]".. for nr, update_data in ipairs( chesttools.update_price ) do
"button_exit[2,3.5;1.5,0.5;abort;Abort]"; local link = tostring(update_data[4]);
if( node.name ~= 'default:chest' ) then local chest_node_name = update_data[1];
formspec = formspec..'item_image_button[1,1;1.5,1.5;default:chest;normal;]'.. -- only offer possible updates
'button_exit[1,2.5;1.5,0.5;normal;normal]'; if( minetest.registered_nodes[ chest_node_name ]) then
else if( node.name ~= chest_node_name ) then
formspec = formspec..'item_image[1,1;1.5,1.5;default:chest]'.. formspec = formspec..'item_image_button['..tostring(offset)..',1;1.5,1.5;'..
'label[1,2.5;normal]'; chest_node_name..';'..link..';]'..
end 'button_exit['..tostring(offset)..',2.5;1.5,0.5;'..
if( node.name ~= 'default:chest_locked' ) then link..';'..link..']';
formspec = formspec..'item_image_button[3,1;1.5,1.5;default:chest_locked;locked;]'.. else
'button_exit[3,2.5;1.5,0.5;locked;locked]'; can_be_upgraded = true;
else formspec = formspec..'item_image['..tostring(offset)..',1;1.5,1.5;'..
formspec = formspec..'item_image[3,1;1.5,1.5;default:chest_locked]'.. chest_node_name..']'..
'label[3,2.5;locked]'; 'label['..tostring(offset)..',2.5;'..link..']';
end end
if( node.name ~= 'chesttools:shared_chest' ) then offset = offset + 2;
formspec = formspec..'item_image_button[5,1;1.5,1.5;chesttools:shared_chest;shared;]'..
'button_exit[5,2.5;1.5,0.5;shared;shared]';
else
formspec = formspec..'item_image[5,1;1.5,1.5;chesttools:shared_chest]'..
'label[5,2.5;shared]';
end end
end
-- make the formspec wide enough to show all chests centered
formspec = 'size['..tostring(offset)..',4]'..formspec;
-- only show the formspec if it really is a chest that can be updated
if( can_be_upgraded ) then
minetest.show_formspec( name, "chesttools:update", formspec ); minetest.show_formspec( name, "chesttools:update", formspec );
end end
return nil; return nil;