Compare commits

...

4 Commits

2 changed files with 116 additions and 32 deletions

View File

@ -1239,6 +1239,10 @@ end
local function vinedecay_particles(pos, node) local function vinedecay_particles(pos, node)
local dir = minetest.wallmounted_to_dir(node.param2) local dir = minetest.wallmounted_to_dir(node.param2)
-- Don't crash if the map data got corrupted somehow
if not dir then return end
local relpos1, relpos2 local relpos1, relpos2
if dir.x < 0 then if dir.x < 0 then
relpos1 = { x = -0.45, y = -0.4, z = -0.5 } relpos1 = { x = -0.45, y = -0.4, z = -0.5 }
@ -1475,6 +1479,10 @@ Vines are considered “supported” if they face a walkable+solid block or “h
function mcl_core.check_vines_supported(pos, node) function mcl_core.check_vines_supported(pos, node)
local supported = false local supported = false
local dir = minetest.wallmounted_to_dir(node.param2) local dir = minetest.wallmounted_to_dir(node.param2)
-- Don't crash if the map data got corrupted somehow
if not dir then return false end
local pos1 = vector.add(pos, dir) local pos1 = vector.add(pos, dir)
local node_neighbor = minetest.get_node(pos1) local node_neighbor = minetest.get_node(pos1)
-- Check if vines are attached to a solid block. -- Check if vines are attached to a solid block.

View File

@ -44,12 +44,34 @@ shuffle_table(adjacents)
local function has_flammable(pos) local function has_flammable(pos)
for k,v in pairs(adjacents) do for k,v in pairs(adjacents) do
local p=vector.add(pos,v) local p=vector.add(pos,v)
local n=minetest.get_node_or_nil(p) local n=get_node_or_nil(p)
if n and minetest.get_item_group(n.name, "flammable") ~= 0 then if n and get_item_group(n.name, "flammable") ~= 0 then
return p return p
end end
end end
end end
local all_adjacents = {}
for x = 0,1 do
for y = 0,1 do
for z = 0,1 do
all_adjacents[#all_adjacents+1] = vector.new(x*2-1, y*2-1, z*2-1)
end
end
end
local function get_adjacent_fire_age(pos)
local lowest_age = nil
for k,v in pairs(all_adjacents) do
local p = vector.add(pos, v)
local node = get_node_or_nil(p)
if node and get_item_group(node.name, "fire") ~= 0 then
if not lowest_age or node.param2 < lowest_age then
lowest_age = node.param2
end
end
end
return lowest_age
end
local smoke_pdef = { local smoke_pdef = {
amount = 0.009, amount = 0.009,
@ -90,7 +112,40 @@ else
eternal_fire_help = S("Eternal fire is a damaging block. Eternal fire can be extinguished by punches and nearby water blocks. Other than (normal) fire, eternal fire does not get extinguished on its own and also continues to burn under rain. Punching eternal fire is safe, but it hurts if you stand inside.") eternal_fire_help = S("Eternal fire is a damaging block. Eternal fire can be extinguished by punches and nearby water blocks. Other than (normal) fire, eternal fire does not get extinguished on its own and also continues to burn under rain. Punching eternal fire is safe, but it hurts if you stand inside.")
end end
local function spawn_fire(pos, age) -- exponential constant is such that at age=255, p=0.5%
local K1 = ( math.log(0.005) / math.log(10) ) / 255
local function spawn_fire(pos, age, force)
if not age then
minetest.log("warning","No age specified at "..debug.traceback())
-- Get adjacent age
local adjacent_age = get_adjacent_fire_age(pos)
-- Don't create new fire if we can't find adjacent fire from this position
if not adjacent_age then return end
age = adjacent_age + math.ceil(minetest.get_humidity(pos)/10) + math.random(5)
end
if age <= 1 then
minetest.log("warning","new flash point at "..vector.to_string(pos).." age="..tostring(age)..",backtrace = "..debug.traceback())
end
if age >= 255 then
age = 255
end
local node = get_node(pos)
local node_is_flammable = get_item_group(node.name, "flammable")
-- Limit fire spread
local probability_age = age
if node_is_flammable then
probability_age = probability_age * 0.80
end
local probability = math.pow(10,K1 * probability_age)
if not force and math.random(65536)/65536 >= probability then
return
end
set_node(pos, {name="mcl_fire:fire", param2 = age}) set_node(pos, {name="mcl_fire:fire", param2 = age})
minetest.check_single_for_falling({x=pos.x, y=pos.y+1, z=pos.z}) minetest.check_single_for_falling({x=pos.x, y=pos.y+1, z=pos.z})
end end
@ -358,19 +413,47 @@ if not fire_enabled then
else -- Fire enabled else -- Fire enabled
-- Extinguish parameters
local C2 = math.log(1/20) / math.log(10)
local K2 = -C2 / 255
-- Fire Spread -- Fire Spread
minetest.register_abm({ minetest.register_abm({
label = "Ignite flame", label = "Ignite flame",
nodenames ={"mcl_fire:fire","mcl_fire:eternal_fire"}, nodenames ={"mcl_fire:fire","mcl_fire:eternal_fire"},
interval = 7, interval = 7,
chance = 12, chance = 5,
catch_up = false, catch_up = false,
action = function(pos) action = function(pos)
local node = get_node(pos)
local age = node.param2
-- Always age the source fire
age = age + math.ceil(minetest.get_humidity(pos)/10) + math.random(5)
if age > 255 then age = 255 end
node.param2 = age
local p = get_ignitable(pos) local p = get_ignitable(pos)
if p then if p then
spawn_fire(p) -- Spawn new fire with an age based on this node's age
spawn_fire(p, age + math.ceil(minetest.get_humidity(p)/10) + math.random(5))
shuffle_table(adjacents) shuffle_table(adjacents)
end end
if node.name ~= "mcl_fire:eternal_fire" then
-- Randomly extinguish fires with increasing probability the older they are
local extinguish_probability = math.pow(10,K2 * age + C2)
if math.random(65536)/65536 <= extinguish_probability then
node.name = "air"
node.param2 = 0
-- Extinguish fires not adjacent to flammable materials
elseif not has_flammable(pos) then
node.name = "air"
node.param2 = 0
end
end
set_node(pos, node)
end end
}) })
@ -385,26 +468,7 @@ else -- Fire enabled
action = function(pos) action = function(pos)
local p=get_ignitable_by_lava(pos) local p=get_ignitable_by_lava(pos)
if p then if p then
spawn_fire(p) spawn_fire(p, 0)
end
end,
})
minetest.register_abm({
label = "Remove fires",
nodenames = {"mcl_fire:fire"},
interval = 7,
chance = 3,
catch_up = false,
action = function(pos)
local p=has_flammable(pos)
if p then
local n=minetest.get_node_or_nil(p)
if n and minetest.get_item_group(n.name, "flammable") < 1 then
minetest.remove_node(pos)
end
else
minetest.remove_node(pos)
end end
end, end,
}) })
@ -423,15 +487,27 @@ else -- Fire enabled
return return
end end
local nn = minetest.get_node(p).name local node = get_node(p)
local def = minetest.registered_nodes[nn] local node_name = node.name
local fgroup = minetest.get_item_group(nn, "flammable") local def = minetest.registered_nodes[node_name]
local fgroup = minetest.get_item_group(node_name, "flammable")
if def and def._on_burn then if def and def._on_burn then
def._on_burn(p) def._on_burn(p)
elseif fgroup ~= -1 then elseif fgroup ~= -1 then
spawn_fire(p) local source_node = get_node(pos)
local age = source_node.param2
spawn_fire(p, age + math.ceil(minetest.get_humidity(p)/10) + math.random(5), true)
minetest.check_for_falling(p) minetest.check_for_falling(p)
if source_node.name == "mcl_fire:fire" then
-- Always age the source fire
age = age + math.ceil(minetest.get_humidity(pos)/10) + math.random(5)
if age > 255 then age = 255 end
source_node.param2 = age
set_node(pos, source_node)
end
end end
end end
}) })
@ -454,17 +530,17 @@ function mcl_fire.set_fire(pointed_thing, player, allow_on_fire)
return return
end end
local n_pointed = minetest.get_node(pointed_thing.under) local n_pointed = get_node(pointed_thing.under)
if allow_on_fire == false and get_item_group(n_pointed.name, "fire") ~= 0 then if allow_on_fire == false and get_item_group(n_pointed.name, "fire") ~= 0 then
return return
end end
local n_fire_pos = minetest.get_node(pointed_thing.above) local n_fire_pos = get_node(pointed_thing.above)
if n_fire_pos.name ~= "air" then if n_fire_pos.name ~= "air" then
return return
end end
local n_below = minetest.get_node(vector.offset(pointed_thing.above, 0, -1, 0)) local n_below = get_node(vector.offset(pointed_thing.above, 0, -1, 0))
if minetest.get_item_group(n_below.name, "water") ~= 0 then if minetest.get_item_group(n_below.name, "water") ~= 0 then
return return
end end