giftbox/init.lua

427 lines
17 KiB
Lua

--------------------------------------------------------
-- Minetest :: Giftbox Mod v2.4 (giftbox)
--
-- See README.txt for licensing and other information.
-- Copyright (c) 2016-2020, Leslie E. Krause
--
-- ./games/minetest_game/mods/giftbox/init.lua
--------------------------------------------------------
giftbox = { }
local config = minetest.load_config( )
local box_colors = { "black", "blue", "cyan", "green", "magenta", "red", "white", "yellow" }
-- black = black + grey
-- blue = blue + magenta
-- brown => yellow
-- cyan = cyan + yellow
-- dark_green => green
-- dark_grey => cyan
-- green = green + red
-- grey => white
-- magenta = magenta + cyan
-- orange => red
-- pink => magenta
-- red = red + green
-- violet => blue
-- white = white + grey
-- yellow = yellow + green
minetest.register_node( "giftbox:present", {
description = "Gift Box",
tiles = { "present_top.png", "present_bottom.png", "present_side.png",
"present_side.png", "present_side.png", "present_side.png" },
is_ground_content = false,
groups = { choppy = 2, oddly_breakable_by_hand = 2 },
sounds = default.node_sound_wood_defaults( ),
drop = { },
after_place_node = function ( pos, player )
minetest.get_meta( pos ):set_string( "infotext", config.present_infotext .. " (placed by " .. player:get_player_name( ) .. ")" )
end,
on_construct = function ( pos )
local meta = minetest.get_meta( pos )
meta:get_inventory( ):set_size( "main", 1 )
meta:set_string( "oldtime", os.time( ) )
meta:set_string( "newtime", os.time( ) )
end,
can_dig = function ( pos, player )
return not minetest.is_protected( pos, player:get_player_name( ) ) and default.is_empty( pos )
end,
allow_metadata_inventory_take = function ( pos, listname, index, stack, player )
-- only allow receiver to take item and remove node
-- of course, placer can already bypass protection
if minetest.is_protected( pos, player:get_player_name( ) ) then
return 0
end
return stack:get_count( )
end,
allow_metadata_inventory_put = function ( pos, listname, index, stack, player )
return 0
end,
on_metadata_inventory_take = function ( pos, listname, index, stack, player )
if default.is_empty( pos ) then
minetest.remove_node( pos )
end
minetest.log( "action", string.format( default.STATUS_CONTAINER_GET, player:get_player_name( ), "giftbox", minetest.pos_to_string( pos ) ) )
end,
on_open = function ( pos, clicker )
local pname = clicker:get_player_name( )
local spos = pos.x .. "," .. pos.y .. "," .. pos.z
if minetest.check_player_privs( pname, { give = true } ) then
local slot, name
local formspec =
"size[8,6]" ..
default.gui_bg ..
default.gui_bg_img ..
default.gui_slots ..
"label[1,0.8;Select an item to place in the gift box.]" ..
"list[nodemeta:%s;main;6,0.5;1,1;]"
slot = 0
for _, name in ipairs( config.present_items ) do
formspec = formspec .. "item_image_button[ " .. ( slot % 8 ) .. "," .. ( math.floor ( slot / 8 ) + 2 ) .. ";1,1;" .. name .. ";add " .. name .. ";]"
slot = slot + 1
end
return string.format( formspec, spos )
elseif not minetest.is_protected( pos, pname ) and not default.is_empty( pos ) then
-- only show formspec if placer remembered to select item
-- otherwise, allow node be dug normally (but no drops)
local formspec =
"size[10,6.5]" ..
"image[0,0;12,6;" .. config.present_greeting .. "]" ..
default.gui_bg ..
default.gui_bg_img ..
default.gui_slots ..
"list[nodemeta:%s;main;7,4;1,1;]" ..
"list[current_player;main;1,5.5;8,1;]" ..
default.get_hotbar_bg( 1, 5.5 )
return string.format( formspec, spos )
end
end,
on_close = function ( pos, player, fields )
local fname, item
fname = next( fields, nil ) -- use next since we only care about the name of a single button
if minetest.check_player_privs( player:get_player_name( ), { give = true } ) and fname then
item = string.match( fname, "add (.+)" )
if item then
minetest.get_meta( pos ):get_inventory( ):set_stack( "main", 1, item )
minetest.log( "action", string.format( default.STATUS_CONTAINER_PUT, player:get_player_name( ), "present", minetest.pos_to_string( pos ) ) )
end
end
end,
} )
minetest.register_craftitem( "giftbox:package_unsealed", {
description = "Package (To seal, point to an object and use)",
inventory_image = "package_unsealed.png",
wield_image = "package_unsealed2.png",
groups = { flammable = 3 },
on_use = function( cur_stack, player, pointed_thing )
if pointed_thing.type == "object" and not pointed_thing.ref:is_player( ) then
local player_name = player:get_player_name( )
local player_inv = player:get_inventory( )
-- ignore objects that are not builtin-item (sanity check)
local entity = pointed_thing.ref:get_luaentity( )
if entity.name ~= "__builtin:item" then return end
local item_name = ItemStack( entity.itemstring ):get_name( )
if item_name == "giftbox:package_unsealed" or item_name == "giftbox:package_sealed" then
minetest.chat_send_player( player_name, "This item cannot be stored inside a package." )
return
end
cur_stack:take_item( )
pointed_thing.ref:remove( )
-- produce a sealed package containing pointed_thing
local new_stack = ItemStack( "giftbox:package_sealed" )
local meta = new_stack:get_meta( )
meta:set_string( "description", config.parcel_public_description ..
" (from " .. player_name .. " on " .. os.date( "%x" ) .. ")" )
meta:set_string( "timestamp", os.time( ) )
meta:set_string( "receiver", default.OWNER_NOBODY )
meta:set_string( "owner", player_name )
meta:set_string( "is_anonymous", "false" )
meta:set_string( "itemstring", entity.itemstring )
if player_inv:room_for_item( "main", new_stack ) then
player_inv:add_item( "main", new_stack )
else
minetest.add_item( player:getpos( ), new_stack )
end
end
return cur_stack
end
} )
minetest.register_craftitem( "giftbox:package_sealed", {
inventory_image = "package_sealed.png",
wield_image = "package_sealed2.png",
groups = { flammable = 3, not_in_creative_inventory = 1 },
on_use = function( itemstack, player, pointed_thing )
local player_name = player:get_player_name( )
local meta = itemstack:get_meta( )
local receiver = meta:get_string( "receiver" )
local owner = meta:get_string( "owner" )
if owner == player_name or minetest.check_player_privs( player_name, { give = true } ) then
local formspec =
"size[8,3.5]" ..
default.gui_bg ..
default.gui_bg_img ..
"checkbox[4.8,1.8;is_anonymous;Anonymous Sender;" .. meta:get_string( "is_anonymous" ) .. "]" ..
"label[0.1,2.0;Recipient:]" ..
"field[1.8,2.4;3.0,0.25;receiver;;" .. receiver .. "]" ..
"label[2.9,0.0;Package Contents:]" ..
"image[3.5,0.6;1,1;gui_furnace_arrow_bg.png^[transformR270]" ..
"item_image_button[2.5,0.6;1,1;giftbox:package_sealed;restore;]" ..
"item_image_button[4.5,0.6;1,1;" .. ItemStack( meta:get_string( "itemstring" ) ):get_name( ) .. ";revert;]" ..
"label[0.1,2.9;Stored on " .. os.date( "%x %X", tonumber( meta:get_string( "timestamp" ) ) ) .. "]" ..
"button_exit[6.0,3.0;2,0.3;save;Save]"
minetest.create_form( nil, player_name, formspec, function ( _, player, fields )
if fields.is_anonymous then
meta:set_string( "is_anonymous", fields.is_anonymous )
elseif fields.revert then
local itemstring = meta:get_string( "itemstring" )
player:set_wielded_item( ItemStack( itemstring ) )
minetest.destroy_form( player_name )
elseif fields.restore then
player:set_wielded_item( "giftbox:package_unsealed" )
minetest.destroy_form( player_name )
elseif fields.save and fields.receiver then
if fields.receiver == owner then
minetest.chat_send_player( owner, "You cannot send a parcel to yourself." )
return
elseif fields.receiver ~= default.OWNER_NOBODY and not string.find( fields.receiver, "^[-_A-Za-z0-9]+$" ) then
minetest.chat_send_player( owner, "The specified recipient is invalid." )
return
end
-- public vs. private letters and parcels
local description = fields.receiver == default.OWNER_NOBODY and
config.parcel_public_description or
string.format( config.parcel_private_description, fields.receiver )
if meta:get_string( "is_anonymous" ) == "false" then
description = description .. " (from " .. owner .. " on " .. os.date( "%x", tonumber( meta:get_string( "timestamp" ) ) ) .. ")"
end
meta:set_string( "description", description )
meta:set_string( "receiver", fields.receiver )
player:set_wielded_item( itemstack )
end
end )
elseif receiver == player_name or receiver == default.OWNER_NOBODY then
local formspec =
"size[9,7]" ..
default.gui_bg ..
default.gui_bg_img ..
"background[0,0;9,6;" .. config.package_viewer .. "]" ..
"label[0.5,0.5;" .. minetest.colorize( "#000000", os.date( "%x %X", tonumber( meta:get_string( "timestamp" ) ) ) ) .. "]" ..
"button_exit[3.0,6.5;3.0,0.3;open;Open Package]"
if meta:get_string( "is_anonymous" ) == "false" then
formspec = formspec .. "label[3.5,2.5;" .. minetest.colorize( "#000000", owner ) .. "]"
end
if receiver ~= default.OWNER_NOBODY then
formspec = formspec .. "label[3.5,3.0;" .. minetest.colorize( "#000000", receiver ) .. "]"
end
minetest.create_form( nil, player_name, formspec, function ( _, player, fields )
if fields.open then
local itemstring = meta:get_string( "itemstring" )
player:set_wielded_item( ItemStack( itemstring ) )
-- TODO: record deliveries of letters and parcels in debug log
end
end )
else
minetest.chat_send_player( player_name, "Access denied. This parcel does not belong to you." )
end
return itemstack
end
} )
minetest.register_craft( {
output = "giftbox:package_unsealed",
recipe = {
{ "default:paper", "default:paper", "default:paper" },
{ "default:paper", "", "default:paper" },
{ "default:paper", "default:paper", "default:paper" },
}
} )
for i, color in ipairs( box_colors ) do
minetest.register_node( "giftbox:giftbox_" .. color, {
description = ( color:gsub( "^%l", string.upper ) ) .. " Gift Box",
drawtype = "mesh",
mesh = "giftbox.obj",
tiles = { "giftbox_" .. color .. ".png" },
paramtype = "light",
visual_scale = 0.45,
wield_scale = { x = 1, y = 1, z = 1 }, -- apparently no way to set wield scale of mesh?
sunlight_propagates = true,
is_ground_content = false,
groups = { choppy = 2, oddly_breakable_by_hand = 2, flammable = 1 },
sounds = default.node_sound_dirt_defaults(),
paramtype2 = "facedir",
selection_box = {
type = "fixed",
fixed = {
{ -0.45, -0.5, -0.45, 0.45, 0.45, 0.45 },
}
},
drop = { max_items = 1, items = config.giftbox_drops },
on_dig = function ( pos, node, player )
local digger = player:get_player_name( )
local receiver = minetest.get_meta( pos ):get_string( "receiver" )
-- local is_protected = minetest.get_meta( pos ):get_string( "is_protected" ) == "true"
if not minetest.is_protected( pos, digger ) then
-- always allow owner to dig node, but still obey protection
minetest.handle_node_drops( pos, { node.name }, player )
minetest.remove_node( pos )
elseif receiver == digger or receiver == default.OWNER_NOBODY then
-- otherwise drop random items directly for receiver (if any)
-- this is necessary to bypass protection checks
local drops = minetest.get_node_drops( node.name, player:get_wielded_item( ):get_name( ) )
minetest.handle_node_drops( pos, drops, player )
minetest.remove_node( pos )
end
end,
after_place_node = function ( pos, player )
local placer = player:get_player_name( ) or "singleplayer"
local meta = minetest.get_meta( pos )
default.set_owner( pos, placer )
meta:set_string( "receiver", default.OWNER_NOBODY )
meta:set_string( "is_anonymous", "false" )
-- initial item string: Gift Box (placed by sorcerykid)
meta:set_string( "infotext", config.giftbox_public_infotext1 .. " (from " .. placer .. ")" )
end,
on_open = function ( pos, player, fields )
local meta = minetest.get_meta( pos )
local formspec =
"size[8,3]" ..
default.gui_bg ..
default.gui_bg_img ..
"button_exit[6,2.5;2,0.3;save;Save]" ..
"checkbox[4.5,1.3;is_anonymous;Anonymous Sender;" .. meta:get_string( "is_anonymous" ) .. "]" ..
"label[0.1,0;Personalize your holiday greeting (or leave blank for the default):]" ..
"field[0.4,1;7.8,0.25;message;;" .. minetest.formspec_escape( meta:get_string( "message" ) ) .. "]" ..
"label[0.1,1.5;Recipient:]" ..
"field[1.8,1.9;2.5,0.25;receiver;;" .. meta:get_string( "receiver" ) .. "]"
-- only placer of gift box should edit properties, not the receiver
if default.is_owner( pos, player:get_player_name( ) ) then
return formspec
end
end,
on_close = function ( pos, player, fields )
local owner = player:get_player_name( )
local meta = minetest.get_meta( pos )
-- only placer of gift box should edit properties, not the receiver
if not default.is_owner( pos, owner ) then return end
if fields.is_anonymous then
-- in next version of active formspecs, we should save checkbox state
-- in form meta first rather than directly to node meta
meta:set_string( "is_anonymous", fields.is_anonymous )
elseif fields.save and fields.message and fields.receiver then
local infotext
if fields.message ~= "" and string.len( fields.message ) < 5 then
minetest.chat_send_player( owner, "The specified message is too short." )
return
elseif string.len( fields.message ) > 250 then
minetest.chat_send_player( owner, "The specified message is too long." )
return
elseif fields.receiver == owner then
minetest.chat_send_player( owner, "You cannot give a gift to yourself." )
return
elseif fields.receiver ~= default.OWNER_NOBODY and not string.find( fields.receiver, "^[-_A-Za-z0-9]+$" ) then
minetest.chat_send_player( owner, "The specified recipient is invalid." )
return
end
-- item string with message: Dear sorcerykid: "Happy holidays!" (placed by sorcerykid)
-- item string without message: Gift Box for maikerumine (placed by sorcerykid)
if fields.receiver == default.OWNER_NOBODY then
-- public gift box
infotext = fields.message == "" and
config.giftbox_public_infotext1 or
string.format( config.giftbox_public_infotext2, fields.message )
else
-- private gift box
infotext = fields.message == "" and
string.format( config.giftbox_private_infotext1, fields.receiver ) or
string.format( config.giftbox_private_infotext2, fields.receiver, fields.message )
end
if meta:get_string( "is_anonymous" ) == "false" then
infotext = infotext .. " (from " .. owner .. ")"
end
minetest.log( "action", string.format( default.STATUS_SIGNATURE_SET, player:get_player_name( ), fields.message, "giftbox", minetest.pos_to_string( pos ) ) )
meta:set_string( "receiver", fields.receiver )
meta:set_string( "message", fields.message )
meta:set_string( "infotext", infotext )
end
end,
} )
minetest.register_craft( {
output = "giftbox:giftbox_" .. color,
recipe = {
{ "wool:" .. color, "farming:cotton", "wool:" .. color },
{ "default:paper", "default:mese_crystal", "default:paper" },
{ "wool:" .. color, "default:paper", "wool:" .. color },
}
} )
end
minetest.register_alias( "mt_seasons:gift_box_brown", "giftbox:giftbox_yellow" )
minetest.register_alias( "mt_seasons:gift_box_dark_green", "giftbox:giftbox_green" )
minetest.register_alias( "mt_seasons:gift_box_dark_grey", "giftbox:giftbox_cyan" )
minetest.register_alias( "mt_seasons:gift_box_grey", "giftbox:giftbox_white" )
minetest.register_alias( "mt_seasons:gift_box_orange", "giftbox:giftbox_red" )
minetest.register_alias( "mt_seasons:gift_box_pink", "giftbox:giftbox_magenta" )
minetest.register_alias( "mt_seasons:gift_box_violet", "giftbox:giftbox_blue" )
minetest.register_alias( "mt_seasons:gift_box_red", "giftbox:giftbox_red" )
minetest.register_alias( "mt_seasons:gift_box_green", "giftbox:giftbox_green" )
minetest.register_alias( "mt_seasons:gift_box_blue", "giftbox:giftbox_blue" )
minetest.register_alias( "mt_seasons:gift_box_cyan", "giftbox:giftbox_cyan" )
minetest.register_alias( "mt_seasons:gift_box_magenta", "giftbox:giftbox_magenta" )
minetest.register_alias( "mt_seasons:gift_box_yellow", "giftbox:giftbox_yellow" )
minetest.register_alias( "mt_seasons:gift_box_white", "giftbox:giftbox_white" )
minetest.register_alias( "mt_seasons:gift_box_black", "giftbox:giftbox_black" )
minetest.register_alias( "giftbox:giftbox", "giftbox:present" )