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
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.tiles = {
"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.tube = {};
-- additional/changed definitions for pipeworks;
-- taken from pipeworks/compat.lua
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.5,4.5;0.5,0.5;take_all;TA]"..
"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
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")..")")
-- update the normal formspec
meta:set_string("formspec", chesttools.formspec..
"field[1.8,10.0;6,0.5;chestname;;"..chestname.."]"..
"list[current_player;main;0.5,5.5;8,4;]");
"field[1.8,10.0;6,0.5;chestname;;"..chestname.."]");
end
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
-- check if the player has sufficient access to the chest
local node = minetest.get_node( pos );
local pname = player:get_player_name();
-- deny access for unsupported chests
if( not( node )
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
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;
end
end
@ -259,94 +278,103 @@ chesttools.update_chest = function(pos, formname, fields, player)
end
local node = minetest.get_node( pos );
local price = 1;
if( node.name=='default:chest' ) then
if( fields.normal) then
return;
local old_nr = -1;
local new_nr = -1;
for nr, update_data in ipairs( chesttools.update_price ) do
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
if( fields.locked ) then
price = 1;
elseif( fields.shared ) 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
end
-- no change necessary
if( old_nr == -1 or new_nr == -1 or old_nr == new_nr ) then
return;
end
local player_inv = player:get_inventory();
if( price>0 and not( player_inv:contains_item( 'main', 'default:steel_ingot '..tostring( price )))) then
minetest.chat_send_player( pname, 'Sorry. You do not have '..tostring( price )..' steel ingots for the update.');
return;
local new_node_name= chesttools.update_price[ new_nr ][1];
local price_item = chesttools.update_price[ new_nr ][2];
local price_amount = chesttools.update_price[ new_nr ][3];
local price_name = chesttools.update_price[ new_nr ][6];
-- 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
-- only work on chests owned by the player (or unlocked ones)
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.');
return;
end
-- check if steel ingot is present
-- can the player build here (and thus change this chest)?
if( minetest.is_protected(pos, pname )) then
minetest.chat_send_player( pname, 'This chest is protected from digging.');
return;
end
if( price > 0 ) then
player_inv:remove_item( 'main', 'default:steel_ingot '..tostring( price ));
elseif( price < 0 ) then
price = price * -1;
player_inv:add_item( 'main', 'default:steel_ingot '..tostring( price ));
local player_inv = player:get_inventory();
if( price_amount>0 and not( player_inv:contains_item( 'main', price_item..' '..price_amount))) then
minetest.chat_send_player( pname, 'Sorry. You do not have '..tostring( price_amount )..
' '..price_name..' for the update.');
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
-- set the owner field
meta:set_string( 'owner', pname );
target = node.name;
if( fields.locked ) then
target = 'default:chest_locked';
meta:set_string("infotext", "Locked Chest (owned by "..meta:get_string("owner")..")")
elseif( fields.shared ) then
target = 'chesttools:shared_chest';
meta:set_string("infotext", "Shared Chest (owned by "..meta:get_string("owner")..")")
else
target = 'default:chest';
meta:set_string("infotext", "Chest")
end
if( not( fields.shared )) then
meta:set_string("formspec", "size[9,10]"..
"list[current_name;main;0.5,0.3;8,4;]"..
"list[current_player;main;0.5,5.5;8,4;]");
else
meta:set_string("formspec", chesttools.formspec..
"field[1.8,10.0;6,0.5;chestname;;"..tostring( meta:get_string("chestname") or "unconfigured").."]"..
"list[current_player;main;0.5,5.5;8,4;]");
-- copy the old inventory
local inv = meta:get_inventory();
local main_inv = {};
local inv_size = inv:get_size("main");
for i=1, inv_size do
main_inv[ i ] = inv:get_stack( "main", i);
print("Found: "..tostring( main_inv[ i ]:get_name()));
end
minetest.swap_node( pos, { name = target, param2 = node.param2 });
minetest.chat_send_player( pname, 'Chest changed to '..tostring( minetest.registered_nodes[ target].description )..
' for '..tostring( price )..' steel ingots.');
-- actually change and initialize the new chest
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
@ -450,6 +478,7 @@ minetest.register_node( 'chesttools:shared_chest', {
chesttools.on_receive_fields( pos, formname, fields, sender);
end,
-- show chest upgrade formspec
on_use = function(itemstack, user, pointed_thing)
if( user == nil or pointed_thing == nil or pointed_thing.type ~= 'node') then
return nil;
@ -463,35 +492,35 @@ minetest.register_node( 'chesttools:shared_chest', {
return nil;
end
if( node.name=='default:chest'
or node.name=='default:chest_locked'
or node.name=='chesttools:shared_chest') then
local formspec = "label[2,0.4;Change chest type:]"..
"field[20,20;0.1,0.1;pos2str;Pos;"..minetest.pos_to_string( pos ).."]"..
"button_exit[2,3.5;1.5,0.5;abort;Abort]";
local formspec = "size[8,4]"..
"label[2,0.4;Change chest type:]"..
"field[20,20;0.1,0.1;pos2str;Pos;"..minetest.pos_to_string( pos ).."]"..
"button_exit[2,3.5;1.5,0.5;abort;Abort]";
if( node.name ~= 'default:chest' ) then
formspec = formspec..'item_image_button[1,1;1.5,1.5;default:chest;normal;]'..
'button_exit[1,2.5;1.5,0.5;normal;normal]';
else
formspec = formspec..'item_image[1,1;1.5,1.5;default:chest]'..
'label[1,2.5;normal]';
end
if( node.name ~= 'default:chest_locked' ) then
formspec = formspec..'item_image_button[3,1;1.5,1.5;default:chest_locked;locked;]'..
'button_exit[3,2.5;1.5,0.5;locked;locked]';
else
formspec = formspec..'item_image[3,1;1.5,1.5;default:chest_locked]'..
'label[3,2.5;locked]';
end
if( node.name ~= 'chesttools:shared_chest' ) then
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]';
local can_be_upgraded = false;
local offset = 1;
for nr, update_data in ipairs( chesttools.update_price ) do
local link = tostring(update_data[4]);
local chest_node_name = update_data[1];
-- only offer possible updates
if( minetest.registered_nodes[ chest_node_name ]) then
if( node.name ~= chest_node_name ) then
formspec = formspec..'item_image_button['..tostring(offset)..',1;1.5,1.5;'..
chest_node_name..';'..link..';]'..
'button_exit['..tostring(offset)..',2.5;1.5,0.5;'..
link..';'..link..']';
else
can_be_upgraded = true;
formspec = formspec..'item_image['..tostring(offset)..',1;1.5,1.5;'..
chest_node_name..']'..
'label['..tostring(offset)..',2.5;'..link..']';
end
offset = offset + 2;
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 );
end
return nil;