-- mods/default/functions.lua -- -- Sounds -- function default.node_sound_defaults(table) table = table or {} table.footstep = table.footstep or {name="", gain=1.0} table.dug = table.dug or {name="default_dug_node", gain=0.25} table.place = table.place or {name="default_place_node_hard", gain=1.0} return table end function default.node_sound_stone_defaults(table) table = table or {} table.footstep = table.footstep or {name="default_hard_footstep", gain=0.5} table.dug = table.dug or {name="default_hard_footstep", gain=1.0} default.node_sound_defaults(table) return table end function default.node_sound_dirt_defaults(table) table = table or {} table.footstep = table.footstep or {name="default_dirt_footstep", gain=1.0} table.dug = table.dug or {name="default_dirt_footstep", gain=1.5} table.place = table.place or {name="default_place_node", gain=1.0} default.node_sound_defaults(table) return table end function default.node_sound_sand_defaults(table) table = table or {} table.footstep = table.footstep or {name="default_sand_footstep", gain=0.5} table.dug = table.dug or {name="default_sand_footstep", gain=1.0} table.place = table.place or {name="default_place_node", gain=1.0} default.node_sound_defaults(table) return table end function default.node_sound_wood_defaults(table) table = table or {} table.footstep = table.footstep or {name="default_wood_footstep", gain=0.5} table.dug = table.dug or {name="default_wood_footstep", gain=1.0} default.node_sound_defaults(table) return table end function default.node_sound_leaves_defaults(table) table = table or {} table.footstep = table.footstep or {name="default_grass_footstep", gain=0.35} table.dug = table.dug or {name="default_grass_footstep", gain=0.85} table.dig = table.dig or {name="default_dig_crumbly", gain=0.4} table.place = table.place or {name="default_place_node", gain=1.0} default.node_sound_defaults(table) return table end function default.node_sound_glass_defaults(table) table = table or {} table.footstep = table.footstep or {name="default_glass_footstep", gain=0.5} table.dug = table.dug or {name="default_break_glass", gain=1.0} default.node_sound_defaults(table) return table end -- -- Legacy -- function default.spawn_falling_node(p, nodename) spawn_falling_node(p, nodename) end -- Horrible crap to support old code -- Don't use this and never do what this does, it's completely wrong! -- (More specifically, the client and the C++ code doesn't get the group) function default.register_falling_node(nodename, texture) minetest.log("error", debug.traceback()) minetest.log('error', "WARNING: default.register_falling_node is deprecated") if minetest.registered_nodes[nodename] then minetest.registered_nodes[nodename].groups.falling_node = 1 end end minetest.register_abm({ label = "grow sapling", nodenames = {"default:sapling"}, interval = 10, chance = 50, action = function(pos, node) --if abm_limiter() then return end local nu = minetest.get_node({x=pos.x, y=pos.y-1, z=pos.z}).name local is_soil = minetest.get_item_group(nu, "soil") if is_soil == 0 then return end minetest.log("action", "A sapling grows into a tree at "..minetest.pos_to_string(pos)) local vm = minetest.get_voxel_manip() local minp, maxp = vm:read_from_map({x=pos.x-16, y=pos.y, z=pos.z-16}, {x=pos.x+16, y=pos.y+16, z=pos.z+16}) local a = VoxelArea:new{MinEdge=minp, MaxEdge=maxp} local data = vm:get_data() default.grow_tree(data, a, pos, math.random(1, 4) == 1, math.random(1,100000)) vm:set_data(data) vm:write_to_map(data) vm:update_map() end }) minetest.register_abm({ label = "grow jungle sapling", nodenames = {"default:junglesapling"}, interval = 10, chance = 50, action = function(pos, node) local nu = minetest.get_node({x=pos.x, y=pos.y-1, z=pos.z}).name local is_soil = minetest.get_item_group(nu, "soil") if is_soil == 0 then return end minetest.log("action", "A jungle sapling grows into a tree at "..minetest.pos_to_string(pos)) local vm = minetest.get_voxel_manip() local minp, maxp = vm:read_from_map({x=pos.x-16, y=pos.y-1, z=pos.z-16}, {x=pos.x+16, y=pos.y+16, z=pos.z+16}) local a = VoxelArea:new{MinEdge=minp, MaxEdge=maxp} local data = vm:get_data() default.grow_jungletree(data, a, pos, math.random(1,100000)) vm:set_data(data) vm:write_to_map(data) vm:update_map() end }) -- -- Lavacooling -- default.cool_lava_source = function(pos) minetest.set_node(pos, {name="default:obsidian"}) minetest.sound_play("default_cool_lava", {pos = pos, gain = 0.25}) end default.cool_lava_flowing = function(pos) minetest.set_node(pos, {name="default:stone"}) minetest.sound_play("default_cool_lava", {pos = pos, gain = 0.25}) end minetest.register_abm({ label = "cool lava flow", nodenames = {"default:lava_flowing"}, neighbors = {"group:water"}, interval = 1, chance = 1, action = function(pos, node, active_object_count, active_object_count_wider) --if abm_limiter() then return end default.cool_lava_flowing(pos, node, active_object_count, active_object_count_wider) end, }) minetest.register_abm({ label = "cool lava source", nodenames = {"default:lava_source"}, neighbors = {"group:water"}, interval = 1, chance = 1, action = function(pos, node, active_object_count, active_object_count_wider) --if abm_limiter() then return end default.cool_lava_source(pos, node, active_object_count, active_object_count_wider) end, }) -- freeze things minetest.register_abm({ label = "freeze things", nodenames = {"group:freezes"}, neighbors = {"group:cold"}, interval = 10, chance = 4, action = function(pos, node) pos.y = pos.y + 1 if minetest.get_node(pos).name == "air" then pos.y = pos.y - 1 local new_node = minetest.registered_nodes[node.name].freezemelt if new_node ~= nil then minetest.set_node(pos,{name=new_node}) else minetest.log("error","Freezing node without freezemelt set: "..node.name) end end end }) -- melt things minetest.register_abm({ label = "melt things", nodenames = {"group:melts"}, neighbors = {"group:hot"}, interval = 10, chance = 4, action = function(pos, node) local new_node = minetest.registered_nodes[node.name].freezemelt if new_node ~= nil then minetest.set_node(pos,{name=new_node}) else minetest.log("error","Thawing node without freezemelt set: "..node.name) end end }) -- -- Papyrus and cactus growing -- minetest.register_abm({ label = "grow cactus", nodenames = {"default:cactus"}, neighbors = {"group:sand"}, interval = 50, chance = 20, action = function(pos, node) --if abm_limiter() then return end pos.y = pos.y-1 local name = minetest.get_node(pos).name if minetest.get_item_group(name, "sand") ~= 0 then pos.y = pos.y+1 local height = 0 while minetest.get_node(pos).name == "default:cactus" and height < 4 do height = height+1 pos.y = pos.y+1 end if height < 4 then if minetest.get_node(pos).name == "air" then minetest.set_node(pos, {name="default:cactus"}) end end end end, }) minetest.register_abm({ label = "grow papyrus", nodenames = {"default:papyrus"}, neighbors = {"default:dirt", "default:dirt_with_grass"}, interval = 50, chance = 20, action = function(pos, node) --if abm_limiter() then return end pos.y = pos.y-1 local name = minetest.get_node(pos).name if name == "default:dirt" or name == "default:dirt_with_grass" then if minetest.find_node_near(pos, 3, {"group:water"}) == nil then return end pos.y = pos.y+1 local height = 0 while minetest.get_node(pos).name == "default:papyrus" and height < 4 do height = height+1 pos.y = pos.y+1 end if height < 4 then if minetest.get_node(pos).name == "air" then minetest.set_node(pos, {name="default:papyrus"}) end end end end, }) -- -- Leafdecay -- -- To enable leaf decay for a node, add it to the "leafdecay" group. -- -- The rating of the group determines how far from a node in the group "tree" -- the node can be without decaying. -- -- If param2 of the node is ~= 0, the node will always be preserved. Thus, if -- the player places a node of that kind, you will want to set param2=1 or so. -- -- If the node is in the leafdecay_drop group then the it will always be dropped -- as an item default.leafdecay_trunk_cache = {} default.leafdecay_enable_cache = true -- Spread the load of finding trunks default.leafdecay_trunk_find_allow_accumulator = 0 function default.leaf_globalstep(dtime) local finds_per_second = 5000 default.leafdecay_trunk_find_allow_accumulator = math.floor(dtime * finds_per_second) end minetest.register_abm({ label = "leaf decay", nodenames = {"group:leafdecay"}, neighbors = {"air", "group:liquid"}, -- A low interval and a high inverse chance spreads the load interval = 2, chance = 5, action = function(p0, node, _, _) ----if abm_limiter() then return end --print("leafdecay ABM at "..p0.x..", "..p0.y..", "..p0.z..")") local do_preserve = false local d = minetest.registered_nodes[node.name].groups.leafdecay if not d or d == 0 then --print("not groups.leafdecay") return end local n0 = minetest.get_node(p0) if n0.param2 ~= 0 then --print("param2 ~= 0") return end local p0_hash = nil if default.leafdecay_enable_cache then p0_hash = minetest.hash_node_position(p0) local trunkp = default.leafdecay_trunk_cache[p0_hash] if trunkp then local n = minetest.get_node(trunkp) local reg = minetest.registered_nodes[n.name] -- Assume ignore is a trunk, to make the thing work at the border of the active area if n.name == "ignore" or (reg and reg.groups.tree and reg.groups.tree ~= 0) then --print("cached trunk still exists") return end --print("cached trunk is invalid") -- Cache is invalid table.remove(default.leafdecay_trunk_cache, p0_hash) end end if default.leafdecay_trunk_find_allow_accumulator <= 0 then return end default.leafdecay_trunk_find_allow_accumulator = default.leafdecay_trunk_find_allow_accumulator - 1 -- Assume ignore is a trunk, to make the thing work at the border of the active area local p1 = minetest.find_node_near(p0, d, {"ignore", "group:tree"}) if p1 then do_preserve = true if default.leafdecay_enable_cache then --print("caching trunk") -- Cache the trunk default.leafdecay_trunk_cache[p0_hash] = p1 end end if not do_preserve then -- Drop stuff other than the node itself local itemstacks = minetest.get_node_drops(n0.name) for _, itemname in pairs(itemstacks) do if minetest.get_item_group(n0.name, "leafdecay_drop") ~= 0 or itemname ~= n0.name then local p_drop = { x = p0.x - 0.5 + math.random(), y = p0.y - 0.5 + math.random(), z = p0.z - 0.5 + math.random(), } minetest.add_item(p_drop, itemname) end end -- Remove node minetest.remove_node(p0) if adventuretest.is_50 then minetest.check_for_falling(p0) else nodeupdate(p0) end end end }) function default.serialize_to_file(filename,t) local f = io.open(filename, "w") if f ~= nil then f:write(minetest.serialize(t)) f:close() else minetest.log("error","Unable to open for writing "..tostring(filename)) end end function default.deserialize_from_file(filename) local f = io.open(filename, "r") if f==nil then --minetest.log("error","File "..filename.." not found, returning empty table") return {} end local t = f:read("*all") f:close() if t=="" or t==nil then --minetest.log("error","File "..filename.." is blank, returning empty table") return {} end return minetest.deserialize(t) end function default.dump_inv(pos,listname,inv) if inv == nil then local meta = minetest.get_meta(pos) inv = meta:get_inventory() end if inv:get_list(listname) ~= nil then for i,stack in pairs(inv:get_list(listname)) do default.drop_item(pos,stack) stack:clear() inv:set_stack(listname, i, stack) end end end function default.drop_item(pos,itemstack,vel,acc) -- math.randomseed(os.time() + os.clock()) local x = math.random(0, 15)/10 - 0.5 local z = math.random(0, 15)/10 - 0.5 --local y = math.random(0, 15)/10 - 2 local np = { } np.x = pos.x + x np.z = pos.z + z np.y = pos.y + .25 local obj = minetest.add_item(np, itemstack) if obj then obj:get_luaentity().collect = true if vel ~= nil and acc ~= nil then obj:get_luaentity().object:setvelocity(vel) obj:get_luaentity().object:setacceleration(acc) end end end function default.get_distance(pos1,pos2) if ( pos1 ~= nil and pos2 ~= nil ) then return math.abs(math.floor(math.sqrt( (pos1.x - pos2.x)^2 + (pos1.z - pos2.z)^2 ))) else return nil end end function default.get_file_contents(filename) local f = io.open(filename, "r") if f==nil then minetest.log("error","File "..filename.." not found, returning empty table") return "" end local t = f:read("*all") f:close() if t=="" or t==nil then minetest.log("error","File "..filename.." is blank, returning empty table") return "" end return t end function randomChance (percent) --math.randomseed( os.clock() ) return percent >= ( math.random(1000, 100000) / 1000 ) end function default.tprint (tbl, indent) if not indent then indent = 0 end for k, v in pairs(tbl) do local formatting = string.rep(" ", indent) .. k .. ": " if type(v) == "table" then print(formatting) default.tprint(v, indent+1) elseif type(v) == 'boolean' then print(formatting .. tostring(v)) else print(formatting .. v) end end end