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