1 -- Global namespace for functions
12 minetest.register_node("fire:basic_flame", {
13 drawtype = "firelike",
16 name = "fire_basic_flame_animated.png",
18 type = "vertical_frames",
25 inventory_image = "fire_basic_flame.png",
30 sunlight_propagates = true,
31 damage_per_second = 4,
32 groups = {igniter = 2, dig_immediate = 3, not_in_creative_inventory = 1},
33 on_timer = function(pos)
34 local f = minetest.find_node_near(pos, 1, {"group:flammable"})
36 minetest.remove_node(pos)
44 on_construct = function(pos)
45 minetest.get_node_timer(pos):start(math.random(30, 60))
49 minetest.register_node("fire:permanent_flame", {
50 description = "Permanent Flame",
51 drawtype = "firelike",
54 name = "fire_basic_flame_animated.png",
56 type = "vertical_frames",
63 inventory_image = "fire_basic_flame.png",
68 sunlight_propagates = true,
69 damage_per_second = 4,
70 groups = {igniter = 2, dig_immediate = 3},
77 minetest.register_tool("fire:flint_and_steel", {
78 description = "Flint and Steel",
79 inventory_image = "fire_flint_steel.png",
80 sound = {breaks = "default_tool_breaks"},
82 on_use = function(itemstack, user, pointed_thing)
83 local sound_pos = pointed_thing.above or user:get_pos()
85 "fire_flint_and_steel",
86 {pos = sound_pos, gain = 0.5, max_hear_distance = 8}
88 local player_name = user:get_player_name()
89 if pointed_thing.type == "node" then
90 local node_under = minetest.get_node(pointed_thing.under).name
91 local nodedef = minetest.registered_nodes[node_under]
95 if minetest.is_protected(pointed_thing.under, player_name) then
96 minetest.chat_send_player(player_name, "This area is protected")
99 if nodedef.on_ignite then
100 nodedef.on_ignite(pointed_thing.under, user)
101 elseif minetest.get_item_group(node_under, "flammable") >= 1
102 and minetest.get_node(pointed_thing.above).name == "air" then
103 minetest.set_node(pointed_thing.above, {name = "fire:basic_flame"})
106 if not (creative and creative.is_enabled_for
107 and creative.is_enabled_for(player_name)) then
109 local wdef = itemstack:get_definition()
110 itemstack:add_wear(1000)
112 if itemstack:get_count() == 0 and wdef.sound and wdef.sound.breaks then
113 minetest.sound_play(wdef.sound.breaks, {pos = sound_pos, gain = 0.5})
120 minetest.register_craft({
121 output = "fire:flint_and_steel",
123 {"default:flint", "default:steel_ingot"}
128 -- Override coalblock to enable permanent flame above
129 -- Coalblock is non-flammable to avoid unwanted basic_flame nodes
131 minetest.override_item("default:coalblock", {
132 after_destruct = function(pos, oldnode)
134 if minetest.get_node(pos).name == "fire:permanent_flame" then
135 minetest.remove_node(pos)
138 on_ignite = function(pos, igniter)
139 local flame_pos = {x = pos.x, y = pos.y + 1, z = pos.z}
140 if minetest.get_node(flame_pos).name == "air" then
141 minetest.set_node(flame_pos, {name = "fire:permanent_flame"})
151 local flame_sound = minetest.settings:get_bool("flame_sound")
152 if flame_sound == nil then
153 -- Enable if no setting present
164 local radius = 8 -- Flame node search radius around player
165 local cycle = 3 -- Cycle time for sound updates
167 -- Update sound for player
169 function fire.update_player_sound(player)
170 local player_name = player:get_player_name()
171 -- Search for flame nodes in radius around player
172 local ppos = player:get_pos()
173 local areamin = vector.subtract(ppos, radius)
174 local areamax = vector.add(ppos, radius)
175 local fpos, num = minetest.find_nodes_in_area(
178 {"fire:basic_flame", "fire:permanent_flame"}
180 -- Total number of flames in radius
181 local flames = (num["fire:basic_flame"] or 0) +
182 (num["fire:permanent_flame"] or 0)
183 -- Stop previous sound
184 if handles[player_name] then
185 minetest.sound_stop(handles[player_name])
186 handles[player_name] = nil
190 -- Find centre of flame positions
191 local fposmid = fpos[1]
192 -- If more than 1 flame
194 local fposmin = areamax
195 local fposmax = areamin
197 local fposi = fpos[i]
198 if fposi.x > fposmax.x then
201 if fposi.y > fposmax.y then
204 if fposi.z > fposmax.z then
207 if fposi.x < fposmin.x then
210 if fposi.y < fposmin.y then
213 if fposi.z < fposmin.z then
217 fposmid = vector.divide(vector.add(fposmin, fposmax), 2)
220 local handle = minetest.sound_play(
224 to_player = player_name,
225 gain = math.min(0.06 * (1 + flames * 0.125), 0.18),
226 max_hear_distance = 32,
227 loop = true, -- In case of lag
230 -- Store sound handle for this player
232 handles[player_name] = handle
237 -- Cycle for updating players sounds
239 minetest.register_globalstep(function(dtime)
240 timer = timer + dtime
241 if timer < cycle then
246 local players = minetest.get_connected_players()
247 for n = 1, #players do
248 fire.update_player_sound(players[n])
252 -- Stop sound and clear handle on player leave
254 minetest.register_on_leaveplayer(function(player)
255 local player_name = player:get_player_name()
256 if handles[player_name] then
257 minetest.sound_stop(handles[player_name])
258 handles[player_name] = nil
264 -- Deprecated function kept temporarily to avoid crashes if mod fire nodes call it
266 function fire.update_sounds_around(pos)
274 -- Extinguish all flames quickly with water, snow, ice
276 minetest.register_abm({
277 label = "Extinguish flame",
278 nodenames = {"fire:basic_flame", "fire:permanent_flame"},
279 neighbors = {"group:puts_out_fire"},
283 action = function(pos, node, active_object_count, active_object_count_wider)
284 minetest.remove_node(pos)
285 minetest.sound_play("fire_extinguish_flame",
286 {pos = pos, max_hear_distance = 16, gain = 0.15})
291 -- Enable the following ABMs according to 'enable fire' setting
293 local fire_enabled = minetest.settings:get_bool("enable_fire")
294 if fire_enabled == nil then
295 -- enable_fire setting not specified, check for disable_fire
296 local fire_disabled = minetest.settings:get_bool("disable_fire")
297 if fire_disabled == nil then
298 -- Neither setting specified, check whether singleplayer
299 fire_enabled = minetest.is_singleplayer()
301 fire_enabled = not fire_disabled
305 if not fire_enabled then
307 -- Remove basic flames only if fire disabled
309 minetest.register_abm({
310 label = "Remove disabled fire",
311 nodenames = {"fire:basic_flame"},
315 action = minetest.remove_node,
320 -- Ignite neighboring nodes, add basic flames
322 minetest.register_abm({
323 label = "Ignite flame",
324 nodenames = {"group:flammable"},
325 neighbors = {"group:igniter"},
329 action = function(pos, node, active_object_count, active_object_count_wider)
330 -- If there is water or stuff like that around node, don't ignite
331 if minetest.find_node_near(pos, 1, {"group:puts_out_fire"}) then
334 local p = minetest.find_node_near(pos, 1, {"air"})
336 minetest.set_node(p, {name = "fire:basic_flame"})
341 -- Remove flammable nodes around basic flame
343 minetest.register_abm({
344 label = "Remove flammable nodes",
345 nodenames = {"fire:basic_flame"},
346 neighbors = "group:flammable",
350 action = function(pos, node, active_object_count, active_object_count_wider)
351 local p = minetest.find_node_near(pos, 1, {"group:flammable"})
353 local flammable_node = minetest.get_node(p)
354 local def = minetest.registered_nodes[flammable_node.name]
358 minetest.remove_node(p)
359 minetest.check_for_falling(p)