1 -- minetest/fire/init.lua
3 minetest.register_node("fire:basic_flame", {
5 drawtype = "glasslike",
6 tile_images = {"fire_basic_flame.png"},
8 groups = {igniter=3,dig_immediate=3},
15 -- key: position hash of low corner of area
16 -- value: {handle=sound handle, name=sound name}
19 function fire.get_area_p0p1(pos)
21 x=math.floor(pos.x/fire.D)*fire.D,
22 y=math.floor(pos.y/fire.D)*fire.D,
23 z=math.floor(pos.z/fire.D)*fire.D,
33 function fire.update_sounds_around(pos)
34 local p0, p1 = fire.get_area_p0p1(pos)
35 local cp = {x=(p0.x+p1.x)/2, y=(p0.y+p1.y)/2, z=(p0.z+p1.z)/2}
36 local flames_p = minetest.env:find_nodes_in_area(p0, p1, {"fire:basic_flame"})
37 --print("number of flames at "..minetest.pos_to_string(p0).."/"
38 -- ..minetest.pos_to_string(p1)..": "..#flames_p)
39 local should_have_sound = (#flames_p > 0)
40 local wanted_sound = nil
41 if #flames_p >= 9 then
42 wanted_sound = {name="fire_large", gain=1.5}
43 elseif #flames_p > 0 then
44 wanted_sound = {name="fire_small", gain=1.5}
46 local p0_hash = minetest.hash_node_position(p0)
47 local sound = fire.sounds[p0_hash]
49 if should_have_sound then
50 fire.sounds[p0_hash] = {
51 handle = minetest.sound_play(wanted_sound, {pos=cp, loop=true}),
52 name = wanted_sound.name,
56 if not wanted_sound then
57 minetest.sound_stop(sound.handle)
58 fire.sounds[p0_hash] = nil
59 elseif sound.name ~= wanted_sound.name then
60 minetest.sound_stop(sound.handle)
61 fire.sounds[p0_hash] = {
62 handle = minetest.sound_play(wanted_sound, {pos=cp, loop=true}),
63 name = wanted_sound.name,
69 function fire.on_flame_add_at(pos)
70 --print("flame added at "..minetest.pos_to_string(pos))
71 fire.update_sounds_around(pos)
74 function fire.on_flame_remove_at(pos)
75 --print("flame removed at "..minetest.pos_to_string(pos))
76 fire.update_sounds_around(pos)
79 function fire.find_pos_for_flame_around(pos)
80 return minetest.env:find_node_near(pos, 1, {"air"})
83 function fire.flame_should_extinguish(pos)
84 --return minetest.env:find_node_near(pos, 1, {"group:puts_out_fire"})
85 local p0 = {x=pos.x-2, y=pos.y, z=pos.z-2}
86 local p1 = {x=pos.x+2, y=pos.y, z=pos.z+2}
87 local ps = minetest.env:find_nodes_in_area(p0, p1, {"group:puts_out_fire"})
91 minetest.register_on_placenode(function(pos, newnode, placer)
92 if newnode.name == "fire:basic_flame" then
93 fire.on_flame_add_at(pos)
97 minetest.register_on_dignode(function(pos, oldnode, digger)
98 if oldnode.name == "fire:basic_flame" then
99 fire.on_flame_remove_at(pos)
103 -- Ignite neighboring nodes
104 minetest.register_abm({
105 nodenames = {"group:flammable"},
106 neighbors = {"group:igniter"},
109 action = function(p0, node, _, _)
110 -- If there is water or stuff like that around flame, don't ignite
111 if fire.flame_should_extinguish(p0) then
114 local p = fire.find_pos_for_flame_around(p0)
116 minetest.env:set_node(p, {name="fire:basic_flame"})
117 fire.on_flame_add_at(p)
122 -- Rarely ignite things from far
123 minetest.register_abm({
124 nodenames = {"group:igniter"},
128 action = function(p0, node, _, _)
129 local reg = minetest.registered_nodes[node.name]
130 if not reg or not reg.groups.igniter or reg.groups.igniter < 2 then
133 local d = reg.groups.igniter
134 local p = minetest.env:find_node_near(p0, d, {"group:flammable"})
136 -- If there is water or stuff like that around flame, don't ignite
137 if fire.flame_should_extinguish(p) then
140 local p2 = fire.find_pos_for_flame_around(p)
142 minetest.env:set_node(p2, {name="fire:basic_flame"})
143 fire.on_flame_add_at(p2)
149 -- Remove flammable nodes and flame
150 minetest.register_abm({
151 nodenames = {"fire:basic_flame"},
154 action = function(p0, node, _, _)
155 -- If there is water or stuff like that around flame, remove flame
156 if fire.flame_should_extinguish(p0) then
157 minetest.env:remove_node(p0)
158 fire.on_flame_remove_at(p0)
161 -- Make the following things rarer
162 if math.random(1,3) == 1 then
165 -- If there are no flammable nodes around flame, remove flame
166 if not minetest.env:find_node_near(p0, 1, {"group:flammable"}) then
167 minetest.env:remove_node(p0)
168 fire.on_flame_remove_at(p0)
171 if math.random(1,4) == 1 then
172 -- remove a flammable node around flame
173 local p = minetest.env:find_node_near(p0, 1, {"group:flammable"})
175 -- If there is water or stuff like that around flame, don't remove
176 if fire.flame_should_extinguish(p0) then
179 minetest.env:remove_node(p)
183 minetest.env:remove_node(p0)
184 fire.on_flame_remove_at(p0)