Zefram
2014-08-22 0cf4133b9718b95dc65b5357892255a5115919e8
commit | author | age
d5c554 1 --[[
731a82 2 Wrench mod
S 3
4 Adds a wrench that allows the player to pickup nodes that contain an inventory
5 with items or metadata that needs perserving.
6 The wrench has the same tool capability as the normal hand.
7 To pickup a node simply right click on it. If the node contains a formspec,
8 you will need to shift+right click instead.
0cf413 9 Because it enables arbitrary nesting of chests, and so allows the player
Z 10 to carry an unlimited amount of material at once, this wrench is not
11 available to survival-mode players.
d5c554 12 --]]
21c96a 13
c5a2f0 14 local LATEST_SERIALIZATION_VERSION = 1
S 15
731a82 16 wrench = {}
S 17
18 local modpath = minetest.get_modpath(minetest.get_current_modname())
19 dofile(modpath.."/support.lua")
20 dofile(modpath.."/technic.lua")
21
39c41a 22 -- Boilerplate to support localized strings if intllib mod is installed.
X 23 local S
24 if intllib then
25     S = intllib.Getter()
26 else
27     S = function(s) return s end
28 end
29
731a82 30 local function get_meta_type(name, metaname)
S 31     local def = wrench.registered_nodes[name]
32     if not def or not def.metas or not def.metas[metaname] then
33         return nil
21c96a 34     end
731a82 35     return def.metas[metaname]
21c96a 36 end
M 37
731a82 38 local function get_pickup_name(name)
S 39     return "wrench:picked_up_"..(name:gsub(":", "_"))
40 end
41
42 local function restore(pos, placer, itemstack)
43     local name = itemstack:get_name()
44     local meta = minetest.get_meta(pos)
45     local inv = meta:get_inventory()
46     local data = minetest.deserialize(itemstack:get_metadata())
47     minetest.set_node(pos, {name = data.name})
48     local lists = data.lists
49     for listname, list in pairs(lists) do
50         inv:set_list(listname, list)
51     end
52     for name, value in pairs(data.metas) do
53         local meta_type = get_meta_type(data.name, name)
54         if meta_type == wrench.META_TYPE_INT then
55             meta:set_int(name, value)
56         elseif meta_type == wrench.META_TYPE_FLOAT then
57             meta:set_float(name, value)
58         elseif meta_type == wrench.META_TYPE_STRING then
59             meta:set_string(name, value)
60         end
61     end
62     itemstack:take_item()
63     return itemstack
64 end
65
66 for name, info in pairs(wrench.registered_nodes) do
21c96a 67     local olddef = minetest.registered_nodes[name]
731a82 68     if olddef then
21c96a 69         local newdef = {}
731a82 70         for key, value in pairs(olddef) do
21c96a 71             newdef[key] = value
M 72         end
73         newdef.stack_max = 1
39c41a 74         newdef.description = S("%s with items"):format(newdef.description)
3b7695 75         newdef.groups = {}
21c96a 76         newdef.groups.not_in_creative_inventory = 1
M 77         newdef.on_construct = nil
78         newdef.on_destruct = nil
731a82 79         newdef.after_place_node = restore
S 80         minetest.register_node(":"..get_pickup_name(name), newdef)
21c96a 81     end
M 82 end
83
84 minetest.register_tool("wrench:wrench", {
39c41a 85     description = S("Wrench"),
21c96a 86     inventory_image = "technic_wrench.png",
M 87     tool_capabilities = {
88         full_punch_interval = 0.9,
89         max_drop_level = 0,
90         groupcaps = {
91             crumbly = {times={[2]=3.00, [3]=0.70}, uses=0, maxlevel=1},
92             snappy = {times={[3]=0.40}, uses=0, maxlevel=1},
731a82 93             oddly_breakable_by_hand = {times={[1]=7.00,[2]=4.00,[3]=1.40},
S 94                         uses=0, maxlevel=3}
21c96a 95         },
M 96         damage_groups = {fleshy=1},
97     },
98     on_place = function(itemstack, placer, pointed_thing)
99         local pos = pointed_thing.under
731a82 100         if not placer or not pos then
S 101             return
102         end
103         if minetest.is_protected(pos, placer:get_player_name()) then
104             minetest.record_protection_violation(pos, placer:get_player_name())
105             return
106         end
21c96a 107         local name = minetest.get_node(pos).name
731a82 108         local def = wrench.registered_nodes[name]
S 109         if not def then
110             return
111         end
112
113         local stack = ItemStack(get_pickup_name(name))
114         local player_inv = placer:get_inventory()
115         if not player_inv:room_for_item("main", stack) then
116             return
117         end
3b7695 118         local meta = minetest.get_meta(pos)
731a82 119         if def.owned then
d5c554 120             local owner = meta:get_string("owner")
731a82 121             if owner and owner ~= placer:get_player_name() then
S 122                 minetest.log("action", placer:get_player_name()..
123                     " tried to pick up a owned node belonging to "..
d5c554 124                     owner.." at "..
3b7695 125                     minetest.pos_to_string(pos))
731a82 126                 return
21c96a 127             end
M 128         end
731a82 129
S 130         local metadata = {}
131         metadata.name = name
c5a2f0 132         metadata.version = LATEST_SERIALIZATION_VERSION
S 133
3b7695 134         local inv = meta:get_inventory()
731a82 135         local lists = {}
S 136         for _, listname in pairs(def.lists or {}) do
137             if not inv:is_empty(listname) then
138                 empty = false
21c96a 139             end
731a82 140             local list = inv:get_list(listname)
S 141             for i, stack in pairs(list) do
142                 list[i] = stack:to_string()
143             end
144             lists[listname] = list
21c96a 145         end
731a82 146         metadata.lists = lists
3b7695 147         
731a82 148         local metas = {}
S 149         for name, meta_type in pairs(def.metas or {}) do
150             if meta_type == wrench.META_TYPE_INT then
151                 metas[name] = meta:get_int(name)
152             elseif meta_type == wrench.META_TYPE_FLOAT then
153                 metas[name] = meta:get_float(name)
154             elseif meta_type == wrench.META_TYPE_STRING then
155                 metas[name] = meta:get_string(name)
3b7695 156             end
M 157         end
731a82 158         metadata.metas = metas
3b7695 159         
731a82 160         stack:set_metadata(minetest.serialize(metadata))
S 161         minetest.remove_node(pos)
162         itemstack:add_wear(65535 / 20)
163         player_inv:add_item("main", stack)
21c96a 164         return itemstack
M 165     end,
3b32bf 166 })