forked from VoxeLibre/VoxeLibre
Import Minetest Game 0.4.15 code for: fire
- Fire spread is much slower now - Higher code quality in general
This commit is contained in:
parent
aabb5a8d41
commit
13ec1ce743
|
@ -19,8 +19,13 @@ http://creativecommons.org/licenses/by-sa/3.0/
|
||||||
|
|
||||||
Authors of media files
|
Authors of media files
|
||||||
-----------------------
|
-----------------------
|
||||||
fire_small.ogg sampled from:
|
Muadtralk (CC BY-SA 3.0)
|
||||||
http://www.freesound.org/people/dobroide/sounds/4211/
|
fire_basic_flame_animated.png
|
||||||
|
|
||||||
fire_large.ogg sampled from:
|
Dynamicell (CC BY 3.0)
|
||||||
http://www.freesound.org/people/Dynamicell/sounds/17548/
|
http://www.freesound.org/people/Dynamicell/sounds/17548/
|
||||||
|
fire_fire.*.ogg
|
||||||
|
|
||||||
|
Benboncan (CC BY 3.0)
|
||||||
|
https://www.freesound.org/people/Benboncan/sounds/66457/
|
||||||
|
fire_flint_and_steel.ogg
|
||||||
|
|
|
@ -1,237 +1,305 @@
|
||||||
local init = os.clock()
|
-- Global namespace for functions
|
||||||
minetest.register_node("mcl_fire:basic_flame", {
|
|
||||||
description = "Fire",
|
|
||||||
drawtype = "firelike",
|
|
||||||
tiles = {{
|
|
||||||
name="fire_basic_flame_animated.png",
|
|
||||||
animation={type="vertical_frames", aspect_w=32, aspect_h=32, length=1},
|
|
||||||
}},
|
|
||||||
inventory_image = "fire_basic_flame.png",
|
|
||||||
-- Real light level: 15 (but Minetest caps at 14)
|
|
||||||
light_source = 14,
|
|
||||||
groups = {igniter=2,dig_immediate=3,dig_by_water=1,not_in_creative_inventory=1},
|
|
||||||
drop = '',
|
|
||||||
walkable = false,
|
|
||||||
buildable_to = true,
|
|
||||||
damage_per_second = 4,
|
|
||||||
|
|
||||||
after_place_node = function(pos, placer)
|
|
||||||
mcl_fire.on_flame_add_at(pos)
|
|
||||||
end,
|
|
||||||
|
|
||||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
|
||||||
mcl_fire.on_flame_remove_at(pos)
|
|
||||||
end,
|
|
||||||
})
|
|
||||||
|
|
||||||
mcl_fire = {}
|
mcl_fire = {}
|
||||||
mcl_fire.D = 6
|
|
||||||
-- key: position hash of low corner of area
|
|
||||||
-- value: {handle=sound handle, name=sound name}
|
|
||||||
mcl_fire.sounds = {}
|
|
||||||
|
|
||||||
function mcl_fire.get_area_p0p1(pos)
|
|
||||||
local p0 = {
|
--
|
||||||
x=math.floor(pos.x/mcl_fire.D)*mcl_fire.D,
|
-- Items
|
||||||
y=math.floor(pos.y/mcl_fire.D)*mcl_fire.D,
|
--
|
||||||
z=math.floor(pos.z/mcl_fire.D)*mcl_fire.D,
|
|
||||||
}
|
-- Flame nodes
|
||||||
local p1 = {
|
|
||||||
x=p0.x+mcl_fire.D-1,
|
minetest.register_node("mcl_fire:fire", {
|
||||||
y=p0.y+mcl_fire.D-1,
|
description = "Fire",
|
||||||
z=p0.z+mcl_fire.D-1
|
drawtype = "firelike",
|
||||||
}
|
tiles = {
|
||||||
return p0, p1
|
{
|
||||||
|
name = "fire_basic_flame_animated.png",
|
||||||
|
animation = {
|
||||||
|
type = "vertical_frames",
|
||||||
|
aspect_w = 16,
|
||||||
|
aspect_h = 16,
|
||||||
|
length = 1
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
inventory_image = "fire_basic_flame.png",
|
||||||
|
paramtype = "light",
|
||||||
|
-- Real light level: 15 (but Minetest caps at 14)
|
||||||
|
light_source = 14,
|
||||||
|
walkable = false,
|
||||||
|
buildable_to = true,
|
||||||
|
sunlight_propagates = true,
|
||||||
|
damage_per_second = 1,
|
||||||
|
groups = {igniter = 1, dig_immediate = 3, not_in_creative_inventory = 1},
|
||||||
|
on_timer = function(pos)
|
||||||
|
local f = minetest.find_node_near(pos, 1, {"group:flammable"})
|
||||||
|
if not f then
|
||||||
|
minetest.remove_node(pos)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
-- Restart timer
|
||||||
|
return true
|
||||||
|
end,
|
||||||
|
drop = "",
|
||||||
|
|
||||||
|
on_construct = function(pos)
|
||||||
|
minetest.get_node_timer(pos):start(math.random(30, 60))
|
||||||
|
end,
|
||||||
|
|
||||||
|
on_blast = function() -- Unaffected by explosions
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_node("mcl_fire:eternal_fire", {
|
||||||
|
description = "Eternal Fire",
|
||||||
|
drawtype = "firelike",
|
||||||
|
tiles = {
|
||||||
|
{
|
||||||
|
name = "fire_basic_flame_animated.png",
|
||||||
|
animation = {
|
||||||
|
type = "vertical_frames",
|
||||||
|
aspect_w = 16,
|
||||||
|
aspect_h = 16,
|
||||||
|
length = 1
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
inventory_image = "fire_basic_flame.png",
|
||||||
|
paramtype = "light",
|
||||||
|
-- Real light level: 15 (but Minetest caps at 14)
|
||||||
|
light_source = 14,
|
||||||
|
walkable = false,
|
||||||
|
buildable_to = true,
|
||||||
|
sunlight_propagates = true,
|
||||||
|
damage_per_second = 1,
|
||||||
|
groups = {igniter = 1, dig_immediate = 3, not_in_creative_inventory = 1},
|
||||||
|
drop = "",
|
||||||
|
|
||||||
|
on_blast = function() -- Unaffected by explosions
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Sound
|
||||||
|
--
|
||||||
|
|
||||||
|
local flame_sound = minetest.setting_getbool("flame_sound")
|
||||||
|
if flame_sound == nil then
|
||||||
|
-- Enable if no setting present
|
||||||
|
flame_sound = true
|
||||||
end
|
end
|
||||||
|
|
||||||
function mcl_fire.update_sounds_around(pos)
|
if flame_sound then
|
||||||
local p0, p1 = mcl_fire.get_area_p0p1(pos)
|
|
||||||
local cp = {x=(p0.x+p1.x)/2, y=(p0.y+p1.y)/2, z=(p0.z+p1.z)/2}
|
local handles = {}
|
||||||
local flames_p = minetest.find_nodes_in_area(p0, p1, {"mcl_fire:basic_flame"})
|
local timer = 0
|
||||||
--print("number of flames at "..minetest.pos_to_string(p0).."/"
|
|
||||||
-- ..minetest.pos_to_string(p1)..": "..#flames_p)
|
-- Parameters
|
||||||
local should_have_sound = (#flames_p > 0)
|
|
||||||
local wanted_sound = nil
|
local radius = 8 -- Flame node search radius around player
|
||||||
if #flames_p >= 9 then
|
local cycle = 3 -- Cycle time for sound updates
|
||||||
wanted_sound = {name="fire_large", gain=1.5}
|
|
||||||
elseif #flames_p > 0 then
|
-- Update sound for player
|
||||||
wanted_sound = {name="fire_small", gain=1.5}
|
|
||||||
|
function mcl_fire.update_player_sound(player)
|
||||||
|
local player_name = player:get_player_name()
|
||||||
|
-- Search for flame nodes in radius around player
|
||||||
|
local ppos = player:getpos()
|
||||||
|
local areamin = vector.subtract(ppos, radius)
|
||||||
|
local areamax = vector.add(ppos, radius)
|
||||||
|
local fpos, num = minetest.find_nodes_in_area(
|
||||||
|
areamin,
|
||||||
|
areamax,
|
||||||
|
{"mcl_fire:fire", "mcl_fire:eternal_fire"}
|
||||||
|
)
|
||||||
|
-- Total number of flames in radius
|
||||||
|
local flames = (num["mcl_fire:fire"] or 0) +
|
||||||
|
(num["mcl_fire:eternal_fire"] or 0)
|
||||||
|
-- Stop previous sound
|
||||||
|
if handles[player_name] then
|
||||||
|
minetest.sound_stop(handles[player_name])
|
||||||
|
handles[player_name] = nil
|
||||||
end
|
end
|
||||||
local p0_hash = minetest.hash_node_position(p0)
|
-- If flames
|
||||||
local sound = mcl_fire.sounds[p0_hash]
|
if flames > 0 then
|
||||||
if not sound then
|
-- Find centre of flame positions
|
||||||
if should_have_sound then
|
local fposmid = fpos[1]
|
||||||
mcl_fire.sounds[p0_hash] = {
|
-- If more than 1 flame
|
||||||
handle = minetest.sound_play(wanted_sound, {pos=cp, loop=true}),
|
if #fpos > 1 then
|
||||||
name = wanted_sound.name,
|
local fposmin = areamax
|
||||||
}
|
local fposmax = areamin
|
||||||
|
for i = 1, #fpos do
|
||||||
|
local fposi = fpos[i]
|
||||||
|
if fposi.x > fposmax.x then
|
||||||
|
fposmax.x = fposi.x
|
||||||
end
|
end
|
||||||
else
|
if fposi.y > fposmax.y then
|
||||||
if not wanted_sound then
|
fposmax.y = fposi.y
|
||||||
minetest.sound_stop(sound.handle)
|
end
|
||||||
mcl_fire.sounds[p0_hash] = nil
|
if fposi.z > fposmax.z then
|
||||||
elseif sound.name ~= wanted_sound.name then
|
fposmax.z = fposi.z
|
||||||
minetest.sound_stop(sound.handle)
|
end
|
||||||
mcl_fire.sounds[p0_hash] = {
|
if fposi.x < fposmin.x then
|
||||||
handle = minetest.sound_play(wanted_sound, {pos=cp, loop=true}),
|
fposmin.x = fposi.x
|
||||||
name = wanted_sound.name,
|
end
|
||||||
}
|
if fposi.y < fposmin.y then
|
||||||
|
fposmin.y = fposi.y
|
||||||
|
end
|
||||||
|
if fposi.z < fposmin.z then
|
||||||
|
fposmin.z = fposi.z
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
fposmid = vector.divide(vector.add(fposmin, fposmax), 2)
|
||||||
|
end
|
||||||
|
-- Play sound
|
||||||
|
local handle = minetest.sound_play(
|
||||||
|
"fire_fire",
|
||||||
|
{
|
||||||
|
pos = fposmid,
|
||||||
|
to_player = player_name,
|
||||||
|
gain = math.min(0.06 * (1 + flames * 0.125), 0.18),
|
||||||
|
max_hear_distance = 32,
|
||||||
|
loop = true, -- In case of lag
|
||||||
|
}
|
||||||
|
)
|
||||||
|
-- Store sound handle for this player
|
||||||
|
if handle then
|
||||||
|
handles[player_name] = handle
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Cycle for updating players sounds
|
||||||
|
|
||||||
|
minetest.register_globalstep(function(dtime)
|
||||||
|
timer = timer + dtime
|
||||||
|
if timer < cycle then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
timer = 0
|
||||||
|
local players = minetest.get_connected_players()
|
||||||
|
for n = 1, #players do
|
||||||
|
mcl_fire.update_player_sound(players[n])
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- Stop sound and clear handle on player leave
|
||||||
|
|
||||||
|
minetest.register_on_leaveplayer(function(player)
|
||||||
|
local player_name = player:get_player_name()
|
||||||
|
if handles[player_name] then
|
||||||
|
minetest.sound_stop(handles[player_name])
|
||||||
|
handles[player_name] = nil
|
||||||
|
end
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
function mcl_fire.on_flame_add_at(pos)
|
|
||||||
--print("flame added at "..minetest.pos_to_string(pos))
|
|
||||||
mcl_fire.update_sounds_around(pos)
|
|
||||||
end
|
|
||||||
|
|
||||||
function mcl_fire.on_flame_remove_at(pos)
|
--
|
||||||
--print("flame removed at "..minetest.pos_to_string(pos))
|
-- ABMs
|
||||||
mcl_fire.update_sounds_around(pos)
|
--
|
||||||
end
|
|
||||||
|
|
||||||
function mcl_fire.find_pos_for_flame_around(pos)
|
-- Extinguish all flames quickly with water, snow, ice
|
||||||
return minetest.find_node_near(pos, 1, {"air"})
|
|
||||||
end
|
|
||||||
|
|
||||||
function mcl_fire.flame_should_extinguish(pos)
|
|
||||||
if minetest.setting_getbool("disable_fire") then return true end
|
|
||||||
--return minetest.find_node_near(pos, 1, {"group:puts_out_fire"})
|
|
||||||
local p0 = {x=pos.x-2, y=pos.y, z=pos.z-2}
|
|
||||||
local p1 = {x=pos.x+2, y=pos.y, z=pos.z+2}
|
|
||||||
local ps = minetest.find_nodes_in_area(p0, p1, {"group:puts_out_fire"})
|
|
||||||
return (#ps ~= 0)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Ignite neighboring nodes
|
|
||||||
minetest.register_abm({
|
minetest.register_abm({
|
||||||
|
label = "Extinguish flame",
|
||||||
|
nodenames = {"mcl_fire:fire", "mcl_fire:eternal_fire"},
|
||||||
|
neighbors = {"group:puts_out_fire"},
|
||||||
|
interval = 3,
|
||||||
|
chance = 1,
|
||||||
|
catch_up = false,
|
||||||
|
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||||
|
minetest.remove_node(pos)
|
||||||
|
minetest.sound_play("fire_extinguish_flame",
|
||||||
|
{pos = pos, max_hear_distance = 16, gain = 0.15})
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
-- Enable the following ABMs according to 'enable fire' setting
|
||||||
|
|
||||||
|
local fire_enabled = minetest.setting_getbool("enable_fire")
|
||||||
|
if fire_enabled == nil then
|
||||||
|
-- New setting not specified, check for old setting.
|
||||||
|
-- If old setting is also not specified, 'not nil' is true.
|
||||||
|
fire_enabled = not minetest.setting_getbool("disable_fire")
|
||||||
|
end
|
||||||
|
|
||||||
|
if not fire_enabled then
|
||||||
|
|
||||||
|
-- Remove basic flames only if fire disabled
|
||||||
|
|
||||||
|
minetest.register_abm({
|
||||||
|
label = "Remove disabled fire",
|
||||||
|
nodenames = {"fire:basic_flame"},
|
||||||
|
interval = 7,
|
||||||
|
chance = 1,
|
||||||
|
catch_up = false,
|
||||||
|
action = minetest.remove_node,
|
||||||
|
})
|
||||||
|
|
||||||
|
else -- Fire enabled
|
||||||
|
|
||||||
|
-- Ignite neighboring nodes, add basic flames
|
||||||
|
|
||||||
|
minetest.register_abm({
|
||||||
|
label = "Ignite flame",
|
||||||
nodenames = {"group:flammable"},
|
nodenames = {"group:flammable"},
|
||||||
neighbors = {"group:igniter"},
|
neighbors = {"group:igniter"},
|
||||||
interval = 1,
|
interval = 7,
|
||||||
chance = 2,
|
chance = 12,
|
||||||
action = function(p0, node, _, _)
|
catch_up = false,
|
||||||
-- If there is water or stuff like that around flame, don't ignite
|
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||||
if mcl_fire.flame_should_extinguish(p0) then
|
-- If there is water or stuff like that around node, don't ignite
|
||||||
|
if minetest.find_node_near(pos, 1, {"group:puts_out_fire"}) then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local p = mcl_fire.find_pos_for_flame_around(p0)
|
local p = minetest.find_node_near(pos, 1, {"air"})
|
||||||
if p then
|
if p then
|
||||||
minetest.set_node(p, {name="mcl_fire:basic_flame"})
|
minetest.set_node(p, {name = "mcl_fire:fire"})
|
||||||
mcl_fire.on_flame_add_at(p)
|
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
-- Rarely ignite things from far
|
-- Remove flammable nodes around fire
|
||||||
minetest.register_abm({
|
|
||||||
nodenames = {"group:igniter"},
|
minetest.register_abm({
|
||||||
neighbors = {"air"},
|
label = "Remove flammable nodes",
|
||||||
interval = 2,
|
nodenames = {"mcl_fire:fire"},
|
||||||
chance = 10,
|
neighbors = "group:flammable",
|
||||||
action = function(p0, node, _, _)
|
interval = 5,
|
||||||
local reg = minetest.registered_nodes[node.name]
|
chance = 18,
|
||||||
if not reg or not reg.groups.igniter or reg.groups.igniter < 2 then
|
catch_up = false,
|
||||||
return
|
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||||
end
|
local p = minetest.find_node_near(pos, 1, {"group:flammable"})
|
||||||
local d = reg.groups.igniter
|
|
||||||
local p = minetest.find_node_near(p0, d, {"group:flammable"})
|
|
||||||
if p then
|
if p then
|
||||||
-- If there is water or stuff like that around flame, don't ignite
|
local flammable_node = minetest.get_node(p)
|
||||||
if mcl_fire.flame_should_extinguish(p) then
|
local def = minetest.registered_nodes[flammable_node.name]
|
||||||
return
|
if def.on_burn then
|
||||||
end
|
def.on_burn(p)
|
||||||
local p2 = mcl_fire.find_pos_for_flame_around(p)
|
|
||||||
if p2 then
|
|
||||||
minetest.set_node(p2, {name="mcl_fire:basic_flame"})
|
|
||||||
mcl_fire.on_flame_add_at(p2)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
})
|
|
||||||
|
|
||||||
-- Remove flammable nodes and flame
|
|
||||||
minetest.register_abm({
|
|
||||||
nodenames = {"mcl_fire:basic_flame"},
|
|
||||||
interval = 1,
|
|
||||||
chance = 2,
|
|
||||||
action = function(p0, node, _, _)
|
|
||||||
-- If there is water or stuff like that around flame, remove flame
|
|
||||||
|
|
||||||
if mcl_fire.flame_should_extinguish(p0) then
|
|
||||||
minetest.remove_node(p0)
|
|
||||||
mcl_fire.on_flame_remove_at(p0)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
-- Make the following things rarer
|
|
||||||
if math.random(1,3) == 1 then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
-- If there are no flammable nodes around flame, remove flame
|
|
||||||
if not minetest.find_node_near(p0, 1, {"group:flammable"}) then
|
|
||||||
minetest.remove_node(p0)
|
|
||||||
mcl_fire.on_flame_remove_at(p0)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if math.random(1,3) == 1 then
|
|
||||||
-- remove a flammable node around flame
|
|
||||||
local p = minetest.find_node_near(p0, 1, {"group:flammable"})
|
|
||||||
if p then
|
|
||||||
-- If there is water or stuff like that around flame, don't remove
|
|
||||||
if mcl_fire.flame_should_extinguish(p0) then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
minetest.remove_node(p)
|
|
||||||
core.check_for_falling(p)
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
-- remove flame
|
minetest.remove_node(p)
|
||||||
minetest.remove_node(p0)
|
minetest.check_for_falling(p)
|
||||||
mcl_fire.on_flame_remove_at(p0)
|
end
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
--
|
end
|
||||||
-- Flint and Steel
|
|
||||||
--
|
|
||||||
|
|
||||||
function mcl_fire.set_fire(pointed_thing)
|
-- Set pointed_thing on fire
|
||||||
|
mcl_fire.set_fire = function(pointed_thing)
|
||||||
local n = minetest.get_node(pointed_thing.above)
|
local n = minetest.get_node(pointed_thing.above)
|
||||||
if n.name ~= "" and n.name == "air" and not minetest.is_protected(pointed_thing.above, "fire") then
|
if n.name ~= "" and n.name == "air" and not minetest.is_protected(pointed_thing.above, "fire") then
|
||||||
minetest.add_node(pointed_thing.above, {name="mcl_fire:basic_flame"})
|
minetest.add_node(pointed_thing.above, {name="mcl_fire:fire"})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--
|
minetest.register_alias("mcl_fire:basic_flame", "mcl_fire:fire")
|
||||||
-- Fire Particles
|
minetest.register_alias("fire:basic_flame", "mcl_fire:fire")
|
||||||
--
|
minetest.register_alias("fire:permanent_flame", "mcl_fire:eternal_flame")
|
||||||
|
|
||||||
function mcl_fire.add_fire(pos)
|
|
||||||
local null = {x=0, y=0, z=0}
|
|
||||||
pos.y = pos.y+0.19
|
|
||||||
minetest.add_particle({
|
|
||||||
pos = pos,
|
|
||||||
velocity = null,
|
|
||||||
acceleration = null,
|
|
||||||
expirationtime = 1.1,
|
|
||||||
size = 1.5,
|
|
||||||
collisiondetection = true,
|
|
||||||
texture = "default_fire_particle"..tostring(math.random(1,2)) ..".png"
|
|
||||||
})
|
|
||||||
pos.y = pos.y +0.01
|
|
||||||
minetest.add_particle({
|
|
||||||
pos = pos,
|
|
||||||
velocity = null,
|
|
||||||
acceleration = null,
|
|
||||||
expirationtime = 0.8,
|
|
||||||
size = 1.5,
|
|
||||||
collisiondetection = true,
|
|
||||||
texture = "default_fire_particle"..tostring(math.random(1,2)) ..".png"
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
dofile(minetest.get_modpath(minetest.get_current_modname()).."/flint_and_steel.lua")
|
dofile(minetest.get_modpath(minetest.get_current_modname()).."/flint_and_steel.lua")
|
||||||
dofile(minetest.get_modpath(minetest.get_current_modname()).."/fire_charge.lua")
|
dofile(minetest.get_modpath(minetest.get_current_modname()).."/fire_charge.lua")
|
||||||
|
|
||||||
local time_to_load= os.clock() - init
|
|
||||||
print(string.format("[MOD] "..minetest.get_current_modname().." loaded in %.4f s", time_to_load))
|
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue