1 -- Minetest 0.4 mod: bucket
2 -- See README.txt for licensing and other information.
4 minetest.register_alias("bucket", "bucket:bucket_empty")
5 minetest.register_alias("bucket_water", "bucket:bucket_water")
6 minetest.register_alias("bucket_lava", "bucket:bucket_lava")
8 minetest.register_craft({
9 output = 'bucket:bucket_empty 1',
11 {'default:steel_ingot', '', 'default:steel_ingot'},
12 {'', 'default:steel_ingot', ''},
19 local function check_protection(pos, name, text)
20 if minetest.is_protected(pos, name) then
21 minetest.log("action", (name ~= "" and name or "A mod")
22 .. " tried to " .. text
23 .. " at protected position "
24 .. minetest.pos_to_string(pos)
26 minetest.record_protection_violation(pos, name)
32 -- Register a new liquid
33 -- source = name of the source node
34 -- flowing = name of the flowing node
35 -- itemname = name of the new bucket item (or nil if liquid is not takeable)
36 -- inventory_image = texture of the new bucket item (ignored if itemname == nil)
37 -- name = text description of the bucket item
38 -- groups = (optional) groups of the bucket item, for example {water_bucket = 1}
39 -- force_renew = (optional) bool. Force the liquid source to renew if it has a
40 -- source neighbour, even if defined as 'liquid_renewable = false'.
41 -- Needed to avoid creating holes in sloping rivers.
42 -- This function can be called from any mod (that depends on bucket).
43 function bucket.register_liquid(source, flowing, itemname, inventory_image, name,
45 bucket.liquids[source] = {
49 force_renew = force_renew,
51 bucket.liquids[flowing] = bucket.liquids[source]
53 if itemname ~= nil then
54 minetest.register_craftitem(itemname, {
56 inventory_image = inventory_image,
58 liquids_pointable = true,
61 on_place = function(itemstack, user, pointed_thing)
62 -- Must be pointing to node
63 if pointed_thing.type ~= "node" then
67 local node = minetest.get_node_or_nil(pointed_thing.under)
68 local ndef = node and minetest.registered_nodes[node.name]
70 -- Call on_rightclick if the pointed node defines it
71 if ndef and ndef.on_rightclick and
72 not (user and user:is_player() and
73 user:get_player_control().sneak) then
74 return ndef.on_rightclick(
82 -- Check if pointing to a buildable node
83 if ndef and ndef.buildable_to then
84 -- buildable; replace the node
85 lpos = pointed_thing.under
87 -- not buildable to; place the liquid above
88 -- check if the node above can be replaced
90 lpos = pointed_thing.above
91 node = minetest.get_node_or_nil(lpos)
92 local above_ndef = node and minetest.registered_nodes[node.name]
94 if not above_ndef or not above_ndef.buildable_to then
95 -- do not remove the bucket with the liquid
100 if check_protection(lpos, user
101 and user:get_player_name()
102 or "", "place "..source) then
106 minetest.set_node(lpos, {name = source})
107 return ItemStack("bucket:bucket_empty")
113 minetest.register_craftitem("bucket:bucket_empty", {
114 description = "Empty Bucket",
115 inventory_image = "bucket.png",
117 liquids_pointable = true,
118 on_use = function(itemstack, user, pointed_thing)
119 if pointed_thing.type == "object" then
120 pointed_thing.ref:punch(user, 1.0, { full_punch_interval=1.0 }, nil)
121 return user:get_wielded_item()
122 elseif pointed_thing.type ~= "node" then
123 -- do nothing if it's neither object nor node
126 -- Check if pointing to a liquid source
127 local node = minetest.get_node(pointed_thing.under)
128 local liquiddef = bucket.liquids[node.name]
129 local item_count = user:get_wielded_item():get_count()
132 and liquiddef.itemname ~= nil
133 and node.name == liquiddef.source then
134 if check_protection(pointed_thing.under,
135 user:get_player_name(),
136 "take ".. node.name) then
140 -- default set to return filled bucket
141 local giving_back = liquiddef.itemname
143 -- check if holding more than 1 empty bucket
144 if item_count > 1 then
146 -- if space in inventory add filled bucked, otherwise drop as item
147 local inv = user:get_inventory()
148 if inv:room_for_item("main", {name=liquiddef.itemname}) then
149 inv:add_item("main", liquiddef.itemname)
151 local pos = user:getpos()
152 pos.y = math.floor(pos.y + 0.5)
153 minetest.add_item(pos, liquiddef.itemname)
156 -- set to return empty buckets minus 1
157 giving_back = "bucket:bucket_empty "..tostring(item_count-1)
161 -- force_renew requires a source neighbour
162 local source_neighbor = false
163 if liquiddef.force_renew then
165 minetest.find_node_near(pointed_thing.under, 1, liquiddef.source)
167 if not (source_neighbor and liquiddef.force_renew) then
168 minetest.add_node(pointed_thing.under, {name = "air"})
171 return ItemStack(giving_back)
173 -- non-liquid nodes will have their on_punch triggered
174 local node_def = minetest.registered_nodes[node.name]
176 node_def.on_punch(pointed_thing.under, node, user, pointed_thing)
178 return user:get_wielded_item()
183 bucket.register_liquid(
184 "default:water_source",
185 "default:water_flowing",
186 "bucket:bucket_water",
192 -- River water source is 'liquid_renewable = false' to avoid horizontal spread
193 -- of water sources in sloping rivers that can cause water to overflow
194 -- riverbanks and cause floods.
195 -- River water source is instead made renewable by the 'force renew' option
198 bucket.register_liquid(
199 "default:river_water_source",
200 "default:river_water_flowing",
201 "bucket:bucket_river_water",
202 "bucket_river_water.png",
203 "River Water Bucket",
208 bucket.register_liquid(
209 "default:lava_source",
210 "default:lava_flowing",
211 "bucket:bucket_lava",
216 minetest.register_craft({
218 recipe = "bucket:bucket_lava",
220 replacements = {{"bucket:bucket_lava", "bucket:bucket_empty"}},