-- 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_strings = { {"snowy", "plain", "alpine", "normal", "normal"}, {"cool", "icebergs", "icesheet", "icecave", "icehole"} } local function biome_to_string(num,num2) local biome = biome_strings[1][num] or "unknown "..num return biome end local function do_ws_func(a, x) local n = x/(16000) local y = 0 for k=1,1000 do y = y + 1000*(math.sin(math.pi * k^a * n)/(math.pi * k^a)) end return y end local ws_lists = {} local function get_ws_list(a,x) ws_lists[a] = ws_lists[a] or {} local v = ws_lists[a][x] if v then return v end v = {} for x=x,x + (80 - 1) do local y = do_ws_func(a, x) v[x] = y end ws_lists[a][x] = v return v 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 spawn_pine = snow.voxelmanip_pine local smooth = snow.smooth_biomes 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, emin, emax = minetest.get_mapgen_object("voxelmanip") local area = VoxelArea:new({MinEdge=emin, MaxEdge=emax}) local data = vm:get_data() local snow_tab,num = {},1 local sidelen = x1 - x0 + 1 local chulens = {x=sidelen, y=sidelen, z=sidelen} 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) -- Land biomes local biome = pr:next(1, 5) local snowy = biome == 1 -- spawns snow local alpine = biome == 3 -- rocky terrain -- Misc biome settings local icy = pr:next(1, 2) == 2 -- if enabled spawns ice in sand instead of snow blocks 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 = math.min(nvals_cold[ni], 1) if smooth and not snowy then if (test > 0.73 or (test > 0.43 and pr:next(0,29) > (0.73 - test) * 100 )) then in_biome = true end elseif test > 0.53 then in_biome = true end if not in_biome then if alpine and test > 0.43 then -- remove trees near alpine 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) local id = data[vi] if id ~= c_air then if id == c_leaves or id == c_jungleleaves or id == c_tree or id == c_apple then data[vi] = c_air else break end end end end end end else write_to_map = true local icetype = nvals_ice[ni] local cool = icetype > 0 -- only spawns ice on edge of water local icebergs = icetype > -0.2 and icetype <= 0 local icehole = icetype > -0.4 and icetype <= -0.2 -- icesheet with holes local icesheet = icetype > -0.6 and icetype <= -0.4 local icecave = icetype <= -0.6 local ground_y 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 c_ground = data[node] local abovenode = area:index(x, ground_y+1, z) if c_ground == c_dirt_with_grass then if alpine and test > 0.53 then snow_tab[num] = {abovenode, z, x, test} num = num+1 -- generate stone ground for y = ground_y, math.max(-6, minp.y-6), -1 do local vi = area:index(x, y, z) if data[vi] == c_stone then break end data[vi] = c_stone 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) else data[node] = c_dirt_with_snow snow_tab[num] = {abovenode, z, x, test} num = num+1 end elseif c_ground == c_sand then if icy then data[node] = c_ice end snow_tab[num] = {abovenode, z, x, test} num = num+1 elseif c_ground == c_leaves or c_ground == c_jungleleaves or c_ground == c_apple then if alpine then snow_tab[num] = {abovenode, z, x, test} num = num+1 -- make stone pillars out of trees for y = ground_y, math.max(-6, minp.y-6), -1 do local stone = area:index(x, y, z) if data[stone] == c_stone then break end data[stone] = c_stone end else -- put snow onto leaves snow_tab[num] = {abovenode, z, x, test} num = num+1 end elseif c_ground == c_junglegrass then data[node] = c_dry_shrub elseif c_ground == c_papyrus then snow_tab[num] = {abovenode, z, x, test} num = num+1 -- replace papyrus plants with snowblocks local y = ground_y for _ = 1,7 do local vi = area:index(x, y, z) if data[vi] == c_papyrus then data[vi] = c_snow_block y = y-1 else break end end elseif c_ground == c_water then if not icesheet and not icecave and not icehole then local nds = { data[area:index(x+1, ground_y, z)], data[area:index(x, ground_y, z+1)], data[area:index(x+1, ground_y, z+1)], data[area:index(x-1, ground_y, z-1)], data[area:index(x-1, ground_y, z)], data[area:index(x, ground_y, z-1)], } local ice if pr:next(1,4) == 1 and (cool or icebergs) then for _,i in ipairs(nds) do if i == c_ice then ice = true break end end end if not ice then for _,i in ipairs(nds) do if i ~= c_water and i ~= c_ice and i ~= c_air and i ~= c_ignore then ice = true break end end end local y = data[area:index(x, ground_y-1, z)] if ice or (y ~= c_water and y ~= c_ice) -- and y ~= "air") …I don't think y can be a string here ~HybridDog or (icebergs and pr:next(1,6) == 1) then data[node] = c_ice end else if icesheet or icecave or (icehole and pr:next(1,10) > 1) 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 end data[vi] = c_air end end if icesheet then -- put snow onto icesheets snow_tab[num] = {abovenode, z, x, test} num = num+1 end end end end end ni = ni + 1 end end local param2s if num ~= 1 then local wsz, wsx for _,i in pairs(snow_tab) do local p,z,x,test = unpack(i) -- snow is set data[p] = c_snow test = (test-0.73)/0.27 -- /(1-0.73) if test > 0 then local maxh = math.floor(test*10)%10+1 if maxh ~= 1 then if not wsz then wsz = get_ws_list(5, z0) wsx = get_ws_list(2, x0) end local h = math.floor(wsx[x]+wsz[z]*5)%10+1 if h ~= 1 then if h == 10 then -- make snowdrifts walkable h = 5 end h = math.min(maxh, h) if h == 9 then -- replace the snow with a snowblock because its a full node data[p] = c_snow_block else -- set a specific snow height if not param2s then param2s = vm:get_param2_data() end param2s[p] = h*7 end end end end end end vm:set_data(data) if param2s then vm:set_param2_data(param2s) end vm:set_lighting({day=0, night=0}) vm:calc_lighting() vm:write_to_map() if write_to_map and snow.debug then -- print if any column of mapchunk was snow biome local biome_string = biome_to_string(biome) local chugent = math.ceil((os.clock() - t1) * 1000) print("[snow] "..biome_string.." x "..minp.x.." z "..minp.z.." time "..chugent.." ms") end end)