1 -- minetest/fire/init.lua
3 minetest.register_node("fire:basic_flame", {
5 drawtype = "plantlike",
7 name="fire_basic_flame_animated.png",
8 animation={type="vertical_frames", aspect_w=16, aspect_h=16, length=1},
10 inventory_image = "fire_basic_flame.png",
12 groups = {igniter=2,dig_immediate=3},
16 damage_per_second = 4,
18 after_place_node = function(pos, placer)
19 fire.on_flame_add_at(pos)
22 after_dig_node = function(pos, oldnode, oldmetadata, digger)
23 fire.on_flame_remove_at(pos)
29 -- key: position hash of low corner of area
30 -- value: {handle=sound handle, name=sound name}
33 function fire.get_area_p0p1(pos)
35 x=math.floor(pos.x/fire.D)*fire.D,
36 y=math.floor(pos.y/fire.D)*fire.D,
37 z=math.floor(pos.z/fire.D)*fire.D,
47 function fire.update_sounds_around(pos)
48 local p0, p1 = fire.get_area_p0p1(pos)
49 local cp = {x=(p0.x+p1.x)/2, y=(p0.y+p1.y)/2, z=(p0.z+p1.z)/2}
50 local flames_p = minetest.env:find_nodes_in_area(p0, p1, {"fire:basic_flame"})
51 --print("number of flames at "..minetest.pos_to_string(p0).."/"
52 -- ..minetest.pos_to_string(p1)..": "..#flames_p)
53 local should_have_sound = (#flames_p > 0)
54 local wanted_sound = nil
55 if #flames_p >= 9 then
56 wanted_sound = {name="fire_large", gain=1.5}
57 elseif #flames_p > 0 then
58 wanted_sound = {name="fire_small", gain=1.5}
60 local p0_hash = minetest.hash_node_position(p0)
61 local sound = fire.sounds[p0_hash]
63 if should_have_sound then
64 fire.sounds[p0_hash] = {
65 handle = minetest.sound_play(wanted_sound, {pos=cp, loop=true}),
66 name = wanted_sound.name,
70 if not wanted_sound then
71 minetest.sound_stop(sound.handle)
72 fire.sounds[p0_hash] = nil
73 elseif sound.name ~= wanted_sound.name then
74 minetest.sound_stop(sound.handle)
75 fire.sounds[p0_hash] = {
76 handle = minetest.sound_play(wanted_sound, {pos=cp, loop=true}),
77 name = wanted_sound.name,
83 function fire.on_flame_add_at(pos)
84 --print("flame added at "..minetest.pos_to_string(pos))
85 fire.update_sounds_around(pos)
88 function fire.on_flame_remove_at(pos)
89 --print("flame removed at "..minetest.pos_to_string(pos))
90 fire.update_sounds_around(pos)
93 function fire.find_pos_for_flame_around(pos)
94 return minetest.env:find_node_near(pos, 1, {"air"})
97 function fire.flame_should_extinguish(pos)
98 if minetest.setting_getbool("disable_fire") then return true end
99 --return minetest.env:find_node_near(pos, 1, {"group:puts_out_fire"})
100 local p0 = {x=pos.x-2, y=pos.y, z=pos.z-2}
101 local p1 = {x=pos.x+2, y=pos.y, z=pos.z+2}
102 local ps = minetest.env:find_nodes_in_area(p0, p1, {"group:puts_out_fire"})
106 -- Ignite neighboring nodes
107 minetest.register_abm({
108 nodenames = {"group:flammable"},
109 neighbors = {"group:igniter"},
112 action = function(p0, node, _, _)
113 -- If there is water or stuff like that around flame, don't ignite
114 if fire.flame_should_extinguish(p0) then
117 local p = fire.find_pos_for_flame_around(p0)
119 minetest.env:set_node(p, {name="fire:basic_flame"})
120 fire.on_flame_add_at(p)
125 -- Rarely ignite things from far
126 minetest.register_abm({
127 nodenames = {"group:igniter"},
131 action = function(p0, node, _, _)
132 local reg = minetest.registered_nodes[node.name]
133 if not reg or not reg.groups.igniter or reg.groups.igniter < 2 then
136 local d = reg.groups.igniter
137 local p = minetest.env:find_node_near(p0, d, {"group:flammable"})
139 -- If there is water or stuff like that around flame, don't ignite
140 if fire.flame_should_extinguish(p) then
143 local p2 = fire.find_pos_for_flame_around(p)
145 minetest.env:set_node(p2, {name="fire:basic_flame"})
146 fire.on_flame_add_at(p2)
152 -- Remove flammable nodes and flame
153 minetest.register_abm({
154 nodenames = {"fire:basic_flame"},
157 action = function(p0, node, _, _)
158 -- If there is water or stuff like that around flame, remove flame
159 if fire.flame_should_extinguish(p0) then
160 minetest.env:remove_node(p0)
161 fire.on_flame_remove_at(p0)
164 -- Make the following things rarer
165 if math.random(1,3) == 1 then
168 -- If there are no flammable nodes around flame, remove flame
169 if not minetest.env:find_node_near(p0, 1, {"group:flammable"}) then
170 minetest.env:remove_node(p0)
171 fire.on_flame_remove_at(p0)
174 if math.random(1,4) == 1 then
175 -- remove a flammable node around flame
176 local p = minetest.env:find_node_near(p0, 1, {"group:flammable"})
178 -- If there is water or stuff like that around flame, don't remove
179 if fire.flame_should_extinguish(p0) then
182 minetest.env:remove_node(p)
187 minetest.env:remove_node(p0)
188 fire.on_flame_remove_at(p0)