-- 2D noise for coldness local np_cold = { offset = 0, scale = 1, spread = {x=150, y=150, z=150}, seed = 112, octaves = 3, persist = 0.5 } -- 2D noise for icetype local np_ice = { offset = 0, scale = 1, spread = {x=80, y=80, z=80}, seed = 322345, octaves = 3, persist = 0.5 } -- Debugging function local biome_to_string = function(num,num2) local biome, biome2 if num == 1 then biome = "snowy" elseif num == 2 then biome = "plain" elseif num == 3 then biome = "alpine" elseif num == 4 or num == 5 then biome = "normal" else biome = "unknown "..num end if num2 == 1 then biome2 = "cool" elseif num2 == 2 then biome2 = "icebergs" elseif num2 == 3 then biome2 = "icesheet" elseif num2 == 4 then biome2 = "icecave" elseif num2 == 5 then biome2 = "icehole" else biome2 = "unknown "..num end return biome, biome2 end -- On generated function minetest.register_on_generated(function(minp, maxp, seed) local t1 = os.clock() local x0 = minp.x local z0 = minp.z local x1 = maxp.x local z1 = maxp.z local debug = snow.debug local min_height = snow.min_height local spawn_pine = snow.voxelmanip_pine local smooth = snow.smooth_biomes local legacy = snow.legacy local c_dirt_with_grass = minetest.get_content_id("default:dirt_with_grass") local c_dirt = minetest.get_content_id("default:dirt") local c_tree = minetest.get_content_id("default:tree") local c_apple = minetest.get_content_id("default:apple") local c_snow = minetest.get_content_id("default:snow") local c_snow_block = minetest.get_content_id("default:snowblock") local c_dirt_with_snow = minetest.get_content_id("default:dirt_with_snow") local c_air = minetest.get_content_id("air") local c_ignore = minetest.get_content_id("ignore") local c_stone = minetest.get_content_id("default:stone") local c_dry_shrub = minetest.get_content_id("default:dry_shrub") local c_leaves = minetest.get_content_id("default:leaves") local c_jungleleaves = minetest.get_content_id("default:jungleleaves") local c_junglegrass = minetest.get_content_id("default:junglegrass") local c_ice = minetest.get_content_id("default:ice") local c_water = minetest.get_content_id("default:water_source") local c_papyrus = minetest.get_content_id("default:papyrus") local c_sand = minetest.get_content_id("default:sand") local vm = minetest.get_voxel_manip() local emin, emax = vm:read_from_map(minp, maxp) local area = VoxelArea:new({MinEdge=emin, MaxEdge=emax}) local data = vm:get_data() local sidelen = x1 - x0 + 1 local chulens = {x=sidelen, y=sidelen, z=sidelen} local minpos = {x=x0, y=z0} local nvals_cold = minetest.get_perlin_map(np_cold, chulens):get2dMap_flat({x=x0, y=z0}) local nvals_ice = minetest.get_perlin_map(np_ice, chulens):get2dMap_flat({x=x0, y=z0}) -- Choose biomes local pr = PseudoRandom(seed+57) local biome local biome2 -- Land biomes biome = pr:next(1, 5) local snowy = biome == 1 -- spawns alot of snow local plain = biome == 2 -- spawns not much local alpine = biome == 3 -- rocky terrain -- Water biomes biome2 = pr:next(1, 5) local cool = biome == 1 -- only spawns ice on edge of water local icebergs = biome == 2 local icesheet = biome == 3 local icecave = biome == 4 local icehole = biome == 5 -- icesheet with holes -- Misc biome settings local icy = pr:next(1, 2) == 2 -- if enabled spawns ice in sand instead of snow blocks local mossy = pr:next(1,2) == 1 -- spawns moss in snow local shrubs = pr:next(1,2) == 1 -- spawns dry shrubs in snow local pines = pr:next(1,2) == 1 -- spawns pines -- Reseed random pr = PseudoRandom(seed+68) -- Loop through columns in chunk local write_to_map = false local ni = 1 for z = z0, z1 do for x = x0, x1 do local in_biome = false local test = nvals_cold[ni] if smooth and (not snowy) and (test > 0.73 or (test > 0.43 and pr:next(0,29) > (0.73 - test) * 100 )) then in_biome = true elseif (not smooth or snowy) and test > 0.53 then in_biome = true end if not in_biome then if alpine == true and test > 0.43 then local ground_y = nil for y = maxp.y, minp.y, -1 do local nodid = data[area:index(x, y, z)] if nodid ~= c_air and nodid ~= c_ignore then ground_y = y break end end if ground_y then local vi = area:index(x, ground_y, z) if data[vi] == c_leaves or data[vi] == c_jungleleaves then for y = ground_y, -16, -1 do local vi = area:index(x, y, z) if data[vi] ~= c_leaves and data[vi] ~= c_jungleleaves and data[vi] ~= c_tree and data[vi] ~= c_air and data[vi] ~= c_apple then break else data[vi] = c_air end end end end end elseif in_biome then write_to_map = true local icetype = nvals_ice[ni] local cool = icetype > 0 local icebergs = icetype > -0.2 and icetype <= 0 local icehole = icetype > -0.4 and icetype <= -0.2 local icesheet = icetype > -0.6 and icetype <= -0.4 local icecave = icetype <= -0.6 local ground_y = nil for y = maxp.y, minp.y, -1 do local nodid = data[area:index(x, y, z)] if nodid ~= c_air and nodid ~= c_ignore then ground_y = y break end end if ground_y then local node = area:index(x, ground_y, z) local abovenode = area:index(x, ground_y+1, z) local belownode = area:index(x, ground_y-1, z) if ground_y and data[node] == c_dirt_with_grass then if alpine and test > 0.53 then data[abovenode] = c_snow for y = ground_y, -6, -1 do local vi = area:index(x, y, z) if data[vi] == c_stone then break else data[vi] = c_stone end end elseif (shrubs and pr:next(1,28) == 1) then data[node] = c_dirt_with_snow data[abovenode] = c_dry_shrub elseif pines and pr:next(1,36) == 1 then data[node] = c_dirt_with_snow spawn_pine({x=x, y=ground_y+1, z=z}, area, data) elseif snowy and test > 0.63 then data[abovenode] = c_snow_block else data[node] = c_dirt_with_snow data[abovenode] = c_snow end elseif ground_y and data[node] == c_sand then if not icy then data[abovenode] = c_snow else data[node] = c_ice end elseif ground_y and data[node] == c_leaves or data[node] == c_jungleleaves or data[node] == c_apple then if alpine then data[abovenode] = c_snow for y = ground_y, -6, -1 do local stone = area:index(x, y, z) if data[stone] == c_stone then break else data[stone] = c_stone end end else data[abovenode] = c_snow end elseif ground_y and data[node] == c_junglegrass then data[node] = c_dry_shrub elseif ground_y and data[node] == c_papyrus then for y = ground_y, ground_y-4, -1 do local vi = area:index(x, y, z) if data[vi] == c_papyrus then local via = area:index(x, ground_y, z) data[via] = c_snow data[vi] = c_snow_block end end elseif ground_y and data[node] == c_water then if not icesheet and not icecave and not icehole then local x1 = data[area:index(x+1, ground_y, z)] local z1 = data[area:index(x, ground_y, z+1)] local xz1 = data[area:index(x+1, ground_y, z+1)] local xz2 = data[area:index(x-1, ground_y, z-1)] local x2 = data[area:index(x-1, ground_y, z)] local z2 = data[area:index(x, ground_y, z-1)] local y = data[area:index(x, ground_y-1, z)] local rand = pr:next(1,4) == 1 if ((x1 and x1 ~= c_water and x1 ~= c_ice and x1 ~= c_air and x1 ~= c_ignore) or ((cool or icebergs) and x1 == c_ice and rand)) or ((z1 and z1 ~= c_water and z1 ~= c_ice and z1 ~= c_air and z1 ~= c_ignore) or ((cool or icebergs) and z1 == c_ice and rand)) or ((xz1 and xz1 ~= c_water and xz1 ~= c_ice and xz1 ~= c_air and xz1 ~= c_ignore) or ((cool or icebergs) and xz1 == c_ice and rand)) or ((xz2 and xz2 ~= c_water and xz2 ~= c_ice and xz2 ~= c_air and xz2 ~= c_ignore) or ((cool or icebergs) and xz2 == c_ice and rand)) or ((x2 and x2 ~= c_water and x2 ~= c_ice and x2 ~= c_air and x2 ~= c_ignore) or ((cool or icebergs) and x2 == c_ice and rand)) or ((z2 and z2 ~= c_water and z2 ~= c_ice and z2 ~= c_air and z2 ~= c_ignore) or ((cool or icebergs) and z2 == c_ice and rand)) or (y ~= c_water and y ~= c_ice and y ~= "air") or (pr:next(1,6) == 1 and icebergs) then data[node] = c_ice end else if (icehole and pr:next(1,10) > 1) or icecave or icesheet then data[node] = c_ice end if icecave then for y = ground_y-1, -33, -1 do local vi = area:index(x, y, z) if data[vi] ~= c_water then break else data[vi] = c_air end end end end end end end ni = ni + 1 end end vm:set_data(data) vm:set_lighting({day=0, night=0}) vm:calc_lighting() vm:write_to_map() if write_to_map and debug then -- print if any column of mapchunk was snow biome local biome_string,biome2_string = biome_to_string(biome,biome2) local chugent = math.ceil((os.clock() - t1) * 1000) print("[snow] "..biome_string.." and "..biome2_string.." x "..minp.x.." z "..minp.z.." time "..chugent.." ms") end end)