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