EinsDreiDreiSieben/mods/effervescence/effervescence_particles/init.lua
2025-05-04 16:01:41 +02:00

512 lines
No EOL
16 KiB
Lua

-- Extract particle graphics from a node texture
local function extract_tile(tiles,color)
if not tiles then
return "blank.png"
end
if not color and tiles.color then
color = tiles.color
end
if type(tiles[1]) == "string" then
return tiles[1], color
elseif type(tiles[1]) == "table" then
return tiles[1].name or tiles[1].image, color
else
return "blank.png"
end
end
local function extract_particles(tiles,color,coords)
tiles, color = extract_tile(tiles,color)
return tiles .. "^[resize:16x16^[sheet:8x8:" .. (coords or (math.random(0,7) .. "," .. math.random(0,7))) .. (color and ("^[multiply:" .. color) or "")
end
-- Get texture blend value
local blend_method = core.features.particle_blend_clip and "clip" or "alpha"
-- Dusty particles (sand, dry grass, etc.)
effervescence.register_environmental_particles({
name = "effervescence:dusty",
check = function(self, pos)
return (pos.y < 0 or pos.y > 6) and core.get_node(pos:offset(0,1,0)).name == "air"
end,
applies_to = function(self, node, def)
local groups = def.groups or {}
local does_apply = (groups.stone and groups.stone > 0) or (groups.sand and groups.sand > 0) or (groups.everness_sand and groups.everness_sand > 0) or node:find("dry_") or node:find("clay") or node:find("gravel") or node:find("litter$") or node:find("podzol")
return does_apply and { "effervescence:floors" }
end,
emit = function(self, pos)
local node = core.get_node(pos)
local ndef = core.registered_nodes[node.name]
return {
amount = math.random(56,64),
time = 5,
pos = {
min = pos:add(vector.new(-6,0.575,-6)),
max = pos:add(vector.new(6,1,6)),
},
minsize = 0.2,
maxsize = 0.275,
minvel = { x = -1, y = -0.02, z = -1 },
maxvel = { x = 1, y = 0.02, z = 1 },
minexptime = 6,
maxexptime = 8,
minacc = {x = -1.5, y = 0, z = -1.5},
maxacc = {x = 1.5, y = 0.05, z = 1.5},
texture = {
name = extract_particles(ndef.tiles,ndef.color),
blend = blend_method,
},
collisiondetection = false,
vertical = false,
}
end,
})
-- Crumbly particles (falling bits of stone, dirt, gravel, etc.)
effervescence.register_environmental_particles({
name = "effervescence:crumbly",
check = function(self, pos)
return core.get_node(pos:offset(0,-1,0)).name == "air"
end,
applies_to = function(self, node, def)
local groups = def.groups or {}
local does_apply = (groups.stone and groups.stone > 0) or (groups.crumbly and groups.crumbly > 0) or (groups.soil and groups.soil > 0) or node:find("gravel") or node:find("ore") or node:find("moss") or node:find(":dirt_")
return does_apply and { "effervescence:ceilings" }
end,
emit = function(self, pos)
local node = core.get_node(pos)
local ndef = core.registered_nodes[node.name]
return {
amount = 6,
time = 0.5,
pos = {
min = pos:add(vector.new(-0.45,-0.75,-0.45)),
max = pos:add(vector.new(0.45,-0.9,0.45)),
},
minvel = {x = 0, y = -5, z = 0},
maxvel = {x = -0.1, y = -7, z = -0.1},
minacc = {x = -0.1, y = -2, z = -0.1},
maxacc = {x = 0.1, y = -3, z = 0.1},
minexptime = 0.25,
maxexptime = 1,
minsize = 0.25,
maxsize = 1.25,
glow = ndef.glow or ndef.light_source,
texture = {
name = extract_particles(ndef.tiles,ndef.color),
blend = blend_method,
},
collisiondetection = false,
vertical = false,
}
end,
})
-- Bustling particles (bit of grasses and mosses lifting off the ground)
effervescence.register_environmental_particles({
name = "effervescence:bustling",
check = function(self, pos)
return core.get_node(pos:offset(0,1,0)).name == "air"
end,
applies_to = function(self, node, def)
local groups = def.groups or {}
local does_apply = node:find("grass") or node:find("moss") or node:find("lichen") or node:find("^ethereal:.+_dirt$") or node:find("litter$") or node:find("mycelium")
return does_apply and { "effervescence:floors" }
end,
emit = function(self, pos)
local node = core.get_node(pos)
local ndef = core.registered_nodes[node.name]
return {
amount = math.random(40,48),
time = 6,
pos = {
min = pos:add(vector.new(-8,0.5,-8)),
max = pos:add(vector.new(8,0.75,8)),
},
minvel = {x = -0.5, y = 0.1, z = -0.5},
maxvel = {x = 0.5, y = 0.175, z = 0.5},
minacc = {x = -0.325, y = 0.325, z = -0.325},
maxacc = {x = 0.325, y = 0.5, z = 0.325},
minexptime = 6,
maxexptime = 12,
minsize = 0.25,
maxsize = 0.375,
glow = ndef.glow or ndef.light_source,
texture = {
name = extract_particles(ndef.tiles,ndef.color),
blend = blend_method,
},
collisiondetection = false,
vertical = false,
}
end,
})
-- Snowy particles (snowflakes gusting up from the ground)
effervescence.register_environmental_particles({
name = "effervescence:snowy",
check = function(self, pos)
return core.get_node(pos:offset(0,1,0)).name == "air"
end,
applies_to = function(self, node, def)
local groups = def.groups or {}
local is_snow = (groups.snowy and groups.snowy > 0) or node:find(":snow") or node:find("_with_snow")
if is_snow then
return { def.drawtype == "nodebox" and "effervescence:rare" or "effervescence:floors" }
else
return nil
end
end,
emit = function(self, pos)
local node = core.get_node(pos)
local ndef = core.registered_nodes[node.name]
return {
amount = math.random(8,40),
time = 2,
pos = {
min = pos:add(vector.new(-3,0,-3)),
max = pos:add(vector.new(3,0.4,3)),
},
minvel = {x = -4, y = 2, z = -4},
maxvel = {x = 4, y = 3, z = 4},
minacc = {x = -1.75, y = 1, z = -1.75},
maxacc = {x = 1.75, y = 1.5, z = 1.75},
minexptime = 3,
maxexptime = 5,
minsize = 0.175,
maxsize = 0.225,
texture = {
name = extract_particles(ndef.tiles,ndef.color),
blend = blend_method,
},
collisiondetection = false,
vertical = false,
}
end,
})
-- Leafy particles (falling leaves and snow on leaves)
local leaves = {
air = true, -- special exception for easier check logic
}
effervescence.register_environmental_particles({
name = "effervescence:leafy",
check = function(self, pos)
local below = core.get_node(pos:offset(0,-1,0)).name
return leaves[below]
end,
applies_to = function(self, node, def)
local groups = def.groups or {}
local is_leaves = groups.leaves and groups.leaves > 0
if is_leaves then
leaves[node] = true
return { "effervescence:few" }
elseif node:find(":snow$") then
return { "effervescence:many" }
else
return nil
end
end,
emit = function(self, pos)
local node = core.get_node(pos)
local ndef = core.registered_nodes[node.name]
return {
amount = math.random(1,2),
time = 3,
pos = {
min = pos:add(vector.new(-0.45,-0.3,-0.45)),
max = pos:add(vector.new(0.45,-0.475,0.45)),
},
minvel = {x = -1, y = -0.75, z = -1},
maxvel = {x = 1, y = -1.5, z = 1},
minacc = {x = -0.75, y = -1, z = -0.75},
maxacc = {x = 0.75, y = -1.5, z = 0.75},
minexptime = 4,
maxexptime = 6,
minsize = 1,
maxsize = 1.5,
glow = ndef.glow or ndef.light_source,
texture = {
name = extract_particles(ndef.tiles,ndef.color),
blend = blend_method,
},
collisiondetection = false,
vertical = false,
}
end,
})
-- Blossoming particles (flower petals on the breeze)
local colors = {
black = "#000000",
white = "#ffffff",
blue = "#1f75fe",
cyan = "#00b7eb",
orange = "#ff8c00",
yellow = "#ffd700",
purple = "#6f2da8",
violet = "#6f2da8",
magenta = "#ff33cc",
red = "#ff2400",
pink = "#ffc0cb",
green = "#7cfc00",
dark_green = "#013220",
dark_gray = "#333333",
darkgray = "#333333",
grey = "#9a9a9a",
brown = "#704214",
}
local flowers = { -- special cases listed here
["farming:sunflower_8"] = "#ffd700",
["farming:cotton_8"] = "#ffffff",
["x_farming:cotton_8"] = "#ffffff",
["dorwinion:dorwinion_glow_leaves"] = "self",
["nightshade:nightshade_glowin_leaves_1"] = "self",
["naturalbiomes:heatherflowernode"] = "self",
["naturalbiomes:heatherflower2node"] = "self",
["naturalbiomes:heatherflower3node"] = "self",
["naturalbiomes:heatherflower4node"] = "self",
}
effervescence.register_environmental_particles({
name = "effervescence:blossoming",
check = function(self, pos)
return core.get_node(pos:offset(0,1,0)).name == "air"
end,
applies_to = function(self, node, def)
local groups = def.groups or {}
local is_plant = not def.walkable and def.drawtype:find("plant") and not node:find("shroom") and ((groups.flower and groups.flower > 0) or node:find("flower"))
if is_plant then
local dye = core.get_craft_result({
method = "normal",
width = 1,
items = { node },
})
if not dye.item:is_empty() and dye.item:get_name():find("dye") then
local dgroups = core.registered_items[dye.item:get_name()].groups
for color,hex in pairs(colors) do
if (dgroups["color_" .. color] and dgroups["color_" .. color] > 0) or (dgroups["basecolor_" .. color] and dgroups["basecolor_" .. color] > 0) then
flowers[node] = hex
break
end
end
end
end
return flowers[node] and { "effervescence:many" }
end,
emit = function(self, pos)
local node = core.get_node(pos)
local ndef = core.registered_nodes[node.name]
return {
amount = math.random(2,3),
time = 1,
pos = {
min = pos:add(vector.new(-0.25,-0.125,-0.25)),
max = pos:add(vector.new(0.25,0.25,0.25)),
},
minvel = {x = -3, y = -0.05, z = -3},
maxvel = {x = 3, y = 1.5, z = 3},
minacc = {x = -0.125, y = -0.125, z = -0.125},
maxacc = {x = 0.125, y = 0.75, z = 0.125},
minexptime = 3,
maxexptime = 5,
minsize = 0.375,
maxsize = 0.5,
glow = ndef.glow or ndef.light_source,
texture = {
name = extract_particles(flowers[node.name] == "self" and ndef.tiles or {[1] = "effervescence_petals.png"},flowers[node.name] ~= "self" and flowers[node.name]),
blend = blend_method,
},
collisiondetection = true,
collision_removal = true,
vertical = false,
}
end,
})
-- Sporogenic particles (primarily mushrooms, glow worms, and certain vines)
effervescence.register_environmental_particles({
name = "effervescence:sporogenic",
check = function(self, pos)
return true
end,
applies_to = function(self, node, def)
local groups = def.groups or {}
local does_apply = not def.walkable and def.drawtype:find("plant") and (node:find("glow_worm") or node:find("shroom") or node:find("fung") or node:find("myc") or node:find("coral_grass") or node:find("coral_plant") or node:find("[:_]vine") or node:find("spore") or (groups.mushroom and groups.mushroom > 0))
return does_apply and { "effervescence:many" }
end,
emit = function(self, pos)
local node = core.get_node(pos)
local ndef = core.registered_nodes[node.name]
return {
amount = math.random(9,12),
time = 1.5,
pos = {
min = pos:add(vector.new(-0.25,-0.1,-0.25)),
max = pos:add(vector.new(0.25,0.1,0.25)),
},
minvel = {x = -0.625, y = -0.075, z = -0.625},
maxvel = {x = 0.625, y = -0.05, z = 0.625},
minacc = {x = 0, y = -0.25, z = 0},
maxacc = {x = 0, y = -0.125, z = 0},
minexptime = 5,
maxexptime = 8,
minsize = 0.25,
maxsize = 0.325,
glow = ndef.glow or ndef.light_source or 2,
texture = {
name = extract_particles(ndef.tiles,ndef.color,"4,7"),
blend = blend_method,
},
collisiondetection = true,
collision_removal = true,
vertical = false,
}
end,
})
-- Sparkly particles (glistening crystals or ice)
local neighbors = {
vector.new(0,1,0),
vector.new(1,0,0),
vector.new(0,0,1),
vector.new(-1,0,0),
vector.new(0,0,-1),
vector.new(0,-1,0),
}
effervescence.register_environmental_particles({
name = "effervescence:sparkly",
check = function(self, pos)
for _,direction in ipairs(neighbors) do
if core.get_node(pos:add(direction)).name == "air" then
return true
end
end
return false
end,
applies_to = function(self, node, def)
local does_apply = (def.drawtype:find("plant") and (node:find("[:_]crystal") or node:find("[:_]gem") or node:find("^caverealms:spike$") or node:find("icicle")) or node:find("[:_]ice$") or node:find("[:_]cave_ice$"))
return does_apply and { "effervescence:many" }
end,
emit = function(self, pos)
local node = core.get_node(pos)
local ndef = core.registered_nodes[node.name]
return {
amount = math.random(9,11),
time = 4,
pos = {
min = pos:add(vector.new(-0.75,-0.25,-0.75)),
max = pos:add(vector.new(0.75,0.575,0.75)),
},
minvel = {x = 0, y = -0.05, z = 0},
maxvel = {x = 0, y = 0, z = 0},
minacc = {x = 0, y = 0, z = 0},
maxacc = {x = 0, y = 0, z = 0},
minexptime = 3,
maxexptime = 6,
minsize = 0.1,
maxsize = 0.2,
glow = ndef.glow or ndef.light_source or 2,
texture = {
name = extract_particles(ndef.tiles,nil,"4,7") .. "^[sheet:4x4:1,1^[opacity:255^[brighten",
blend = blend_method,
},
collisiondetection = false,
vertical = false,
}
end,
})
-- Tiny bubbles at the surface of water
effervescence.register_environmental_particles({
name = "effervescence:bubbling",
check = function(self, pos)
return core.get_node(pos:offset(0,1,0)).name == "air"
end,
applies_to = function(self, node, def)
local does_apply = (def.liquidtype == "source" and node:find("[:_]water"))
return does_apply and { "effervescence:liquid_surface" }
end,
emit = function(self, pos)
local node = core.get_node(pos)
local ndef = core.registered_nodes[node.name]
return {
amount = math.random(4,6),
time = math.random(3,4),
pos = {
min = pos:add(vector.new(-0.45,0.5,-0.45)),
max = pos:add(vector.new(0.45,0.525,0.45)),
},
minvel = {x = -0.0275, y = -0.025, z = -0.0275},
maxvel = {x = 0.0275, y = 0, z = 0.0275},
minacc = {x = 0, y = 0, z = 0},
maxacc = {x = 0, y = 0, z = 0},
minexptime = 1,
maxexptime = 2,
minsize = 1,
maxsize = 1.25,
glow = ndef.glow or ndef.light_source,
texture = extract_particles(ndef.tiles,ndef.color) .. "^[brighten^[opacity:127",
collisiondetection = false,
vertical = false,
}
end,
})
-- Player walk particles (bits of dirt, snow, etc. kicked up underfoot)
local walking_nodes = {}
effervescence.register_player_particles({
name = "effervescence:walking",
check = function(self, player)
local velocity = player:get_velocity()
if math.abs(velocity.x) > 0.025 or math.abs(velocity.z) > 0.025 then
local below = core.get_node(player:get_pos():offset(0,-0.1,0)).name
return walking_nodes[below]
end
end,
applies_to = function(self, node, def)
local groups = def.groups or {}
local does_apply = (groups.crumbly and groups.crumbly > 0) or (groups.soil and groups.soil > 0) or (groups.sand and groups.sand > 0) or (groups.leaves and groups.leaves > 0) or (groups.snowy and groups.snowy > 0) or node:find(":snow") or node:find("_with_snow")
if does_apply then
walking_nodes[node] = true
return true
else
return false
end
end,
emit = function(self, player)
local pos = player:get_pos()
local node = core.get_node(pos:offset(0,-0.1,0))
local ndef = core.registered_nodes[node.name]
return {
amount = math.random(3,4),
time = 0.25,
pos = {
min = pos:add(vector.new(-0.45,0.175,-0.45)),
max = pos:add(vector.new(0.45,0.275,0.45)),
},
minvel = {x = -1, y = 0.75, z = -1},
maxvel = {x = 1, y = 1, z = 1},
minacc = {x = 0, y = -9.81, z = 0},
maxacc = {x = 0, y = -9.81, z = 0},
minexptime = 1,
maxexptime = 1,
minsize = 0.75,
maxsize = 1,
glow = ndef.glow or ndef.light_source,
texture = {
name = extract_particles(ndef.tiles,ndef.color),
blend = blend_method,
},
collisiondetection = true,
collision_removal = true,
vertical = false,
}
end,
})