From b6a845ba27620c416f7347dd89f4c9f5e73f66ed Mon Sep 17 00:00:00 2001 From: Leslie Krause Date: Sun, 24 Dec 2017 12:37:00 -0500 Subject: [PATCH] Build 04 - renamed admin giftbox to "present" for distinction - renamed associated texture files of present - replaced owner meta for present with sender instead - added protection check to inventory take of present - disabled formspec for recipient of empty present - added sender/receiver checks when digging giftbox - made default infotext of giftbox configurable - changed owner of giftbox to placer for simplicity - set default receiver of giftbox during placement - switched all prior references of owner to receiver - added alias for original admin giftbox --- README.txt | 107 ++++ config.lua | 10 +- init.lua | 516 +++++++++--------- ...{giftbox_bottom.png => present_bottom.png} | Bin textures/present_greeting.png | Bin 0 -> 17677 bytes .../{giftbox_side.png => present_side.png} | Bin textures/{giftbox_top.png => present_top.png} | Bin 7 files changed, 386 insertions(+), 247 deletions(-) create mode 100644 README.txt rename textures/{giftbox_bottom.png => present_bottom.png} (100%) create mode 100644 textures/present_greeting.png rename textures/{giftbox_side.png => present_side.png} (100%) rename textures/{giftbox_top.png => present_top.png} (100%) diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..fb89757 --- /dev/null +++ b/README.txt @@ -0,0 +1,107 @@ +========================================================== +Giftbox Mod v2.0 by sorcerykid + +https://forum.minetest.net/viewtopic.php?f=9&t=19133 + + +License of source code +---------------------------------------------------------- + +GNU Lesser General Public License v3 (LGPL-3.0) + +Copyright (c) 2016-2017, Leslie E. Krause + +Original source code by maikerumine: +https://github.com/maikerumine/just_test_tribute/blob/master/mods/mt_seasons/nodes.lua + +This program is free software; you can redistribute it and/or modify it under the terms of +the GNU Lesser 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 Lesser General Public License for more details. + +http://www.gnu.org/licenses/lgpl-2.1.html + + + +License of media (textures, sounds, and models) +---------------------------------------------------------- + +Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0) + + /models/giftbox.obj + by Toby109tt + + /textures/present_bottom.png + by lag01 + modified by maikerumine + modified by sorcerykid + + /textures/present_side.png + by lag01 + modified by maikerumine + modified by sorcerykid + + /textures/present_top.png + by lag01 + modified by maikerumine + modified by sorcerykid + + /textures/giftbox_red.png + by Toby109tt + modified by sorcerykid + + /textures/giftbox_green.png + by Toby109tt + modified by sorcerykid + + /textures/giftbox_blue.png + by Toby109tt + modified by sorcerykid + + /textures/giftbox_cyan.png + by Toby109tt + modified by sorcerykid + + /textures/giftbox_magenta.png + by Toby109tt + modified by sorcerykid + + /textures/giftbox_yellow.png + by Toby109tt + modified by sorcerykid + + /textures/giftbox_black.png + by Toby109tt + modified by sorcerykid + + /textures/giftbox_white.png + by Toby109tt + modified by sorcerykid + +You are free to: +Share — copy and redistribute the material in any medium or format. +Adapt — remix, transform, and build upon the material for any purpose, even commercially. +The licensor cannot revoke these freedoms as long as you follow the license terms. + +Under the following terms: + +Attribution — You must give appropriate credit, provide a link to the license, and +indicate if changes were made. You may do so in any reasonable manner, but not in any way +that suggests the licensor endorses you or your use. + +No additional restrictions — You may not apply legal terms or technological measures that +legally restrict others from doing anything the license permits. + +Notices: + +You do not have to comply with the license for elements of the material in the public +domain or where your use is permitted by an applicable exception or limitation. +No warranties are given. The license may not give you all of the permissions necessary +for your intended use. For example, other rights such as publicity, privacy, or moral +rights may limit how you use the material. + +For more details: +http://creativecommons.org/licenses/by-sa/3.0/ diff --git a/config.lua b/config.lua index daf521d..1c02d7c 100644 --- a/config.lua +++ b/config.lua @@ -35,6 +35,11 @@ giftbox.present_items = { "default:meselamp 10", } +giftbox.giftbox_public_infotext1 = "Gift Box" +giftbox.giftbox_public_infotext2 = "'%s'" +giftbox.giftbox_private_infotext1 = "Gift Box for %s" +giftbox.giftbox_private_infotext2 = "Dear %s: '%s'" + giftbox.giftbox_drops = { -- digging gift box allows for a single drop of items with a given a rarity { items = { "default:sword_diamond" }, rarity = 50 }, @@ -43,9 +48,6 @@ giftbox.giftbox_drops = { { items = { "default:pick_diamond" }, rarity = 50 }, { items = { "default:pick_bronze" }, rarity = 25 }, - { items = { "default:gold_lump 5" }, rarity = 10 }, - { items = { "default:coal_lump 10" }, rarity = 10 }, - -- default drop must be placed last and have rarity of 0 to avoid empty drops - { items = { "farming:gingerbread_cookie 5", "farming:candycane 10" }, rarity = 0 }, + { items = { "default:gold_lump 5", "default:coal_lump 10" }, rarity = 0 }, } diff --git a/init.lua b/init.lua index 01269ba..bbe0a5e 100644 --- a/init.lua +++ b/init.lua @@ -1,243 +1,273 @@ --------------------------------------------------------- --- Minetest :: Giftbox Mod v2.0 alpha (giftbox) --- --- See README.txt for licensing and other information. --- Copyright (c) 2016-2017, Leslie Ellen Krause --- --- ./games/just_test_tribute/mods/giftbox/init.lua --------------------------------------------------------- - -giftbox = { } - -dofile( minetest.get_modpath( "giftbox" ) .. "/config.lua" ) - -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:giftbox", { - description = "Gift Box", - tiles = { "giftbox_top.png", "giftbox_bottom.png", "giftbox_side.png", - "giftbox_side.png", "giftbox_side.png", "giftbox_side.png" }, - is_ground_content = false, - groups = { choppy = 2, oddly_breakable_by_hand = 2 }, - sounds = default.node_sound_wood_defaults( ), - - after_place_node = function( pos, player ) - local owner = player:get_player_name( ) or "singleplayer" - local meta = minetest.get_meta( pos ) --- meta:set_string( "owner", owner ) - meta:set_string( "infotext", giftbox.present_infotext .. " (placed by " .. owner .. ")" ) - 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 ) - if not default.is_owner( pos, player ) 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( giftbox.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 ) then - local formspec = - "size[10,6.5]" .. - "image[0,0;12,6;" .. giftbox.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, -}) - -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 = giftbox.giftbox_drops }, - - after_place_node = function( pos, player ) - -- initial item string: Gift Box (placed by sorcerykid) - - local placer = player:get_player_name( ) or "singleplayer" - local meta = minetest.get_meta( pos ) - meta:set_string( "owner", default.OWNER_NOBODY ) - meta:set_string( "placer", placer ) - meta:set_string( "is_anonymous", "false" ) - meta:set_string( "infotext", "Public Gift Box (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[6,1.6;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.5,0.25;message;;" .. meta:get_string( "message" ) .. "]" .. - "label[0.1,1.5;Recipient:]" .. - "field[1.8,1.9;3.5,0.25;owner;;" .. meta:get_string( "owner" ) .. "]" - - -- only placer of gift box should edit properties, not the receiver - if meta:get_string( "placer" ) ~= placer then - return formspec - end - end, - on_close = function( pos, player, fields ) - local placer = player:get_player_name( ) - local meta = minetest.get_meta( pos ) - - -- only placer of gift box should edit properties, not the receiver - if meta:get_string( "placer" ) ~= placer 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.owner then - local infotext - - if string.len( fields.message ) > 50 then - minetest.chat_send_player( placer, "The specified message is too long." ) - return - elseif fields.owner == placer then - minetest.chat_send_player( placer, "You cannot send a gift to yourself." ) - return - elseif not "" and not string.find( fields.owner, "^[_A-Za-z0-9]+$" ) then - minetest.chat_send_player( placer, "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.owner == default.OWNER_NOBODY then - -- public gift box - infotext = fields.message == "" and "Gift Box" or "\"" .. fields.message .. "\"" - else - -- private gift box - infotext = fields.message == "" and "Gift Box for " .. fields.owner or "Dear " .. fields.owner .. ": \"" .. fields.message .. "\"" - end - - if meta:get_string( "is_anonymous" ) == "false" then - infotext = infotext .. " (from " .. placer .. ")" - 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( "owner", fields.owner ) - 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 :: Giftbox Mod v2.0 (giftbox) +-- +-- See README.txt for licensing and other information. +-- Copyright (c) 2016-2017, Leslie Ellen Krause +-- +-- ./games/just_test_tribute/mods/giftbox/init.lua +-------------------------------------------------------- + +giftbox = { } + +dofile( minetest.get_modpath( "giftbox" ) .. "/config.lua" ) + +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", giftbox.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( giftbox.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;" .. giftbox.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, +}) + +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 = giftbox.giftbox_drops }, + + on_dig = function( pos, node, player ) + local digger = player:get_player_name( ) + local receiver = minetest.get_meta( pos ):get_string( "receiver" ) + + if default.is_owner( pos, player ) 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", "" ) + meta:set_string( "is_anonymous", "false" ) + + -- initial item string: Gift Box (placed by sorcerykid) + meta:set_string( "infotext", giftbox.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 Gift;" .. 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;;" .. 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 ) 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, player ) 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 string.len( fields.message ) > 50 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 ~= "" 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 + giftbox.giftbox_public_infotext1 or + string.format( giftbox.giftbox_public_infotext2, fields.message ) + else + -- private gift box + infotext = fields.message == "" and + string.format( giftbox.giftbox_private_infotext1, fields.receiver ) or + string.format( giftbox.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" ) diff --git a/textures/giftbox_bottom.png b/textures/present_bottom.png similarity index 100% rename from textures/giftbox_bottom.png rename to textures/present_bottom.png diff --git a/textures/present_greeting.png b/textures/present_greeting.png new file mode 100644 index 0000000000000000000000000000000000000000..88e5c1c3a8b06bb7c366849084b648a7dec3b0d5 GIT binary patch literal 17677 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 ly|4H6zTVgSdSCzI^*@m|0r|irDn