diff --git a/README.md b/README.md index 7c46bd9..3a2fca9 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,13 @@ # loud_walking -Minetest pod-based mapgen + +Loud Walking is a play on the name of an old science fiction movie about an attempt to preserve Earth's endangered life in sealed pods in space. This mod creates pods with more or less normal terrain inside, including vegetation and minerals. Eventually they'll have a variety of biomes inside. It's unusual in being fully three-dimensional. There are pods above, pods below, pods to all sides, and they all work basically the same. Bridges are provided to move horizontally. Moving vertically is more challenging. + +![screenshot](https://github.com/duane-r/loud_walking/raw/master/textures/screenshot02.jpg) + +The source is available on github. + +Code: CC0 and others, textures: CC0 and others + +Mod dependencies: default + +Download: https://github.com/duane-r/loud_walking/archive/master.zip diff --git a/deco.lua b/deco.lua new file mode 100644 index 0000000..7e9b3ba --- /dev/null +++ b/deco.lua @@ -0,0 +1,75 @@ +----------------- +-- Decorations -- +----------------- + +-- The main decoration handler, through the game's decoration manager. + + +function table.contains_substring(t, s) + if type(s) ~= "string" then + return nil + end + + for key, value in pairs(t) do + if type(value) == 'string' and s:find(value) then + if key then + return key + else + return true + end + end + end + return false +end + + +-- Copy all the decorations except the ones I don't like. +-- This is currently used to remove the default trees. +local bad_deco = {"apple_tree", "pine_tree", "jungle_tree", "acacia_tree", "aspen_tree", } +local decos = {} +for id, deco_table in pairs(minetest.registered_decorations) do + if type(deco_table.schematic) ~= "string" or not table.contains_substring(bad_deco, deco_table.schematic) then + table.insert(decos, deco_table) + end +end + + +-- Create and initialize a table for a schematic. +function loud_walking.schematic_array(width, height, depth) + -- Dimensions of data array. + local s = {size={x=width, y=height, z=depth}} + s.data = {} + + for z = 0,depth-1 do + for y = 0,height-1 do + for x = 0,width-1 do + local i = z*width*height + y*width + x + 1 + s.data[i] = {} + s.data[i].name = "air" + s.data[i].param1 = 000 + end + end + end + + s.yslice_prob = {} + + return s +end + + +-- Clear all decorations, so I can place the new trees. +minetest.clear_registered_decorations() + +-- A list of all schematics, for re-use. +loud_walking.schematics = {} + + +dofile(loud_walking.path.."/deco_trees.lua") + + +-- Re-register the good decorations. +-- This has to be done after registering the trees or +-- the trees spawn on top of grass. /shrug +for _, i in pairs(decos) do + minetest.register_decoration(i) +end diff --git a/deco_conifer.lua b/deco_conifer.lua new file mode 100644 index 0000000..aa98be7 --- /dev/null +++ b/deco_conifer.lua @@ -0,0 +1,193 @@ +------------------- +-- Conifer Trees -- +------------------- + +-- Create different colored needles with the same properties. +newnode = loud_walking.clone_node("default:pine_needles") +if loud_walking.noleafdecay then + newnode.groups.leafdecay = 0 +end +newnode.tiles = {"default_pine_needles.png^[colorize:#FF0000:20"} +minetest.register_node("loud_walking:pine_needles2", newnode) +newnode.tiles = {"default_pine_needles.png^[colorize:#FFFF00:20"} +minetest.register_node("loud_walking:pine_needles3", newnode) +newnode.tiles = {"default_pine_needles.png^[colorize:#00FF00:20"} +minetest.register_node("loud_walking:pine_needles4", newnode) + +if loud_walking.glow then + minetest.register_node("loud_walking:pine_tree_glowing_moss", { + description = "Pine tree with glowing moss", + tiles = {"default_pine_tree_top.png", "default_pine_tree_top.png", + "default_pine_tree.png^trunks_moss.png"}, + paramtype2 = "facedir", + is_ground_content = false, + light_source = 4, + drop = 'default:pine_tree', + groups = {tree = 1, choppy = 2, oddly_breakable_by_hand = 1, flammable = 2}, + sounds = default.node_sound_wood_defaults(), + + on_place = minetest.rotate_node + }) +end + + +-- similar to the general tree schematic, but basically vertical +function loud_walking.generate_conifer_schematic(trunk_height, radius, trunk, leaf) + local height = trunk_height + radius * 3 + 2 + local width = 2 * radius + 1 + local trunk_top = height - radius - 1 + local s = loud_walking.schematic_array(width, height, width) + + -- the main trunk + local probs = {200,150,100,75,50,25} + for z = -radius,radius do + for y = 1,trunk_top do + -- Gives it a vaguely conical shape. + local r1 = math.ceil((height - y) / 4) + -- But rounded at the bottom. + if y == trunk_height + 1 then + r1 = r1 -1 + end + + for x = -radius,radius do + local i = (z+radius)*width*height + y*width + (x+radius) + 1 + local dist = math.floor(math.sqrt(x^2 + z^2 + 0.5)) + if x == 0 and z == 0 then + if trunk == "default:pine_tree" and loud_walking.glow and math.random(1,10) == 1 then + s.data[i].name = "loud_walking:pine_tree_glowing_moss" + else + s.data[i].name = trunk + end + s.data[i].param1 = 255 + s.data[i].force_place = true + elseif y > trunk_height and dist <= r1 then + s.data[i].name = leaf + s.data[i].param1 = probs[dist] + end + end + end + end + + -- leaves at the top + for z = -1,1 do + for y = trunk_top, height-1 do + for x = -1,1 do + local i = (z+radius)*width*height + y*width + (x+radius) + 1 + if (x == 0 and z == 0) or y < height - 1 then + s.data[i].name = leaf + if x == 0 and z == 0 then + s.data[i].param1 = 255 + else + s.data[i].param1 = 200 + end + end + end + end + end + + return s +end + + +-- the default pine schematic +function loud_walking.generate_default_conifer_schematic(trunk, leaf) + local height = 13 + 1 + local width = 5 + local s = loud_walking.schematic_array(width, height, width) + + -- the main trunk + local probs = {255,220,190} + + for p = 0,2 do + local c = math.floor(width / 2) + local y = height - p * 3 - 1 + for r = 0,2 do + for z = c-r,c+r do + for x = c-r,c+r do + local i = z*width*height + (y-r)*width + x + 1 + s.data[i].name = leaf + s.data[i].param1 = probs[r] + end + end + end + + s.yslice_prob = {} + for y = 1,height-3 do + local i = 2*width*height + y*width + 2 + 1 + if trunk == "default:pine_tree" and loud_walking.glow and math.random(1,10) == 1 then + s.data[i].name = "loud_walking:pine_tree_glowing_moss" + else + s.data[i].name = trunk + end + + s.data[i].param1 = 255 + s.data[i].force_place = true + + local j = (height - y - 1) / 3 + if j == 0 or j == 1 or j == 2 or y <= height - 11 then + s.yslice_prob[#s.yslice_prob+1] = {ypos=y,prob=170} + end + end + end + + return s +end + + +-- generic conifers +loud_walking.schematics.conifer_trees = {} +leaves = {"default:pine_needles", "loud_walking:pine_needles2", "loud_walking:pine_needles3", "loud_walking:pine_needles4"} +for i = 1,#leaves do + local max_r = 4 + for r = 2,max_r do + local schem = loud_walking.generate_conifer_schematic(2, r, "default:pine_tree", leaves[i]) + + loud_walking.schematics.conifer_trees[#loud_walking.schematics.conifer_trees+1] = schem + + --minetest.register_decoration({ + -- deco_type = "schematic", + -- sidelen = 80, + -- place_on = {"default:dirt_with_snow", "default:dirt_with_grass"}, + -- fill_ratio = (max_r-r+1)/500, + -- biomes = {"coniferous_forest", "taiga",}, + -- schematic = schem, + -- flags = "place_center_x, place_center_z", + -- y_min = 2, + -- rotation = "random", + --}) + end +end + + +if false then + -- generic conifers + loud_walking.schematics.conifer_trees = {} + leaves = {"default:pine_needles", "loud_walking:pine_needles2", "loud_walking:pine_needles3", "loud_walking:pine_needles4"} + for i = 1,#leaves do + local schem = loud_walking.generate_default_conifer_schematic("default:pine_tree", leaves[i]) + + loud_walking.schematics.conifer_trees[#loud_walking.schematics.conifer_trees+1] = schem + + minetest.register_decoration({ + deco_type = "schematic", + sidelen = 80, + place_on = {"default:dirt_with_snow", "default:dirt_with_grass"}, + fill_ratio = 6/500, + biomes = {"coniferous_forest", "taiga",}, + schematic = schem, + flags = "place_center_x, place_center_z", + y_min = 2, + rotation = "random", + }) + end +end + +-- Place the schematic when a sapling grows. +function default.grow_new_pine_tree(pos, bad) + local schem = loud_walking.schematics.conifer_trees[math.random(1,#loud_walking.schematics.conifer_trees)] + local adj = {x = pos.x - math.floor(schem.size.x / 2), + y = pos.y - 1, + z = pos.z - math.floor(schem.size.z / 2)} + minetest.place_schematic(adj, schem, 'random', nil, true) +end + diff --git a/deco_deciduous.lua b/deco_deciduous.lua new file mode 100644 index 0000000..269189c --- /dev/null +++ b/deco_deciduous.lua @@ -0,0 +1,164 @@ +--------------------- +-- Deciduous Trees -- +--------------------- + +-- Make some leaves of different colors (but the same properties). +local newnode = loud_walking.clone_node("default:leaves") +if loud_walking.noleafdecay then + newnode.groups.leafdecay = 0 +end +newnode.tiles = {"default_leaves.png^[colorize:#FF0000:20"} +minetest.register_node("loud_walking:leaves2", newnode) +newnode.tiles = {"default_leaves.png^[colorize:#FFFF00:20"} +minetest.register_node("loud_walking:leaves3", newnode) +newnode.tiles = {"default_leaves.png^[colorize:#00FFFF:20"} +minetest.register_node("loud_walking:leaves4", newnode) +newnode.tiles = {"default_leaves.png^[colorize:#00FF00:20"} +minetest.register_node("loud_walking:leaves5", newnode) + +if loud_walking.glow then + minetest.register_node("loud_walking:tree_glowing_moss", { + description = "Tree with glowing moss", + tiles = {"default_tree_top.png", "default_tree_top.png", "default_tree.png^trunks_moss.png"}, + paramtype2 = "facedir", + is_ground_content = false, + light_source = 4, + drop = 'default:tree', + groups = {tree = 1, choppy = 2, oddly_breakable_by_hand = 1, flammable = 2}, + sounds = default.node_sound_wood_defaults(), + + on_place = minetest.rotate_node + }) +end + +-- create a schematic for a spherical tree. +function loud_walking.generate_tree_schematic(trunk_height, radii, trunk, leaf, fruit, limbs) + -- trunk_height refers to the amount of trunk visible below any leaves. + local height = trunk_height + radii.y * 2 + 2 + local width = 2 * radii.z + 1 + local trunk_top = height-radii.y-1 + + local s = loud_walking.schematic_array(width, height, width) + + -- the main trunk + for y = 1,trunk_top do + local i = radii.z*width*height + y*width + radii.x + 1 + if trunk == "default:tree" and loud_walking.glow and math.random(1,10) == 1 then + s.data[i].name = "loud_walking:tree_glowing_moss" + else + s.data[i].name = trunk + end + s.data[i].param1 = 255 + s.data[i].force_place = false + end + + -- some leaves for free + loud_walking.generate_leaves(s, leaf, {x=0, y=trunk_top, z=0}, radii.x, fruit) + + -- Specify a table of limb positions... + if radii.x > 3 and limbs then + for _, p in pairs(limbs) do + local i = (p.z+radii.z)*width*height + p.y*width + (p.x+radii.x) + 1 + s.data[i].name = trunk + s.data[i].param1 = 255 + s.data[i].force_place = false + loud_walking.generate_leaves(s, leaf, p, radii.x, fruit, true) + end + -- or just do it randomly. + elseif radii.x > 3 then + for z = -radii.z,radii.z do + for y = -radii.y,radii.y do + for x = -radii.x,radii.x do + -- a smaller spheroid inside the radii + if x^2/(radii.x-3)^2 + y^2/(radii.y-3)^2 + z^2/(radii.z-3)^2 <= 1 then + if math.random(1,6) == 1 then + local i = (z+radii.z)*width*height + (y+trunk_top)*width + (x+radii.x) + 1 + + s.data[i].name = trunk + s.data[i].param1 = 255 + s.data[i].force_place = false + loud_walking.generate_leaves(s, leaf, {x=x, y=trunk_top+y, z=z}, radii.x, fruit, true) + end + end + end + end + end + end + + return s +end + +-- Create a spheroid of leaves. +function loud_walking.generate_leaves(s, leaf, pos, radius, fruit, adjust) + local height = s.size.y + local width = s.size.x + local rx = math.floor(s.size.x / 2) + local rz = math.floor(s.size.z / 2) + local r1 = math.min(3, radius) -- leaf decay radius + local probs = {255,200,150,100,75} + + for z = -r1,r1 do + for y = -r1,r1 do + for x = -r1,r1 do + if x+pos.x >= -rx and x+pos.x <= rx and y+pos.y >= 0 and y+pos.y < height and z+pos.z >= -rz and z+pos.z <= rz then + local i = (z+pos.z+rz)*width*height + (y+pos.y)*width + (x+pos.x+rx) + 1 + local dist1 = math.sqrt(x^2 + y^2 + z^2) + local dist2 = math.sqrt((x+pos.x)^2 + (z+pos.z)^2) + if dist1 <= r1 then + local newprob = probs[math.max(1, math.ceil(dist1))] + if s.data[i].name == "air" then + if fruit and (rx < 3 or dist2 / rx > 0.5) and math.random(1,10) == 1 then + s.data[i].name = fruit + s.data[i].param1 = 127 + else + s.data[i].name = leaf + s.data[i].param1 = newprob + end + elseif adjust and s.data[i].name == leaf then + s.data[i].param1 = math.max(s.data[i].param1, newprob) + end + end + end + end + end + end +end + +-- generic deciduous trees +loud_walking.schematics.deciduous_trees = {} +local leaves = {"default:leaves", "loud_walking:leaves2", "loud_walking:leaves3", "loud_walking:leaves4", "loud_walking:leaves5"} +for i = 1,#leaves do + local max_r = 6 + local fruit = nil + + if i == 1 then + fruit = "default:apple" + end + + for r = 3,max_r do + local schem = loud_walking.generate_tree_schematic(2, {x=r, y=r, z=r}, "default:tree", leaves[i], fruit) + + loud_walking.schematics.deciduous_trees[#loud_walking.schematics.deciduous_trees+1] = schem + + --minetest.register_decoration({ + -- deco_type = "schematic", + -- sidelen = 80, + -- place_on = {"default:dirt_with_grass", "default:dirt_with_dry_grass"}, + -- y_min = 4, + -- fill_ratio = (max_r-r+1)/1700, + -- biomes = {"deciduous_forest",}, + -- schematic = schem, + -- flags = "place_center_x, place_center_z", + -- rotation = "random", + --}) + end +end + +-- Place the schematic when a sapling grows. +function default.grow_new_apple_tree(pos, bad) + local schem = loud_walking.schematics.deciduous_trees[math.random(1,#loud_walking.schematics.deciduous_trees)] + local adj = {x = pos.x - math.floor(schem.size.x / 2), + y = pos.y - 1, + z = pos.z - math.floor(schem.size.z / 2)} + minetest.place_schematic(adj, schem, 'random', nil, true) +end diff --git a/deco_jungle.lua b/deco_jungle.lua new file mode 100644 index 0000000..4b7aab6 --- /dev/null +++ b/deco_jungle.lua @@ -0,0 +1,128 @@ +------------------ +-- Jungle Trees -- +------------------ + +-- Create different colored leaves with the same properties. + +newnode = loud_walking.clone_node("default:jungleleaves") +newnode.tiles = {"default_jungleleaves.png^[colorize:#FF0000:10"} +minetest.register_node("loud_walking:jungleleaves2", newnode) +newnode.tiles = {"default_jungleleaves.png^[colorize:#FFFF00:30"} +minetest.register_node("loud_walking:jungleleaves3", newnode) + + +-- Create a schematic for a jungle tree. +function loud_walking.generate_jungle_tree_schematic(trunk_height, trunk, leaf) + local height = trunk_height * 2 + 1 + local radius = 6 + local width = 2 * radius + 1 + local trunk_top = height - 4 + + local s = loud_walking.schematic_array(width, height, width) + + -- roots, trunk, and extra leaves + for z = -1,1 do + for y = 1,trunk_top do + for x = -1,1 do + local i = (z+radius)*width*height + y*width + (x+radius) + 1 + if x == 0 and z == 0 then + s.data[i].name = trunk + s.data[i].param1 = 255 + s.data[i].force_place = true + elseif (x == 0 or z == 0) and y < 3 then + s.data[i].name = trunk + s.data[i].param1 = 255 + s.data[i].force_place = true + elseif y > 3 then + s.data[i].name = leaf + s.data[i].param1 = 50 + end + end + end + end + + -- canopies + for y = 1,trunk_top+2 do + if y > trunk_height and (y == trunk_top or math.random(1,height - y) == 1) then + local x, z = 0, 0 + while x == 0 and z == 0 do + x = math.random(-1,1) * 2 + z = math.random(-1,1) * 2 + end + for j = -1,1,2 do + local i = (j*z + radius)*width*height + y*width + (j*x + radius) + 1 + s.data[i].name = trunk + s.data[i].param1 = 255 + s.data[i].force_place = true + loud_walking.generate_canopy(s, leaf, {x=j*x, y=y, z=j*z}) + end + end + end + + return s +end + +-- Create a canopy of leaves. +function loud_walking.generate_canopy(s, leaf, pos) + local height = s.size.y + local width = s.size.x + local rx = math.floor(s.size.x / 2) + local rz = math.floor(s.size.z / 2) + local r1 = 4 -- leaf decay radius + local probs = {255,200,150,100,75} + + for z = -r1,r1 do + for y = 0,1 do + for x = -r1,r1 do + if x+pos.x >= -rx and x+pos.x <= rx and y+pos.y >= 0 and y+pos.y < height and z+pos.z >= -rz and z+pos.z <= rz then + local i = (z+pos.z+rz)*width*height + (y+pos.y)*width + (x+pos.x+rx) + 1 + local dist1 = math.sqrt(x^2 + y^2 + z^2) + local dist2 = math.sqrt((x+pos.x)^2 + (z+pos.z)^2) + if dist1 <= r1 then + local newprob = probs[math.max(1, math.ceil(dist1))] + if s.data[i].name == "air" then + s.data[i].name = leaf + s.data[i].param1 = newprob + elseif s.data[i].name == leaf then + s.data[i].param1 = math.max(s.data[i].param1, newprob) + end + end + end + end + end + end +end + +-- generic jungle trees +loud_walking.schematics.jungle_trees = {} +leaves = {"default:jungleleaves", "loud_walking:jungleleaves2", "loud_walking:jungleleaves3"} +for i = 1,#leaves do + local max_h = 7 + for h = 5,max_h do + local schem = loud_walking.generate_jungle_tree_schematic(h*2, "default:jungletree", leaves[i]) + + loud_walking.schematics.jungle_trees[#loud_walking.schematics.jungle_trees+1] = schem + + --minetest.register_decoration({ + -- deco_type = "schematic", + -- sidelen = 80, + -- place_on = {"default:dirt_with_grass", "default:dirt"}, + -- fill_ratio = (max_h-h+1)/1200, + -- biomes = {"rainforest", "rainforest_swamp",}, + -- schematic = schem, + -- flags = "place_center_x, place_center_z", + -- y_min = 0, + -- rotation = "random", + --}) + end +end + +-- Place the schematic when a sapling grows. +function default.grow_new_jungle_tree(pos, bad) + local schem = loud_walking.schematics.jungle_trees[math.random(1,#loud_walking.schematics.jungle_trees)] + local adj = {x = pos.x - math.floor(schem.size.x / 2), + y = pos.y - 1, + z = pos.z - math.floor(schem.size.z / 2)} + minetest.place_schematic(adj, schem, 'random', nil, true) +end + diff --git a/deco_trees.lua b/deco_trees.lua new file mode 100644 index 0000000..cd22c00 --- /dev/null +++ b/deco_trees.lua @@ -0,0 +1,14 @@ +----------- +-- Trees -- +----------- + +-- Change leafdecay ratings +minetest.add_group("default:leaves", {leafdecay = 4}) +minetest.add_group("default:jungleleaves", {leafdecay = 4}) +minetest.add_group("default:pine_needles", {leafdecay = 5}) + + +-- tree creation code +dofile(loud_walking.path.."/deco_deciduous.lua") +dofile(loud_walking.path.."/deco_conifer.lua") +dofile(loud_walking.path.."/deco_jungle.lua") diff --git a/depends.txt b/depends.txt new file mode 100644 index 0000000..4ad96d5 --- /dev/null +++ b/depends.txt @@ -0,0 +1 @@ +default diff --git a/init.lua b/init.lua new file mode 100644 index 0000000..e38c188 --- /dev/null +++ b/init.lua @@ -0,0 +1,84 @@ +-- Check for necessary mod functions and abort if they aren't available. +if not minetest.get_biome_id then + minetest.log() + minetest.log("* Not loading Cityscape *") + minetest.log("Cityscape requires mod functions which are") + minetest.log(" not exposed by your Minetest build.") + minetest.log() + return +end + +loud_walking = {} +loud_walking.version = "1.0" +loud_walking.path = minetest.get_modpath(minetest.get_current_modname()) +loud_walking.first_flag = 0 + + +minetest.register_on_mapgen_init(function(mgparams) + minetest.set_mapgen_params({mgname="singlenode", flags="nolight"}) +end) + +if default then + if default.register_ores then + default.register_ores() + end + if default.register_blobs then + default.register_blobs() + end + --if default.register_biomes then + -- default.register_biomes() + --end + --if default.register_decorations then + -- default.register_decorations() + --end +end + + +-- Modify a node to add a group +function minetest.add_group(node, groups) + local def = minetest.registered_items[node] + if not def then + return false + end + local def_groups = def.groups or {} + for group, value in pairs(groups) do + if value ~= 0 then + def_groups[group] = value + else + def_groups[group] = nil + end + end + minetest.override_item(node, {groups = def_groups}) + return true +end + +function loud_walking.clone_node(name) + local node = minetest.registered_nodes[name] + local node2 = table.copy(node) + return node2 +end + +function loud_walking.node(name) + if not loud_walking.node_cache then + loud_walking.node_cache = {} + end + + if not loud_walking.node_cache[name] then + loud_walking.node_cache[name] = minetest.get_content_id(name) + if name ~= "ignore" and loud_walking.node_cache[name] == 127 then + print("*** Failure to find node: "..name) + end + end + + return loud_walking.node_cache[name] +end + + +dofile(loud_walking.path .. "/nodes.lua") +dofile(loud_walking.path .. "/deco.lua") +dofile(loud_walking.path .. "/mapgen.lua") + + +minetest.register_on_newplayer(loud_walking.respawn) +minetest.register_on_respawnplayer(loud_walking.respawn) +minetest.register_on_generated(loud_walking.generate) diff --git a/mapgen.lua b/mapgen.lua new file mode 100644 index 0000000..d9e2a28 --- /dev/null +++ b/mapgen.lua @@ -0,0 +1,309 @@ +local node = loud_walking.node + + +local data = {} +local p2data = {} -- vm rotation data buffer +local lightmap = {} +local vm, emin, emax, a, csize, heightmap, biomemap +local div_sz_x, div_sz_z, minp, maxp, terrain, cave + +local base_terrain_noise = {offset = 0, +scale = 20, seed = 8829, spread = {x = 40, y = 40, z = 40}, +octaves = 6, persist = 0.4, lacunarity = 2} + +local cave_noise = {offset = 0, scale = 1, +seed = -3977, spread = {x = 30, y = 30, z = 30}, octaves = 3, +persist = 0.8, lacunarity = 2} + +local tree_biomes = {} +tree_biomes["deciduous_forest"] = {"deciduous_trees"} +tree_biomes["coniferous_forest"] = {"conifer_trees"} +tree_biomes["rainforest"] = {"jungle_trees"} + +local biome_terrain_scale = {} +biome_terrain_scale["deciduous_forest"] = 0.5 +biome_terrain_scale["coniferous_forest"] = 0.75 +biome_terrain_scale["rainforest"] = 0.33 + + +local function place_schematic(pos, schem, center) + local yslice = {} + if schem.yslice_prob then + for _, ys in pairs(schem.yslice_prob) do + yslice[ys.ypos] = ys.prob + end + end + + if center then + pos.x = pos.x - math.floor(schem.size.x / 2) + pos.z = pos.z - math.floor(schem.size.z / 2) + end + + for z = 0, schem.size.z - 1 do + for x = 0, schem.size.x - 1 do + local ivm = a:index(pos.x + x, pos.y, pos.z + z) + local isch = z * schem.size.y * schem.size.x + x + 1 + for y = 0, schem.size.y - 1 do + if yslice[y] or 255 >= math.random(255) then + local prob = schem.data[isch].prob or schem.data[isch].param1 or 255 + if prob >= math.random(255) and schem.data[isch].name ~= "air" then + data[ivm] = node(schem.data[isch].name) + end + local param2 = schem.data[isch].param2 or 0 + p2data[ivm] = param2 + end + ivm = ivm + a.ystride + isch = isch + schem.size.x + end + end + end +end + +local function is_pod(x, y, z) + local min_x = math.floor((x + 32) / csize.x) + local min_y = math.floor((y + 32) / csize.y) + local min_z = math.floor((z + 32) / csize.z) + + if min_x % 2 == 0 and min_y % 2 == 0 and min_z % 2 == 0 then + return true + end + --if min_x % 2 == 1 and min_y % 4 == 0 and min_z % 2 == 1 then + -- return true + --elseif min_x % 2 == 0 and min_y % 4 == 2 and min_z % 2 == 0 then + -- return true + --end + + return false +end + +local function connection(x, y, z) + local min_x = math.floor((x + 32) / csize.x) + local min_y = math.floor((y + 32) / csize.y) + local min_z = math.floor((z + 32) / csize.z) + + --local seed_noise = minetest.get_perlin({offset = 0, scale = 32768, + --seed = 5202, spread = {x = 80, y = 80, z = 80}, octaves = 2, + --persist = 0.4, lacunarity = 2}) + --math.randomseed(seed_noise:get2d({x=minp.x, y=minp.z})) + + local ct = min_x % 2 + min_y % 2 + min_z % 2 + local r = min_x % 2 + 2 * (min_y % 2) + 4 * (min_z % 2) + if ct == 1 then + return r + end + + return nil +end + +local function get_height(dx, dz, biome, index) + local terr + + if index == true then + local terrain_noise = table.copy(base_terrain_noise) + terrain_noise.scale = terrain_noise.scale * biome_terrain_scale[biome] + terr = math.floor(minetest.get_perlin(terrain_noise):get2d({x=dx, y=dz}) + 0.5) + -- Still need csize here... + dx = (dx + 32) % 80 + dz = (dz + 32) % 80 + elseif not index then + index = dz * csize.x + dx + 1 + terr = math.floor(terrain[index] + 0.5) + else + terr = math.floor(terrain[index] + 0.5) + end + + local d = 38 - math.abs(math.abs(dx - 39.5) - math.abs(dz - 39.5)) + if math.abs(terr) > d then + if terr > 0 then + terr = math.floor(d + 0.5) + else + terr = math.floor(0.5 - d) + end + end + + return terr +end + +local function get_biome(px, pz) + return "deciduous_forest" +end + + +function loud_walking.generate(p_minp, p_maxp, seed) + minp, maxp = p_minp, p_maxp + vm, emin, emax = minetest.get_mapgen_object("voxelmanip") + vm:get_data(data) + vm:set_lighting({day = 15, night = 0}, minp, maxp) + lightmap = vm:get_light_data() + --p2data = vm:get_param2_data() + a = VoxelArea:new({MinEdge = emin, MaxEdge = emax}) + csize = vector.add(vector.subtract(maxp, minp), 1) + + local write = false + + -- Deal with memory issues. This, of course, is supposed to be automatic. + local mem = math.floor(collectgarbage("count")/1024) + if mem > 300 then + print("Manually collecting garbage...") + collectgarbage("collect") + end + + local px = math.floor((minp.x + 32) / csize.x) + local pz = math.floor((minp.z + 32) / csize.z) + local biome = get_biome(px, pz) + local top = node("default:dirt_with_grass") + + -- use the same seed (based on perlin noise). + local seed_noise = minetest.get_perlin({offset = 0, scale = 32768, + seed = 5202, spread = {x = 80, y = 80, z = 80}, octaves = 2, + persist = 0.4, lacunarity = 2}) + math.randomseed(seed_noise:get2d({x=minp.x, y=minp.z})) + + local terrain_noise = table.copy(base_terrain_noise) + terrain_noise.scale = terrain_noise.scale * biome_terrain_scale[biome] + terrain = minetest.get_perlin_map(terrain_noise, csize):get2dMap_flat(minp) + cave = minetest.get_perlin_map(cave_noise, csize):get3dMap_flat(minp) + + local pod = is_pod(minp.x, minp.y, minp.z) + local connection = connection(minp.x, minp.y, minp.z) + + local index = 0 + local index3d = 0 + for z = minp.z, maxp.z do + local dz = z - minp.z + for x = minp.x, maxp.x do + index = index + 1 + local dx = x - minp.x + index3d = dz * csize.y * csize.x + dx + 1 + local ivm = a:index(x, minp.y, z) + + local terr = get_height(dx, dz, biome, index) + local in_cave = false + + for y = minp.y, maxp.y do + local dy = y - minp.y + if pod then + if math.min(dx, csize.x - dx) + math.min(dy, csize.y - dy) + math.min(dz, csize.z - dz) < 40 then + data[ivm] = node("air") + --lightmap[ivm] = 0 + in_cave = false + elseif math.min(dx, csize.x - dx) + math.min(dy, csize.y - dy) + math.min(dz, csize.z - dz) < 41 then + if dy < terr + 40 then + data[ivm] = node("loud_walking:scrith") + lightmap[ivm] = 0 + else + data[ivm] = node("default:glass") + end + in_cave = false + write = true + elseif (dx == 0 or dx == csize.x - 1) or (dz == 0 or dz == csize.z - 1) or (dy == 0 or dy == csize.y - 1) then + if math.abs(dy - 42) < 2 and (dz == 40 or dx == 40) then + data[ivm] = node("air") + else + if dy < terr + 40 then + data[ivm] = node("loud_walking:scrith") + lightmap[ivm] = 0 + else + data[ivm] = node("default:glass") + end + write = true + end + in_cave = false + elseif dy > terr + 40 then + data[ivm] = node("air") + in_cave = false + elseif cave[index3d] ^ 2 > 0.1 + dy / 40 then + if terr + 40 >= dy and not in_cave and dy > terr + 30 then + data[ivm] = node("default:dirt") + else + data[ivm] = node("air") + end + in_cave = true + lightmap[ivm] = 0 + elseif dy > terr + 39 then + data[ivm] = top + lightmap[ivm] = 0 + in_cave = false + write = true + elseif dy > terr + 37 then + data[ivm] = node("default:dirt") + lightmap[ivm] = 0 + in_cave = false + write = true + else + data[ivm] = node("default:stone") + lightmap[ivm] = 0 + in_cave = false + write = true + end + elseif connection and dy == 40 and ((dx == 40 and connection % 4 == 0) or (dz == 40 and connection % 2 == 1)) then + data[ivm] = node("default:stone") + lightmap[ivm] = 0 + write = true + end + + ivm = ivm + a.ystride + index3d = index3d + csize.x + end + end + end + + if pod then + for dz = 0, 75, 5 do + for dx = 0, 75, 5 do + if math.random(2) == 1 then + local x = minp.x + dx + math.random(0, 4) + local z = minp.z + dz + math.random(0, 4) + local y = minp.y + get_height(x - minp.x, z - minp.z, biome) + 40 + + local ivm = a:index(x, y, z) + if data[ivm + a.ystride] == node("air") and (data[ivm] == node("default:dirt") or data[ivm] == node("default:dirt_with_grass") or data[ivm] == node("default:dirt_with_snow")) then + if tree_biomes[biome] then + local tree_type = tree_biomes[biome][math.random(#tree_biomes[biome])] + local schem = loud_walking.schematics[tree_type][math.random(#loud_walking.schematics[tree_type])] + local pos = {x=x, y=y, z=z} + -- The minetest schematic functions don't seem very accurate. + place_schematic(pos, schem, true) + end + end + end + end + end + end + + if write then + vm:set_data(data) + minetest.generate_ores(vm, minp, maxp) + minetest.generate_decorations(vm, minp, maxp) + --vm:set_param2_data(p2data) + --vm:set_lighting({day = 15, night = 0}) + vm:set_light_data(lightmap) + vm:calc_lighting(minp, maxp, false) + vm:update_liquids() + vm:write_to_map() + end + + vm, a, heightmap, biomemap = nil, nil, nil, nil +end + +function loud_walking.respawn(player) + local success = false + while not success do + local px = math.random(-10, 10) * 2 + local pz = math.random(-10, 10) * 2 + -- How do we get csize before generation? + local dx = math.random(80) - 1 + local dz = math.random(80) - 1 + local x = (dx - 32) + 80 * px + local z = (dz - 32) + 80 * pz + local y = get_height(x, z, get_biome(px, pz), true) + 8 + + local pos = {x=x,y=y,z=z} + local node = minetest.get_node(pos) + if node.name ~= "air" then + player:setpos(pos) + success = true + end + --print(node.name) + end +end diff --git a/mod.conf b/mod.conf new file mode 100644 index 0000000..8ede743 --- /dev/null +++ b/mod.conf @@ -0,0 +1 @@ +name = loud_walking diff --git a/nodes.lua b/nodes.lua new file mode 100644 index 0000000..7306035 --- /dev/null +++ b/nodes.lua @@ -0,0 +1,22 @@ +minetest.register_node("loud_walking:plate_glass", { + description = "Plate Glass", + drawtype = "glasslike", + paramtype = "light", + sunlight_propagates = true, + tiles = {"loud_walking_plate_glass.png"}, + light_source = 8, + use_texture_alpha = true, + is_ground_content = false, + groups = {cracky = 3, level=1}, + sounds = default.node_sound_stone_defaults(), +}) + +minetest.register_node("loud_walking:scrith", { + description = "Scrith", + paramtype = "light", + tiles = {"default_obsidian.png"}, + use_texture_alpha = true, + is_ground_content = false, + groups = {}, + sounds = default.node_sound_stone_defaults(), +}) diff --git a/textures/loud_walking_aluminum.png b/textures/loud_walking_aluminum.png new file mode 100644 index 0000000..e03e0dc Binary files /dev/null and b/textures/loud_walking_aluminum.png differ diff --git a/textures/loud_walking_plate_glass.png b/textures/loud_walking_plate_glass.png new file mode 100644 index 0000000..5061d0c Binary files /dev/null and b/textures/loud_walking_plate_glass.png differ diff --git a/textures/screenshot02.jpg b/textures/screenshot02.jpg new file mode 100644 index 0000000..22a4c8b Binary files /dev/null and b/textures/screenshot02.jpg differ