--[[ Everness. Never ending discovery in Everness mapgen. Copyright (C) 2024 SaKeL This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. --]] -- -- Convert dirt to something that fits the environment -- local grass_covered_mapping = { ['everness:coral_dirt'] = { 'everness:dirt_with_coral_grass' }, ['everness:cursed_dirt'] = { 'everness:dirt_with_cursed_grass' }, ['everness:crystal_dirt'] = { 'everness:dirt_with_crystal_grass' }, ['everness:dirt_1'] = { 'everness:dirt_with_grass_1', 'everness:dirt_with_grass_extras_1', 'everness:dirt_with_grass_extras_2', }, ['everness:dry_dirt'] = { 'everness:dry_dirt_with_dry_grass' } } local grass_covered_mapping_under = { ['everness:coral_desert_stone'] = { 'everness:coral_desert_stone_with_moss' }, ['everness:soul_sandstone'] = { 'everness:soul_sandstone_veined' }, ['everness:crystal_cave_dirt'] = { 'everness:crystal_cave_dirt_with_moss' }, ['everness:mold_cobble'] = { 'everness:mold_stone_with_moss' }, } -- Spread grass on dirt Everness:register_abm({ label = 'everness:grass_spread', description = 'Spreads grass on neighboring blocks.', nodenames = { 'everness:coral_dirt', 'everness:cursed_dirt', 'everness:crystal_dirt', 'everness:dirt_1', 'everness:dry_dirt', }, neighbors = { 'air', 'group:coral_grass', 'group:cursed_grass', 'group:crystal_grass', 'group:bamboo_grass', 'group:everness_dry_grass' }, interval = 6, chance = 50, catch_up = false, action = function(pos, node) -- Check for darkness: night, shadow or under a light-blocking node -- Returns if ignore above local above = { x = pos.x, y = pos.y + 1, z = pos.z } if (minetest.get_node_light(above) or 0) < 13 then return end -- Look for spreading dirt-type neighbours local p2 = minetest.find_node_near(pos, 1, 'group:everness_spreading_dirt_type') if p2 then local n3_def = grass_covered_mapping[node.name] if not n3_def then return end local n3_name = n3_def[1] if #n3_def > 1 then n3_name = n3_def[math.random(1, #n3_def)] end minetest.set_node(pos, { name = n3_name }) return end -- Else, any seeding nodes on top? local name = minetest.get_node(above).name if minetest.get_item_group(name, 'coral_grass') ~= 0 and node.name == 'everness:coral_dirt' then minetest.set_node(pos, { name = 'everness:dirt_with_coral_grass' }) elseif minetest.get_item_group(name, 'cursed_grass') ~= 0 and node.name == 'everness:cursed_dirt' then minetest.set_node(pos, { name = 'everness:dirt_with_cursed_grass' }) elseif minetest.get_item_group(name, 'crystal_grass') ~= 0 and node.name == 'everness:crystal_dirt' then minetest.set_node(pos, { name = 'everness:dirt_with_crystal_grass' }) elseif minetest.get_item_group(name, 'bamboo_grass') ~= 0 and node.name == 'everness:dirt_1' then local bamboo_grass_covered_types = { 'everness:dirt_with_grass_1', 'everness:dirt_with_grass_extras_1', 'everness:dirt_with_grass_extras_2' } minetest.set_node(pos, { name = bamboo_grass_covered_types[math.random(1, #bamboo_grass_covered_types)] }) elseif minetest.get_item_group(name, 'everness_dry_grass') ~= 0 and node.name == 'everness:dry_dirt' then minetest.set_node(pos, { name = 'everness:dry_dirt_with_dry_grass' }) end end }) -- Spread mold/moss on stone/dirt - under Everness:register_abm({ label = 'everness:grass_spread_under', description = 'Spreads grass on neighboring blocks in caves (under).', nodenames = { 'everness:coral_desert_stone', 'everness:soul_sandstone', 'everness:crystal_cave_dirt', 'everness:mold_cobble', }, neighbors = { 'air', 'group:coral_grass_under', 'group:cursed_grass_under', 'group:crystal_grass_under', 'group:forsaken_tundra_grass_under', }, interval = 6, chance = 50, catch_up = false, action = function(pos, node) -- Check for darkness: night, shadow or under a light-blocking node -- Returns if ignore above local above = { x = pos.x, y = pos.y + 1, z = pos.z } if (minetest.get_node_light(above) or 0) < 13 then return end -- Look for spreading dirt-type neighbours local p2 = minetest.find_node_near(pos, 1, 'group:everness_spreading_dirt_type_under') if p2 then local n3_def = grass_covered_mapping_under[node.name] if not n3_def then return end local n3_name = n3_def[1] if #n3_def > 1 then n3_name = n3_def[math.random(1, #n3_def)] end minetest.set_node(pos, {name = n3_name}) return end -- Else, any seeding nodes on top? local name = minetest.get_node(above).name if minetest.get_item_group(name, 'coral_grass_under') ~= 0 and node.name == 'everness:coral_desert_stone' then minetest.set_node(pos, { name = 'everness:coral_desert_stone_with_moss' }) elseif minetest.get_item_group(name, 'cursed_grass_under') ~= 0 and node.name == 'everness:soul_sandstone' then minetest.set_node(pos, { name = 'everness:soul_sandstone_veined' }) elseif minetest.get_item_group(name, 'crystal_grass_under') ~= 0 and node.name == 'everness:crystal_cave_dirt' then minetest.set_node(pos, { name = 'everness:crystal_cave_dirt_with_moss' }) elseif minetest.get_item_group(name, 'forsaken_tundra_grass_under') ~= 0 and node.name == 'everness:mold_cobble' then minetest.set_node(pos, { name = 'everness:mold_stone_with_moss' }) end end }) -- -- Grass and dry grass removed in darkness -- Everness:register_abm({ label = 'everness:grass_covered', description = 'Grass and dry grass removed in darkness.', nodenames = { 'group:everness_spreading_dirt_type', 'group:everness_spreading_dirt_type_under', }, interval = 8, chance = 50, catch_up = false, action = function(pos, node) local above = { x = pos.x, y = pos.y + 1, z = pos.z } local name = minetest.get_node(above).name local nodedef = minetest.registered_nodes[name] if name ~= 'ignore' and nodedef and not ( (nodedef.sunlight_propagates or nodedef.paramtype == 'light') and nodedef.liquidtype == 'none' ) then if node.name == 'everness:dirt_with_coral_grass' then minetest.set_node(pos, { name = 'everness:coral_dirt' }) elseif node.name == 'everness:dirt_with_cursed_grass' then minetest.set_node(pos, { name = 'everness:cursed_dirt' }) elseif node.name == 'everness:dirt_with_crystal_grass' then minetest.set_node(pos, { name = 'everness:crystal_dirt' }) elseif node.name == 'everness:dirt_with_grass_1' or node.name == 'everness:dirt_with_grass_extras_1' or node.name == 'everness:dirt_with_grass_extras_2' then minetest.set_node(pos, { name = 'everness:dirt_1' }) elseif node.name == 'everness:coral_desert_stone_with_moss' then minetest.set_node(pos, { name = 'everness:coral_desert_stone' }) elseif node.name == 'everness:dry_dirt_with_dry_grass' then minetest.set_node(pos, { name = 'everness:dry_dirt' }) elseif node.name == 'everness:soul_sandstone_veined' then minetest.set_node(pos, { name = 'everness:soul_sandstone' }) elseif node.name == 'everness:crystal_cave_dirt_with_moss' then minetest.set_node(pos, { name = 'everness:crystal_cave_dirt' }) elseif node.name == 'everness:mold_stone_with_moss' then minetest.set_node(pos, { name = 'everness:mold_cobble' }) end end end }) -- -- Leafdecay -- Everness:register_leafdecay({ trunks = { 'everness:coral_tree', 'everness:crystal_bush_stem', 'everness:cursed_bush_stem', 'everness:willow_tree', 'everness:sequoia_tree', 'everness:mese_tree', 'everness:palm_tree' }, leaves = { 'everness:coral_leaves', 'everness:crystal_bush_leaves', 'everness:willow_leaves', 'everness:sequoia_leaves', 'everness:mese_leaves', 'everness:mese_tree_fruit', 'everness:palm_leaves', 'everness:coconut' }, radius = 3 }) -- Baobab Tree Everness:register_leafdecay({ trunks = { 'everness:baobab_tree', 'everness:crystal_tree', 'everness:dry_tree', }, leaves = { 'everness:baobab_leaves', 'everness:baobab_fruit_renewable', 'everness:crystal_leaves', 'everness:dry_branches', }, radius = 4, }) -- -- Moss growth on cobble near water -- local moss_correspondences = { ['everness:coral_desert_cobble'] = 'everness:coral_desert_mossy_cobble', ['everness:crystal_cobble'] = 'everness:crystal_mossy_cobble', } local moss_nodenames_correspondences = { 'everness:coral_desert_cobble', 'everness:crystal_cobble', } if minetest.get_modpath('default') then moss_correspondences['stairs:slab_coral_desert_cobble'] = 'stairs:slab_coral_desert_mossy_cobble' moss_correspondences['stairs:stair_coral_desert_cobble'] = 'stairs:stair_coral_desert_mossy_cobble' moss_correspondences['stairs:stair_inner_coral_desert_cobble'] = 'stairs:stair_inner_coral_desert_mossy_cobble' moss_correspondences['stairs:stair_outer_coral_desert_cobble'] = 'stairs:stair_outer_coral_desert_mossy_cobble' moss_correspondences['everness:coral_desert_cobble_wall'] = 'everness:coral_desert_mossy_cobble_wall' table.insert(moss_nodenames_correspondences, 'stairs:slab_coral_desert_cobble') table.insert(moss_nodenames_correspondences, 'stairs:stair_coral_desert_cobble') table.insert(moss_nodenames_correspondences, 'stairs:stair_inner_coral_desert_cobble') table.insert(moss_nodenames_correspondences, 'stairs:stair_outer_coral_desert_cobble') table.insert(moss_nodenames_correspondences, 'everness:coral_desert_cobble_wall') end Everness:register_abm({ label = 'everness:moss_growth', description = 'Grows moss on blocks near water.', nodenames = moss_nodenames_correspondences, neighbors = { 'group:water' }, interval = 16, chance = 200, catch_up = false, action = function(pos, node) node.name = moss_correspondences[node.name] if node.name then minetest.set_node(pos, node) end end }) -- -- Magma growth on cobble near lava -- local magma_correspondences = { ['everness:volcanic_rock'] = 'everness:volcanic_rock_with_magma', } local magma_nodenames_correspondences = { 'everness:volcanic_rock' } if minetest.get_modpath('default') then magma_correspondences['default:cobble'] = 'everness:magmacobble' magma_correspondences['stairs:slab_cobble'] = 'stairs:slab_magmacobble' magma_correspondences['stairs:stair_cobble'] = 'stairs:stair_magmacobble' magma_correspondences['stairs:stair_inner_cobble'] = 'stairs:stair_inner_magmacobble' magma_correspondences['stairs:stair_outer_cobble'] = 'stairs:stair_outer_magmacobble' magma_correspondences['walls:cobble'] = 'everness:magmacobble_wall' magma_correspondences['stairs:slab_volcanic_rock'] = 'stairs:slab_volcanic_rock_with_magma' magma_correspondences['stairs:stair_volcanic_rock'] = 'stairs:stair_volcanic_rock_with_magma' magma_correspondences['stairs:stair_inner_volcanic_rock'] = 'stairs:stair_inner_volcanic_rock_with_magma' magma_correspondences['stairs:stair_outer_volcanic_rock'] = 'stairs:stair_outer_volcanic_rock_with_magma' magma_correspondences['everness:volcanic_rock_wall'] = 'everness:volcanic_rock_with_magma_wall' table.insert(magma_nodenames_correspondences, 'default:cobble') table.insert(magma_nodenames_correspondences, 'stairs:slab_cobble') table.insert(magma_nodenames_correspondences, 'stairs:stair_cobble') table.insert(magma_nodenames_correspondences, 'stairs:stair_inner_cobble') table.insert(magma_nodenames_correspondences, 'stairs:stair_outer_cobble') table.insert(magma_nodenames_correspondences, 'walls:cobble') table.insert(magma_nodenames_correspondences, 'stairs:slab_volcanic_rock') table.insert(magma_nodenames_correspondences, 'stairs:stair_volcanic_rock') table.insert(magma_nodenames_correspondences, 'stairs:stair_inner_volcanic_rock') table.insert(magma_nodenames_correspondences, 'stairs:stair_outer_volcanic_rock') table.insert(magma_nodenames_correspondences, 'everness:volcanic_rock_wall') end Everness:register_abm({ label = 'everness:magma_growth', description = 'Grows magma on blocks near lava.', nodenames = magma_nodenames_correspondences, neighbors = { 'group:lava' }, interval = 16, chance = 200, catch_up = false, action = function(pos, node) node.name = magma_correspondences[node.name] if node.name then minetest.set_node(pos, node) end end }) -- -- Falling leaves -- Everness:register_abm({ label = 'everness:falling_leaves', description = 'Makes leaves falling particles.', nodenames = { 'group:falling_leaves' }, neighbors = { 'air' }, interval = 16, chance = 16, catch_up = false, action = function(pos, node) if not minetest.settings:get_bool('enable_particles', true) then return end local air_below = minetest.find_nodes_in_area(pos, { x = pos.x, y = pos.y + 3, z = pos.z }, { 'air' }) if #air_below < 3 then return end -- particles local particlespawner_def = { amount = 5, time = 1, minpos = { x = pos.x - 0.5, y = pos.y - 0.5, z = pos.z - 0.5 }, maxpos = { x = pos.x + 0.5, y = pos.y - 0.5, z = pos.z + 0.5 }, minvel = { x = -0.25, y = -0.25, z = -0.25 }, maxvel = { x = 0.25, y = -0.5, z = 0.25 }, minacc = { x = -0.25, y = -0.25, z = -0.25 }, maxacc = { x = 0.25, y = -0.5, z = 0.25 }, minexptime = 3, maxexptime = 6, minsize = 0.5, maxsize = 1.5, node = node } if minetest.has_feature({ dynamic_add_media_table = true, particlespawner_tweenable = true }) then -- new syntax, after v5.6.0 particlespawner_def = { amount = 5, time = 1, size = { min = 0.5, max = 1.5, }, exptime = { min = 3, max = 6 }, pos = { min = vector.new({ x = pos.x - 0.5, y = pos.y - 0.5, z = pos.z - 0.5 }), max = vector.new({ x = pos.x + 0.5, y = pos.y - 0.5, z = pos.z + 0.5 }), }, vel = { min = vector.new({ x = -0.25, y = -0.25, z = -0.25 }), max = vector.new({ x = 0.25, y = -0.5, z = 0.25 }) }, acc = { min = vector.new({ x = -0.25, y = -0.25, z = -0.25 }), max = vector.new({ x = 0.25, y = -0.5, z = 0.25 }) }, node = { name = node.name } } end minetest.add_particlespawner(particlespawner_def) end }) -- -- Falling leaves - vines -- Everness:register_abm({ label = 'everness:falling_vines', description = 'Makes vines falling particles.', nodenames = { 'group:falling_vines' }, neighbors = { 'air' }, interval = 16, chance = 16, catch_up = false, action = function(pos, node) if not minetest.settings:get_bool('enable_particles', true) then return end local air_around = minetest.find_nodes_in_area( { x = pos.x - 1, y = pos.y, z = pos.z - 1 }, { x = pos.x + 1, y = pos.y, z = pos.z + 1 }, { 'air' } ) if #air_around < 3 then return end -- particles local particlespawner_def = { amount = 5, time = 1, minpos = { x = pos.x - 0.5, y = pos.y - 0.5, z = pos.z - 0.5 }, maxpos = { x = pos.x + 0.5, y = pos.y - 0.5, z = pos.z + 0.5 }, minvel = { x = -0.25, y = -0.25, z = -0.25 }, maxvel = { x = 0.25, y = -0.5, z = 0.25 }, minacc = { x = -0.25, y = -0.25, z = -0.25 }, maxacc = { x = 0.25, y = -0.5, z = 0.25 }, minexptime = 15, maxexptime = 30, minsize = 0.5, maxsize = 1.5, node = node, glow = 7 } if minetest.has_feature({ dynamic_add_media_table = true, particlespawner_tweenable = true }) then -- new syntax, after v5.6.0 particlespawner_def = { amount = 5, time = 1, size = { min = 0.5, max = 1.5, }, exptime = { min = 15, max = 30 }, pos = { min = vector.new(pos.x - 0.5, pos.y - 0.5, pos.z - 0.5), max = vector.new(pos.x + 0.5, pos.y - 0.5, pos.z + 0.5), }, vel = { min = vector.new(-0.25, -0.15, -0.25), max = vector.new(0.25, -0.25, 0.25) }, acc = { min = vector.new(-0.25, -0.05, -0.25), max = vector.new(0.25, -0.1, 0.25) }, node = { name = node.name }, glow = 7 } end minetest.add_particlespawner(particlespawner_def) end }) Everness:register_abm({ label = 'everness:grow_orange_cactus', description = 'Grows orange cactus.', nodenames = { 'everness:cactus_orange', 'everness:cactus_blue' }, neighbors = { 'group:sand', 'group:everness_sand' }, interval = 12, chance = 83, action = function(...) Everness:grow_cactus(...) end }) -- -- Bio Bubbles -- Everness:register_abm({ label = 'everness:bio_bubbles', description = 'Bubble particles under water.', nodenames = { 'group:bio_bubbles' }, neighbors = { 'group:water' }, interval = 16, chance = 2, catch_up = false, action = function(pos, node) if not minetest.settings:get_bool('enable_particles', true) then return end local water_above = minetest.find_nodes_in_area(pos, { x = pos.x, y = pos.y + 10, z = pos.z }, { 'group:water' }) if #water_above < 10 then return end -- particles local particlespawner_def = { amount = 50, time = 10, minpos = vector.new({ x = pos.x - 0.1, y = pos.y + 0.6, z = pos.z - 0.1 }), maxpos = vector.new({ x = pos.x + 0.1, y = pos.y + 0.6, z = pos.z + 0.1 }), minvel = vector.new({ x = -0.1, y = 0.25, z = -0.1 }), maxvel = vector.new({ x = 0.1, y = 0.5, z = 0.1 }), minacc = vector.new({ x = -0.1, y = 0.25, z = -0.1 }), maxacc = vector.new({ x = 0.1, y = 0.5, z = 0.1 }), minexptime = 5, maxexptime = 7, minsize = 2, maxsize = 3.5, texture = 'everness_bubble.png', glow = 7 } if minetest.has_feature({ dynamic_add_media_table = true, particlespawner_tweenable = true }) then -- new syntax, after v5.6.0 particlespawner_def = { amount = 50, time = 10, size = { min = 2, max = 3.5, }, exptime = { min = 5, max = 7 }, pos = { min = vector.new({ x = pos.x - 0.1, y = pos.y + 0.6, z = pos.z - 0.1 }), max = vector.new({ x = pos.x + 0.1, y = pos.y + 0.6, z = pos.z + 0.1 }), }, vel = { min = vector.new({ x = -0.1, y = 0.25, z = -0.1 }), max = vector.new({ x = 0.1, y = 0.5, z = 0.1 }) }, acc = { min = vector.new({ x = -0.1, y = 0.25, z = -0.1 }), max = vector.new({ x = 0.1, y = 0.5, z = 0.1 }) }, texture = { name = 'everness_bubble.png', alpha_tween = { 1, 0, style = 'fwd', reps = 1 }, scale_tween = { 0.5, 1, style = 'fwd', reps = 1 } }, glow = 7 } end minetest.add_particlespawner(particlespawner_def) end }) -- -- Rising Souls -- Everness:register_abm({ label = 'everness:rising_souls', description = 'Rising souls particles under water.', nodenames = { 'group:rising_souls' }, neighbors = { 'group:water' }, interval = 16, chance = 2, catch_up = false, action = function(pos, node) if not minetest.settings:get_bool('enable_particles', true) then return end local water_above = minetest.find_nodes_in_area(pos, { x = pos.x, y = pos.y + 10, z = pos.z }, { 'group:water' }) if #water_above < 10 then return end -- particles local particlespawner_def = { amount = 17, time = 10, minpos = vector.new({ x = pos.x - 0.3, y = pos.y + 0.6, z = pos.z - 0.3 }), maxpos = vector.new({ x = pos.x + 0.3, y = pos.y + 0.6, z = pos.z + 0.3 }), minvel = vector.new({ x = -0.1, y = 0.25, z = -0.1 }), maxvel = vector.new({ x = 0.1, y = 0.5, z = 0.1 }), minacc = vector.new({ x = -0.1, y = 0.25, z = -0.1 }), maxacc = vector.new({ x = 0.1, y = 0.5, z = 0.1 }), minexptime = 4, maxexptime = 6, minsize = 4, maxsize = 6, texture = 'everness_rising_soul_particle.png', glow = 7 } if minetest.has_feature({ dynamic_add_media_table = true, particlespawner_tweenable = true }) then -- new syntax, after v5.6.0 particlespawner_def = { amount = 17, time = 10, size = { min = 4, max = 6, }, exptime = { min = 4, max = 6 }, pos = { min = vector.new({ x = pos.x - 0.3, y = pos.y + 0.6, z = pos.z - 0.3 }), max = vector.new({ x = pos.x + 0.3, y = pos.y + 0.6, z = pos.z + 0.3 }), }, vel = { min = vector.new({ x = -0.1, y = 0.25, z = -0.1 }), max = vector.new({ x = 0.1, y = 0.5, z = 0.1 }) }, acc = { min = vector.new({ x = -0.1, y = 0.25, z = -0.1 }), max = vector.new({ x = 0.1, y = 0.5, z = 0.1 }) }, texture = { name = 'everness_rising_soul_particle.png', animation = { type = 'vertical_frames', aspect_w = 16, aspect_h = 16, length = 2, }, alpha_tween = { 1, 0, style = 'fwd', reps = 1 }, scale_tween = { 0.5, 1, style = 'fwd', reps = 1 } }, glow = 7 } end minetest.add_particlespawner(particlespawner_def) end }) -- -- Rising Crystals -- Everness:register_abm({ label = 'everness:rising_crystals', description = 'Crystal particles under water.', nodenames = { 'group:rising_crystals' }, neighbors = { 'group:water' }, interval = 16, chance = 2, catch_up = false, action = function(pos, node) if not minetest.settings:get_bool('enable_particles', true) then return end local water_above = minetest.find_nodes_in_area(pos, { x = pos.x, y = pos.y + 10, z = pos.z }, { 'group:water' }) if #water_above < 10 then return end -- particles local particlespawner_def = { amount = 17, time = 10, minpos = vector.new({ x = pos.x - 0.3, y = pos.y + 0.6, z = pos.z - 0.3 }), maxpos = vector.new({ x = pos.x + 0.3, y = pos.y + 0.6, z = pos.z + 0.3 }), minvel = vector.new({ x = -0.1, y = 0.25, z = -0.1 }), maxvel = vector.new({ x = 0.1, y = 0.5, z = 0.1 }), minacc = vector.new({ x = -0.1, y = 0.25, z = -0.1 }), maxacc = vector.new({ x = 0.1, y = 0.5, z = 0.1 }), minexptime = 4, maxexptime = 6, minsize = 4, maxsize = 6, texture = 'everness_rising_soul_particle.png', glow = 7 } if minetest.has_feature({ dynamic_add_media_table = true, particlespawner_tweenable = true }) then -- new syntax, after v5.6.0 particlespawner_def = { amount = 25, time = 10, size = { min = 6, max = 8, }, exptime = { min = 4, max = 6 }, pos = { min = vector.new({ x = pos.x - 0.3, y = pos.y + 0.6, z = pos.z - 0.3 }), max = vector.new({ x = pos.x + 0.3, y = pos.y + 0.6, z = pos.z + 0.3 }), }, vel = { min = vector.new({ x = -0.1, y = 0.25, z = -0.1 }), max = vector.new({ x = 0.1, y = 0.5, z = 0.1 }) }, acc = { min = vector.new({ x = -0.1, y = 0.25, z = -0.1 }), max = vector.new({ x = 0.1, y = 0.5, z = 0.1 }) }, texture = { name = 'everness_crystal_forest_deep_ocean_sand_bubbles.png', animation = { type = 'vertical_frames', aspect_w = 16, aspect_h = 16, length = 1, }, alpha_tween = { 1, 0.5, style = 'fwd', reps = 1 } }, glow = 7 } end minetest.add_particlespawner(particlespawner_def) end }) -- Mineral Waters Water Geyser Everness:register_abm({ label = 'everness:water_geyser', description = 'Water geyser water splash.', nodenames = { 'everness:water_geyser' }, interval = 16, chance = 16, catch_up = false, action = function(pos, node) minetest.swap_node(pos, { name = 'everness:water_geyser_active' }) local meta = minetest.get_meta(pos) local partcile_time = math.random(5, 15) -- player for _, object in ipairs(minetest.get_objects_in_area(vector.new(pos.x - 0.5, pos.y - 0.5, pos.z - 0.5), vector.new(pos.x + 0.5, pos.y + 1, pos.z + 0.5))) do if object:is_player() and object:get_hp() > 0 then object:add_velocity(vector.new(0, math.random(27, 32), 0)) end end -- particles local particlespawner_def = { amount = 80, time = partcile_time, minpos = vector.new(pos.x, pos.y + 1.5, pos.z), maxpos = vector.new(pos.x, pos.y + 2, pos.z), minvel = vector.new(0, 13, 0), maxvel = vector.new(0, 15, 0), minacc = vector.new(0, -1, 1), maxacc = vector.new(0, -3, 2), minexptime = 3, maxexptime = 5, minsize = 5, maxsize = 7, texture = 'everness_water_geyser_particle.png', vertical = true, collisiondetection = true, collision_removal = true } if minetest.has_feature({ dynamic_add_media_table = true, particlespawner_tweenable = true }) then -- new syntax, above v5.6.0 particlespawner_def = { amount = 80, time = partcile_time, size = { min = 5, max = 7, }, exptime = { min = 3, max = 5 }, pos = { min = vector.new(pos.x, pos.y + 1.5, pos.z), max = vector.new(pos.x, pos.y + 2, pos.z) }, vel = { min = vector.new(0, 13, 0), max = vector.new(0, 15, 0) }, acc = { min = vector.new(0, -1, 1), max = vector.new(0, -3, 2) }, texture = { name = 'everness_water_geyser_particle.png', scale_tween = { 5, 10, style = 'fwd', reps = 1 }, alpha_tween = { 1, 0, style = 'fwd', reps = 1 }, blend = 'alpha', }, vertical = true, collisiondetection = true, collision_removal = true } end local particle_id = minetest.add_particlespawner(particlespawner_def) meta:set_int('particle_id', particle_id) minetest.sound_play({ name = 'everness_water_geyser', gain = 1.5, pitch = math.random(10, 30) / 10 }, { pos = pos }) minetest.get_node_timer(pos):start(partcile_time) end }) -- Generate bamboo tops after mineral waters biome generates decorations Everness:register_lbm({ -- Descriptive label for profiling purposes (optional). -- Definitions with identical labels will be listed as one. label = 'Generate bamboo tops after mineral waters biome generates decorations', -- Identifier of the LBM, should follow the modname: convention name = 'everness:mineral_waters_bamboo_large', -- List of node names to trigger the LBM on. -- Names of non-registered nodes and groups (as group:groupname) -- will work as well. nodenames = { 'everness:bamboo_3' }, -- Whether to run the LBM's action every time a block gets activated, -- and not only the first time the block gets activated after the LBM -- was introduced. run_at_every_load = true, -- Function triggered for each qualifying node. -- `dtime_s` is the in-game time (in seconds) elapsed since the block -- was last active action = function(pos, node, dtime_s) if minetest.get_node(vector.new(pos.x, pos.y + 1, pos.z)).name ~= 'air' then return end local node_below = minetest.get_node(vector.new(pos.x, pos.y - 1, pos.z)) -- Get bamboo height local while_counter = 1 local bamboo_height = 0 local bamboo_below = node_below while bamboo_below.name == 'everness:bamboo_3' do bamboo_below = minetest.get_node(vector.new(pos.x, pos.y - while_counter, pos.z)) bamboo_height = bamboo_height + 1 while_counter = while_counter + 1 end -- Add top bamboo nodes with leaves based on their generated height if bamboo_height > 4 then for i = 1, 3 do local pos_i = vector.new(pos.x, pos.y + i, pos.z) if minetest.get_node(pos_i).name == 'air' then if i == 1 then minetest.set_node(pos_i, { name = 'everness:bamboo_4', param2 = node_below.param2 }) else minetest.set_node(pos_i, { name = 'everness:bamboo_5', param2 = node_below.param2 }) end end end else for i = 1, 2 do local pos_i = vector.new(pos.x, pos.y + i, pos.z) if minetest.get_node(pos_i).name == 'air' then if i == 1 then minetest.set_node(pos_i, { name = 'everness:bamboo_4', param2 = node_below.param2 }) else minetest.set_node(pos_i, { name = 'everness:bamboo_5', param2 = node_below.param2 }) end end end end end }) -- Activate timers on lotus flowers Everness:register_lbm({ -- Descriptive label for profiling purposes (optional). -- Definitions with identical labels will be listed as one. label = 'Activate timers on lotus flowers', -- Identifier of the LBM, should follow the modname: convention name = 'everness:everness_lotus_flower_timers', -- List of node names to trigger the LBM on. -- Names of non-registered nodes and groups (as group:groupname) -- will work as well. nodenames = { 'everness:lotus_flower_white', 'everness:lotus_flower_purple', 'everness:lotus_flower_pink' }, -- Whether to run the LBM's action every time a block gets activated, -- and not only the first time the block gets activated after the LBM -- was introduced. run_at_every_load = true, -- Function triggered for each qualifying node. -- `dtime_s` is the in-game time (in seconds) elapsed since the block -- was last active action = function(pos, node, dtime_s) local timer = minetest.get_node_timer(pos) if not timer:is_started() then minetest.get_node_timer(pos):start(1) end end }) -- Spread lotus flowers and leafs around them Everness:register_abm({ label = 'everness:lotus_flowers_and_leaves_spread', description = 'Spreads lotus flowers and leaves.', nodenames = { 'everness:lotus_flower_white', 'everness:lotus_flower_purple', 'everness:lotus_flower_pink', 'everness:lotus_leaf', 'everness:lotus_leaf_2', 'everness:lotus_leaf_3' }, neighbors = { 'everness:lotus_flower_white', 'everness:lotus_flower_purple', 'everness:lotus_flower_pink', 'everness:lotus_leaf', 'everness:lotus_leaf_2', 'everness:lotus_leaf_3' }, max_y = Everness.settings.biomes.everness_mineral_waters.y_max, min_y = Everness.settings.biomes.everness_mineral_waters.y_min, interval = 13, chance = 300, action = function(pos, node) local under = minetest.get_node(vector.new(pos.x, pos.y - 1, pos.z)) local def = minetest.registered_nodes[under.name] or {} if def.liquidtype ~= 'source' and minetest.get_item_group(under.name, 'water') == 0 then return end local light = minetest.get_node_light(pos) if not light or light < 13 then return end local pos0 = vector.subtract(pos, 4) local pos1 = vector.add(pos, 4) local flower_node_names = { 'everness:lotus_flower_white', 'everness:lotus_flower_purple', 'everness:lotus_flower_pink' } local leaf_node_names = { 'everness:lotus_leaf', 'everness:lotus_leaf_2', 'everness:lotus_leaf_3' } local node_name = flower_node_names[math.random(1, #flower_node_names)] local found_flower_positions = minetest.find_nodes_in_area(pos0, pos1, flower_node_names) -- Testing shows that a threshold of 1 result in an appropriate maximum -- density of approximately 7 flowers per 9x9 area. if #found_flower_positions > 1 then -- Spread leafs local rand_flower_pos = found_flower_positions[math.random(1, #found_flower_positions)] pos0 = vector.subtract(rand_flower_pos, 4) pos1 = vector.add(rand_flower_pos, 4) local found_leaf_positions = minetest.find_nodes_in_area(pos0, pos1, leaf_node_names) if #found_leaf_positions > 25 then return end node_name = leaf_node_names[math.random(1, #leaf_node_names)] end local water_positions = minetest.find_nodes_in_area_under_air(pos0, pos1, 'group:water') table.shuffle(water_positions) -- Sort with the closest first table.sort(water_positions, function(a, b) return vector.distance(a, pos) < vector.distance(b, pos) end) local water_pos -- find water source since we are looking only for `group:water` for _, p in ipairs(water_positions) do local n = minetest.get_node(p) local d = minetest.registered_nodes[n.name] or {} if d.liquidtype == 'source' then water_pos = p break end end if not water_pos then return end local water_above = vector.new(water_pos.x, water_pos.y + 1, water_pos.z) light = minetest.get_node_light(water_above) if light and light >= 13 then minetest.set_node(water_above, { name = node_name }) end end }) -- Override lava cooling to include some variations of obsidian minetest.register_on_mods_loaded(function() for _, abm in pairs(minetest.registered_abms) do if abm.label == 'Lava cooling' and abm.action ~= nil then local prev_cool_lava_action = abm.action abm.action = function(pos, node, dtime_s) Everness.cool_lava(pos, node, dtime_s, prev_cool_lava_action) end end end end) -- Calculates `everness:hammer_sharp` wear when crafting minetest.register_craft_predict(function(itemstack, player, old_craft_grid, craft_inv) if itemstack and itemstack:get_name() == 'everness:hammer_sharp' then local stack_meta = itemstack:get_meta() local hammers = 0 local wear_total = 0 for k, stack in pairs(old_craft_grid) do if stack:get_name() == 'everness:hammer' then local meta = stack:get_meta() wear_total = wear_total + meta:get_int('everness_wear') hammers = hammers + 1 end end local average_wear = wear_total / hammers stack_meta:set_int('everness_wear', math.ceil(average_wear)) -- Draw wear bar texture overlay if average_wear > 0 then Everness.draw_wear_bar(itemstack, average_wear) end return itemstack end end) -- Calculates `everness:hammer_sharp` wear when crafting minetest.register_on_craft(function(itemstack, player, old_craft_grid, craft_inv) if itemstack and itemstack:get_name() == 'everness:hammer_sharp' then local stack_meta = itemstack:get_meta() local hammers = 0 local wear_total = 0 for k, stack in pairs(old_craft_grid) do if stack:get_name() == 'everness:hammer' then local meta = stack:get_meta() wear_total = wear_total + meta:get_int('everness_wear') hammers = hammers + 1 end end local average_wear = wear_total / hammers stack_meta:set_int('everness_wear', math.ceil(average_wear)) -- Draw wear bar texture overlay if average_wear > 0 then Everness.draw_wear_bar(itemstack, average_wear) end return itemstack end end)