-- Squaresville deco.lua -- Copyright Duane Robertson (duane@duanerobertson.com), 2017 -- Distributed under the LGPLv2.1 (https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html) local dangerous = squaresville.dangerous_terrain squaresville.decorations = {} squaresville.decorations_schem = {} local math_abs = math.abs local math_floor = math.floor for i = 2, 4 do minetest.register_decoration({ deco_type = "schematic", place_on = {"default:dirt_with_snow", "default:dirt_with_grass"}, sidelen = 16, noise_params = { offset = 0.012, scale = 0.022, spread = {x = 250, y = 250, z = 250}, seed = (84 - 7 * i), octaves = 3, persist = 0.66 }, biomes = {"taiga", "coniferous_forest", "floatland_coniferous_forest"}, y_min = 2, y_max = 31000, schematic = squaresville.path .. "/schematics/pine_tree"..i..".mts", flags = "place_center_x, place_center_z", }) minetest.register_decoration({ deco_type = "schematic", place_on = {"default:dirt_with_grass"}, sidelen = 16, noise_params = { offset = 0.012, scale = 0.022, spread = {x = 250, y = 250, z = 250}, seed = (139 - 7 * i), octaves = 3, persist = 0.66 }, biomes = {"deciduous_forest", 'desertstone_grassland'}, y_min = 1, y_max = 31000, schematic = squaresville.path .. "/schematics/apple_tree"..i..".mts", flags = "place_center_x, place_center_z", rotation = "random", }) end minetest.register_decoration({ deco_type = "schematic", place_on = {"default:dirt_with_grass"}, sidelen = 16, noise_params = { offset = 0, scale = 0.022, spread = {x = 250, y = 250, z = 250}, seed = 119, octaves = 3, persist = 0.66 }, biomes = {"deciduous_forest"}, y_min = 1, y_max = 31000, schematic = squaresville.path .. "/schematics/cherry_tree.mts", flags = "place_center_x, place_center_z", rotation = "random", }) minetest.register_decoration({ deco_type = "schematic", place_on = {"default:polluted_dirt"}, sidelen = 16, noise_params = { offset = 0.036, scale = 0.022, spread = {x = 250, y = 250, z = 250}, seed = 666, octaves = 3, persist = 0.66 }, biomes = {"toxic_forest"}, y_min = 1, y_max = 31000, schematic = squaresville.path .. "/schematics/decaying_tree.mts", flags = "place_center_x, place_center_z", rotation = "random", }) do for _, odeco in pairs(minetest.registered_decorations) do local deco = table.copy(odeco) deco.place_on = table.copy(odeco.place_on) deco.flags = {} if odeco.biomes then deco.biomes = {} for _, b in pairs(odeco.biomes) do deco.biomes[b] = true end end if odeco.flags then for f in odeco.flags:gmatch('[%w_]+') do deco.flags[f] = true end end local nod = minetest.registered_nodes[deco.decoration] if nod and nod.groups and nod.groups.flower then deco.flower = true end if odeco.schematic then deco.name = odeco.schematic:match('([%w_]+)%.mts') or odeco.schematic elseif odeco.decoration and type(odeco.decoration) == 'string' then deco.name = odeco.decoration:match('.*:([%w_]+)') or odeco.decoration end if deco.name == 'apple_tree' or deco.name == 'pine_tree' then deco.noise_params.offset = 0.012 if deco.name == 'apple_tree' then deco.biomes['desertstone_grassland'] = true end elseif deco.name == 'junglegrass' then deco.biomes['desertstone_grassland'] = true deco.place_on[#deco.place_on+1] = 'default:dirt_with_grass' elseif deco.name == 'jungle_tree' then deco.schematic = squaresville.path..'/schematics/jungle_tree_with_orchids.mts' end squaresville.decorations[#squaresville.decorations+1] = deco end end squaresville.biomes = {} local biomes = squaresville.biomes local biome_names = {} do local biome_mod = { tundra = { node_top = 'default:snowblock', depth_top = 1 }, rainforest = { civ = 'desertstone_grassland' }, } for i, obiome in pairs(minetest.registered_biomes) do local biome = table.copy(obiome) biomes[biome.name] = biome biome_names[#biome_names+1] = biome.name -- Make changes to biome values from biome_mod. for n, bi in pairs(biome_mod) do for i, rbi in pairs(biomes) do if rbi.name == n then for j, prop in pairs(bi) do biomes[i][j] = prop end end end end end biomes["desertstone_grassland"] = { name = "desertstone_grassland", --node_dust = "", node_top = "default:dirt_with_grass", depth_top = 1, node_filler = "default:dirt", depth_filler = 1, node_stone = "default:desert_stone", node_riverbed = "default:sand", depth_riverbed = 2, --node_water_top = "", --depth_water_top = , --node_water = "", --node_river_water = "", y_min = squaresville.max_height, y_max = squaresville.max_height, heat_point = 86, humidity_point = 50, } if dangerous then biomes["toxic_forest"] = { name = "toxic_forest", node_top = "squaresville:polluted_dirt", danger = 3, depth_top = 1, node_filler = "squaresville:polluted_dirt", depth_filler = 1, node_riverbed = "squaresville:polluted_dirt", depth_riverbed = 1, node_water = "squaresville:water_poison_source", node_river_water = "squaresville:water_poison_source", special_trees = {"decaying_tree"}, y_min = 1, y_max = squaresville.max_height, heat_point = 20, humidity_point = 50, } biomes["toxic_forest_ocean"] = { name = "toxic_forest_ocean", node_top = "squaresville:polluted_dirt", danger = 3, depth_top = 1, node_filler = "squaresville:polluted_dirt", depth_filler = 1, node_riverbed = "squaresville:polluted_dirt", depth_riverbed = 1, node_water = "squaresville:water_poison_source", node_river_water = "squaresville:water_poison_source", y_min = -10, y_max = 0, heat_point = 20, humidity_point = 50, } biomes["draconic"] = { name = "draconic", --node_dust = "", node_top = "squaresville:cracked_stone", depth_top = 1, node_filler = "squaresville:granite", depth_filler = 1, node_stone = "squaresville:granite", --node_water_top = "", --depth_water_top = , --node_water = "", node_river_water = "squaresville:basalt", node_riverbed = "squaresville:basalt", depth_riverbed = 2, danger = 3, y_min = 1, y_max = squaresville.max_height, heat_point = 80, humidity_point = 20, } biomes["draconic_ocean"] = { name = "draconic_ocean", --node_dust = "", node_top = "squaresville:granite", depth_top = 1, danger = 3, node_filler = "squaresville:granite", depth_filler = 3, node_stone = "squaresville:granite", y_min = -20, y_max = 0, heat_point = 80, humidity_point = 20, } biomes["bizarre"] = { name = "bizarre", --node_dust = "", node_top = "squaresville:dirt_with_odd_grass", depth_top = 1, node_filler = "default:dirt", depth_filler = 1, node_stone = "squaresville:basalt", --node_water_top = "", --depth_water_top = , --node_water = "", --node_river_water = "squaresville:basalt", --node_riverbed = "squaresville:basalt", --depth_riverbed = 2, special_trees = {'fur_tree'}, danger = 3, y_min = 1, y_max = squaresville.max_height, heat_point = 60, humidity_point = 70, } biomes["bizarre_ocean"] = { name = "bizarre_ocean", --node_dust = "", node_top = "default:sand", depth_top = 1, danger = 3, node_filler = "default:sand", depth_filler = 3, node_stone = "squaresville:basalt", y_min = -20, y_max = 0, heat_point = 60, humidity_point = 70, } end end local function register_flower(name, desc, biomes, seed) local groups = {} groups.snappy = 3 groups.flammable = 2 groups.flower = 1 groups.flora = 1 groups.attached_node = 1 minetest.register_node("squaresville:" .. name, { description = desc, drawtype = "plantlike", waving = 1, tiles = {"squaresville_" .. name .. ".png"}, inventory_image = "squaresville_" .. name .. ".png", wield_image = "squaresville_" .. name .. ".png", sunlight_propagates = true, paramtype = "light", walkable = false, buildable_to = true, stack_max = 99, groups = groups, sounds = default.node_sound_leaves_defaults(), selection_box = { type = "fixed", fixed = {-0.5, -0.5, -0.5, 0.5, -5/16, 0.5}, } }) local bi = {} if biomes then bi = {} for _, b in pairs(biomes) do bi[b] = true end end local def = { deco_type = "simple", place_on = {"default:dirt_with_grass", 'default:dirt_with_rainforest_litter'}, sidelen = 16, noise_params = { offset = -0.015, scale = 0.025, spread = {x = 200, y = 200, z = 200}, seed = seed, octaves = 3, persist = 0.6 }, biomes = bi, y_min = 1, y_max = 31000, decoration = "squaresville:"..name, name = name, flower = true, } squaresville.decorations[#squaresville.decorations+1] = def if bi['rainforest'] then def = table.copy(def) def.noise_params = table.copy(def.noise_params) def.noise_params.offset = 0.015 def.place_on = {'default:dirt_with_rainforest_litter'} def.biomes = {['rainforest'] = true, ['rainforest_swamp'] = true} squaresville.decorations[#squaresville.decorations+1] = def end end register_flower("orchid", "Orchid", {"rainforest", "rainforest_swamp"}, 783) register_flower("bird_of_paradise", "Bird of Paradise", {"rainforest", "desertstone_grassland"}, 798) register_flower("gerbera", "Gerbera", {"savanna", "rainforest", "desertstone_grassland"}, 911) local function register_decoration(deco, place_on, biomes, chance) local bi = {} if biomes then bi = {} for _, b in pairs(biomes) do bi[b] = true end end squaresville.decorations[#squaresville.decorations+1] = { deco_type = "simple", place_on = place_on, sidelen = 16, biomes = bi, fill_ratio = chance, y_min = 1, y_max = 31000, decoration = deco, name = deco:match('[^:]+$'), } end if dangerous then --register_decoration('default:lava_source', 'squaresville:cracked_stone', {'draconic'}, 0.0005) register_decoration('squaresville:blackened_shrub', 'squaresville:polluted_dirt', {'toxic_forest'}, 0.05) register_decoration('flowers:mushroom_red', 'squaresville:polluted_dirt', {'toxic_forest'}, 0.05) register_decoration('squaresville:strange_plant_1', 'squaresville:dirt_with_odd_grass', {'bizarre'}, 0.05) register_decoration('squaresville:strange_plant_2', 'squaresville:dirt_with_odd_grass', {'bizarre'}, 0.05) for i = 1, 4 do register_decoration('squaresville:stone_spike_'..i, 'squaresville:cracked_stone', {'draconic'}, 0.02 / i) end end local function place_deco(mg, ps, deco) local data, a = mg.data, mg.area local minp, maxp = mg.minp, mg.maxp local heightmap, biomemap, schem = mg.heightmap, mg.biomemap, mg.schem local csize = mg.csize local sidelen = deco.sidelen or csize.x local node = squaresville.node local max_height = squaresville.max_height local node_air = node['air'] local node_ignore = node['ignore'] local node_water = node['default:water_source'] if csize.x % sidelen ~= 0 then sidelen = csize.x end local divlen = csize.x / sidelen local area = sidelen * sidelen for z0 = 0, divlen-1 do for x0 = 0, divlen-1 do local center = { x=math_floor(minp.x + sidelen / 2 + sidelen * x0), z=math_floor(minp.z + sidelen / 2 + sidelen * z0), } local min = { x=minp.x + sidelen * x0, z=minp.z + sidelen * z0, } local max = { x=minp.x + sidelen + sidelen * x0 - 1, z=minp.z + sidelen + sidelen * z0 - 1, } local nval = deco.noise_params and minetest.get_perlin(deco.noise_params):get2d({x=center.x, y=center.z}) or deco.fill_ratio local deco_count = area * nval if deco_count > 1 then deco_count = math_floor(deco_count) elseif deco_count > 0 then if ps:next(1, 1000) <= deco_count * 1000 then deco_count = 1 else deco_count = 0 end end for i = 1, deco_count do local x = ps:next(min.x, max.x) local z = ps:next(min.z, max.z) local mapindex = csize.x * (z - minp.z) + (x - minp.x) + 1 local y = -squaresville.max_height if deco.liquid_surface then print('Squaresville: Invalid liquid_surface parameter') --y = find_liquid_surface() elseif heightmap then y = heightmap[mapindex] else print('Squaresville: Cannot generate heightmap') --y = find_ground() end if y > -max_height and y < max_height and y >= minp.y and y <= maxp.y and y - mg.baseline >= (deco.y_min or -max_height) and y - mg.baseline <= (deco.y_max or max_height) then local biome if biomemap then biome = biomemap[mapindex] end if not deco.biomes or deco.biomes[biome.name] then local ivm = a:index(x, y, z) if (not deco.place_on) or deco.place_on[data[ivm]] then ivm = ivm + a.ystride if deco.deco_type == 'schematic' then local too_close local size_s = deco.size_offset and ((deco.size_offset.x + 1) * (deco.size_offset.z + 1)) or 9 for _, s in ipairs(schem) do local dx, dz = s.pos.x - x, s.pos.z - z if dx * dx + dz * dz <= size_s then too_close = true break end end if not too_close then schem[#schem+1] = {def=deco, pos={x=x,y=y,z=z}} end elseif data[ivm] == node_air then data[ivm] = node[deco.decoration] end end end end end end end end local first_check = true function squaresville.place_all_decorations(mg) local ps = PcgRandom(mg.seed + 53) for i, deco in pairs(squaresville.decorations) do if first_check and deco.place_on then local new_p = {} if type(deco.place_on) ~= 'table' then deco.place_on = {deco.place_on} end for i, d in ipairs(deco.place_on) do if type(d) == 'string' then new_p[squaresville.node[d]] = squaresville.node[d] end end deco.place_on = new_p end place_deco(mg, ps, deco) end first_check = nil end -- This lets rarer spawns overwrite the more common. table.sort(squaresville.decorations, function(a, b) if a.fill_ratio and b.fill_ratio and a.fill_ratio < b.fill_ratio then return true elseif a.fill_ratio and not b.fill_ratio then return true elseif b.fill_ratio and not a.fill_ratio then return false elseif not (a.fill_ratio or b.fill_ratio) and a.noise_params and b.noise_params and a.noise_params.scale + a.noise_params.offset > b.noise_params.scale + b.noise_params.offset then return true else return false end end)