Fixer
2018-07-15 395089dfd83a797ef408a28a8087276b8845bd3d
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.
41a10a 23 local S = rawget(_G, "intllib") and intllib.Getter() or function(s) return s end
39c41a 24
731a82 25 local function get_meta_type(name, metaname)
S 26     local def = wrench.registered_nodes[name]
161462 27     return def and def.metas and def.metas[metaname] or nil
21c96a 28 end
M 29
731a82 30 local function get_pickup_name(name)
S 31     return "wrench:picked_up_"..(name:gsub(":", "_"))
32 end
33
34 local function restore(pos, placer, itemstack)
35     local name = itemstack:get_name()
78bfa4 36     local node = minetest.get_node(pos)
731a82 37     local meta = minetest.get_meta(pos)
S 38     local inv = meta:get_inventory()
9167d4 39     local data = itemstack:get_meta():get_string("data")
D 40     data = (data ~= "" and data) or    itemstack:get_metadata()
41     data = minetest.deserialize(data)
161462 42     if not data then
D 43         minetest.remove_node(pos)
44         minetest.log("error", placer:get_player_name().." wanted to place "..
45                 name.." at "..minetest.pos_to_string(pos)..
46                 ", but it had no data.")
47         minetest.log("verbose", "itemstack: "..itemstack:to_string())
48         return true
49     end
78bfa4 50     minetest.set_node(pos, {name = data.name, param2 = node.param2})
731a82 51     for name, value in pairs(data.metas) do
S 52         local meta_type = get_meta_type(data.name, name)
53         if meta_type == wrench.META_TYPE_INT then
54             meta:set_int(name, value)
55         elseif meta_type == wrench.META_TYPE_FLOAT then
56             meta:set_float(name, value)
57         elseif meta_type == wrench.META_TYPE_STRING then
58             meta:set_string(name, value)
59         end
60     end
9167d4 61     local lists = data.lists
4874e2 62     for listname, list in pairs(lists) do
R 63         inv:set_list(listname, list)
64     end
731a82 65     itemstack:take_item()
S 66     return itemstack
67 end
68
69 for name, info in pairs(wrench.registered_nodes) do
21c96a 70     local olddef = minetest.registered_nodes[name]
731a82 71     if olddef then
21c96a 72         local newdef = {}
731a82 73         for key, value in pairs(olddef) do
21c96a 74             newdef[key] = value
M 75         end
76         newdef.stack_max = 1
39c41a 77         newdef.description = S("%s with items"):format(newdef.description)
3b7695 78         newdef.groups = {}
21c96a 79         newdef.groups.not_in_creative_inventory = 1
M 80         newdef.on_construct = nil
81         newdef.on_destruct = nil
731a82 82         newdef.after_place_node = restore
S 83         minetest.register_node(":"..get_pickup_name(name), newdef)
21c96a 84     end
M 85 end
86
87 minetest.register_tool("wrench:wrench", {
39c41a 88     description = S("Wrench"),
21c96a 89     inventory_image = "technic_wrench.png",
M 90     tool_capabilities = {
91         full_punch_interval = 0.9,
92         max_drop_level = 0,
93         groupcaps = {
94             crumbly = {times={[2]=3.00, [3]=0.70}, uses=0, maxlevel=1},
95             snappy = {times={[3]=0.40}, uses=0, maxlevel=1},
731a82 96             oddly_breakable_by_hand = {times={[1]=7.00,[2]=4.00,[3]=1.40},
S 97                         uses=0, maxlevel=3}
21c96a 98         },
M 99         damage_groups = {fleshy=1},
100     },
101     on_place = function(itemstack, placer, pointed_thing)
102         local pos = pointed_thing.under
731a82 103         if not placer or not pos then
S 104             return
105         end
9167d4 106         local player_name = placer:get_player_name()
D 107         if minetest.is_protected(pos, player_name) then
108             minetest.record_protection_violation(pos, player_name)
731a82 109             return
S 110         end
21c96a 111         local name = minetest.get_node(pos).name
731a82 112         local def = wrench.registered_nodes[name]
S 113         if not def then
114             return
115         end
116
117         local stack = ItemStack(get_pickup_name(name))
118         local player_inv = placer:get_inventory()
119         if not player_inv:room_for_item("main", stack) then
120             return
121         end
3b7695 122         local meta = minetest.get_meta(pos)
395089 123         if def.owned and not minetest.check_player_privs(placer, "protection_bypass") then
d5c554 124             local owner = meta:get_string("owner")
9167d4 125             if owner and owner ~= player_name then
D 126                 minetest.log("action", player_name..
127                     " tried to pick up an owned node belonging to "..
d5c554 128                     owner.." at "..
3b7695 129                     minetest.pos_to_string(pos))
731a82 130                 return
21c96a 131             end
M 132         end
731a82 133
S 134         local metadata = {}
135         metadata.name = name
c5a2f0 136         metadata.version = LATEST_SERIALIZATION_VERSION
S 137
3b7695 138         local inv = meta:get_inventory()
731a82 139         local lists = {}
S 140         for _, listname in pairs(def.lists or {}) do
141             local list = inv:get_list(listname)
142             for i, stack in pairs(list) do
143                 list[i] = stack:to_string()
144             end
145             lists[listname] = list
21c96a 146         end
731a82 147         metadata.lists = lists
9167d4 148
D 149         local item_meta = stack:get_meta()
150         metadata.metas = {}
731a82 151         for name, meta_type in pairs(def.metas or {}) do
S 152             if meta_type == wrench.META_TYPE_INT then
9167d4 153                 metadata.metas[name] = meta:get_int(name)
731a82 154             elseif meta_type == wrench.META_TYPE_FLOAT then
9167d4 155                 metadata.metas[name] = meta:get_float(name)
731a82 156             elseif meta_type == wrench.META_TYPE_STRING then
9167d4 157                 metadata.metas[name] = meta:get_string(name)
3b7695 158             end
M 159         end
9167d4 160
D 161         item_meta:set_string("data", minetest.serialize(metadata))
731a82 162         minetest.remove_node(pos)
S 163         itemstack:add_wear(65535 / 20)
164         player_inv:add_item("main", stack)
21c96a 165         return itemstack
M 166     end,
3b32bf 167 })