forked from VoxeLibre/VoxeLibre
131 lines
4.2 KiB
Lua
131 lines
4.2 KiB
Lua
local vector = vector
|
|
local table = table
|
|
|
|
local hash_node_position = minetest.hash_node_position
|
|
local add_particlespawner = minetest.add_particlespawner
|
|
local delete_particlespawner = minetest.delete_particlespawner
|
|
|
|
local ipairs = ipairs
|
|
|
|
mcl_particles = {}
|
|
|
|
-- Table of particlespawner IDs on a per-node hash basis
|
|
-- Keys: node position hashes
|
|
-- Values: Tables of particlespawner IDs (each node pos can have an arbitrary number of particlespawners)
|
|
local particle_nodes = {}
|
|
|
|
-- Node particles can be disabled via setting
|
|
local node_particles_allowed = minetest.settings:get("mcl_node_particles") or "none"
|
|
|
|
local levels = {
|
|
high = 3,
|
|
medium = 2,
|
|
low = 1,
|
|
none = 0,
|
|
}
|
|
|
|
allowed_level = levels[node_particles_allowed]
|
|
if not allowed_level then
|
|
allowed_level = levels["none"]
|
|
end
|
|
|
|
|
|
-- Add a particlespawner that is assigned to a given node position.
|
|
-- * pos: Node positon. MUST use integer values!
|
|
-- * particlespawner_definition: definition for minetest.add_particlespawner
|
|
-- * level: detail level of particles. "high", "medium", "low" or "none". High detail levels are for
|
|
-- CPU-demanding particles, like smoke of fire (which occurs frequently)
|
|
-- NOTE: All particlespawners are automatically removed on shutdown.
|
|
-- Returns particlespawner ID on succcess and nil on failure
|
|
function mcl_particles.add_node_particlespawner(pos, particlespawner_definition, level)
|
|
if allowed_level == 0 or levels[level] > allowed_level then
|
|
return
|
|
end
|
|
local poshash = hash_node_position(pos)
|
|
if not poshash then
|
|
return
|
|
end
|
|
local id = add_particlespawner(particlespawner_definition)
|
|
if id == -1 then
|
|
return
|
|
end
|
|
if not particle_nodes[poshash] then
|
|
particle_nodes[poshash] = {}
|
|
end
|
|
table.insert(particle_nodes[poshash], id)
|
|
return id
|
|
end
|
|
|
|
local add_node_particlespawner = mcl_particles.add_node_particlespawner
|
|
|
|
-- Deletes all particlespawners that are assigned to a node position.
|
|
-- If no particlespawners exist for this position, nothing happens.
|
|
-- pos: Node positon. MUST use integer values!
|
|
-- Returns true if particlespawner could be removed and false if not
|
|
function mcl_particles.delete_node_particlespawners(pos)
|
|
if allowed_level == 0 then
|
|
return false
|
|
end
|
|
local poshash = hash_node_position(pos)
|
|
local ids = particle_nodes[poshash]
|
|
if ids then
|
|
for i=1, #ids do
|
|
delete_particlespawner(ids[i])
|
|
end
|
|
particle_nodes[poshash] = nil
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
|
|
-- 3 exptime variants because the animation is not tied to particle expiration time.
|
|
-- 3 colorized variants to imitate minecraft's
|
|
local smoke_pdef_cached = {}
|
|
|
|
function mcl_particles.spawn_smoke(pos, name, smoke_pdef_base)
|
|
local new_minpos = vector.add(pos, smoke_pdef_base.minrelpos)
|
|
local new_maxpos = vector.add(pos, smoke_pdef_base.maxrelpos)
|
|
|
|
-- populate the cache
|
|
if smoke_pdef_cached[name] then
|
|
for i, smoke_pdef in ipairs(smoke_pdef_cached[name]) do
|
|
smoke_pdef.minpos = new_minpos
|
|
smoke_pdef.maxpos = new_maxpos
|
|
add_node_particlespawner(pos, smoke_pdef, "high")
|
|
end
|
|
-- cache already populated
|
|
else
|
|
smoke_pdef_cached[name] = {}
|
|
|
|
local smoke_pdef = table.copy(smoke_pdef_base)
|
|
smoke_pdef.amount = smoke_pdef_base.amount / 9
|
|
smoke_pdef.time = 0
|
|
smoke_pdef.animation = {
|
|
type = "vertical_frames",
|
|
aspect_w = 8,
|
|
aspect_h = 8,
|
|
-- length = 3 exptime variants
|
|
}
|
|
smoke_pdef.collisiondetection = true
|
|
smoke_pdef.minpos = new_minpos
|
|
smoke_pdef.maxpos = new_maxpos
|
|
|
|
-- the last frame plays for 1/8 * N seconds, so we can take advantage of it
|
|
-- to have varying exptime for each variant.
|
|
local exptimes = { 0.175, 0.375, 1.0 }
|
|
local colorizes = { "199", "209", "243" } -- round(78%, 82%, 90% of 256) - 1
|
|
|
|
for _,exptime in ipairs(exptimes) do
|
|
for _,colorize in ipairs(colorizes) do
|
|
smoke_pdef.maxexptime = exptime * smoke_pdef_base.maxexptime
|
|
smoke_pdef.animation.length = exptime + 0.1
|
|
-- minexptime must be set such that the last frame is actully rendered,
|
|
-- even if its very short. Larger exptime -> larger range
|
|
smoke_pdef.minexptime = math.min(exptime, (7.0/8.0 * (exptime + 0.1) + 0.1))
|
|
smoke_pdef.texture = "mcl_particles_smoke_anim.png^[colorize:#000000:" ..colorize
|
|
add_node_particlespawner(pos, smoke_pdef, "high")
|
|
table.insert(smoke_pdef_cached[name], table.copy(smoke_pdef))
|
|
end
|
|
end
|
|
end
|
|
end |