diff --git a/README.md b/README.md index f21d190..e8a9df9 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # fun_caves -Fun Caves is an attempt to convert the mapgen V6 caves into a lua mod, so they can be used with any mapgen. I've translated the C++ code into lua in the most mechanical way possible. I honestly have no idea how half of it works, and I don't intend to spend a lot of time on it in the future, so anyone who likes this mod is encouraged to fork and/or tinker with it and submit pull requests. +Fun Caves started as an attempt to convert the mapgen V6 caves into a lua mod, so they could be used with any mapgen. However, I've since turned it into an all cave environment, with no surface at all. ![screenshot](https://github.com/duane-r/fun_caves/raw/master/textures/screenshot.jpg) diff --git a/depends.txt b/depends.txt index 4ad96d5..abb01ae 100644 --- a/depends.txt +++ b/depends.txt @@ -1 +1,2 @@ default +flowers diff --git a/fungal_tree.lua b/fungal_tree.lua new file mode 100644 index 0000000..3a65241 --- /dev/null +++ b/fungal_tree.lua @@ -0,0 +1,358 @@ +------------------- +-- Fungal Tree -- +------------------- + +local light_max = 9 + +local colors = {"^[colorize:#FF00FF:60", "", "^[colorize:#0000FF:60", "^[colorize:#FF4500:80"} +fun_caves.fungal_tree_leaves = {} + +-- all leaves +function fun_caves.make_fungal_tree(data, area, pos, height, leaves, fruit) + for y = 0, height do + local radius = 1 + if y > 1 and y < height - 2 then + radius = 2 + end + local force_x = math.random(1,3) - 2 + local force_y = math.random(1,3) - 2 + for z = -radius,radius do + for x = -radius,radius do + local sr = math.random(1,27) + local i = pos + z*area.zstride + y*area.ystride + x + if force_x == x and force_y == y then + data[i] = leaves + elseif sr == 1 then + data[i] = fruit + elseif sr < 14 then + data[i] = leaves + end + end + end + end +end + +-- multicolored growths +local count = 0 +for _, color in pairs(colors) do + count = count + 1 + local name = "fun_caves:fungal_tree_leaves_"..count + fun_caves.fungal_tree_leaves[#fun_caves.fungal_tree_leaves+1] = name + + minetest.register_node(name, { + description = "Fungal tree growths", + drawtype = "allfaces_optional", + waving = 1, + visual_scale = 1.3, + tiles = {"fun_caves_fungal_tree_leaves.png"..color}, + paramtype = "light", + is_ground_content = false, + groups = {snappy=3, flammable=3, leaves=1, plant=1}, + drop = { + max_items = 1, + items = { + --{items = {"fun_caves:"..tree.name.."_sapling"}, rarity = tree.drop_rarity }, + {items = {name} } + } + }, + sounds = default.node_sound_leaves_defaults(), + after_place_node = default.after_place_leaves, + }) + + minetest.register_craft({ + output = "default:stick", + recipe = { + {name} + } + }) +end + + +local leaves_and_air = table.copy(fun_caves.fungal_tree_leaves) +leaves_and_air[#leaves_and_air+1] = "air" +local good_stone = {} +good_stone["fun_caves:stone_with_lichen"] = true +good_stone["fun_caves:stone_with_algae"] = true + +local function find_ground(pos) + for y1 = 1, 16 do + local node = minetest.get_node_or_nil({x=pos.x, y=pos.y-y1, z=pos.z}) + if node then + if minetest.get_item_group(node.name, "soil") ~= 0 or + good_stone[node.name] then + return y1 + end + end + end + + return 1000 +end + + +-- fungal spread +minetest.register_abm({ + nodenames = fun_caves.fungal_tree_leaves, + interval = 2 * fun_caves.time_factor, + chance = 10, + action = function(pos, node) + if minetest.get_node_light(pos, nil) == 15 then + minetest.remove_node(pos) + return + end + if find_ground(pos) > 16 then + minetest.remove_node(pos) + return + end + + local grow_pos = {x=pos.x, y=pos.y-1, z=pos.z} + local grow_node = minetest.get_node_or_nil(grow_pos) + if grow_node and grow_node.name == "air" then + minetest.set_node(grow_pos, {name = node.name}) + return + end + if math.random(1,3) ~= 1 then + return + end + + local foreign = {} + for _, i in pairs(fun_caves.fungal_tree_leaves) do + if i ~= node.name then + foreign[#foreign+1] = i + end + end + local pos1, count = minetest.find_nodes_in_area(vector.subtract(pos, 3), vector.add(pos, 3), foreign) + if #pos1 > 0 then + minetest.set_node(pos1[math.random(1,#pos1)], {name="air"}) + return + end + + if math.random(1,201) == 1 then + local new = fun_caves.fungal_tree_leaves[math.random(1,#fun_caves.fungal_tree_leaves)] + local pos1, count = minetest.find_nodes_in_area({x=pos.x-8, y=pos.y-16, z=pos.z-8}, {x=pos.x+8, y=pos.y+16, z=pos.z+8}, node.name) + for _, p in pairs(pos1) do + minetest.set_node(p, {name=new}) + end + return + end + + grow_pos = {x = pos.x + math.random(-1,1), y = pos.y + math.random(-1,1), z = pos.z + math.random(-1,1)} + grow_node = minetest.get_node_or_nil(grow_pos) + --if math.random(1,2) == 1 then + minetest.set_node(pos, {name = "air"}) + --end + if not grow_node or not table.contains(leaves_and_air, grow_node.name) or find_ground(grow_pos) > 16 then + return + end + if minetest.get_node_light(grow_pos, nil) <= light_max then + minetest.set_node(pos, {name = "air"}) + if math.random(1,27) == 1 then + minetest.set_node(grow_pos, {name = "fun_caves:fungal_tree_fruit"}) + else + minetest.set_node(grow_pos, {name = node.name}) + end + end + end +}) + +-- Fill a list with data for content IDs, after all nodes are registered +local cid_data = {} +minetest.after(0, function() + for name, def in pairs(minetest.registered_nodes) do + cid_data[minetest.get_content_id(name)] = { + name = name, + --drops = def.drops, + flammable = def.groups.flammable, + choppy = def.groups.choppy, + fleshy = def.groups.fleshy, + snappy = def.groups.snappy, + on_blast = def.on_blast, + } + end +end) + +local function add_effects(pos, radius) + minetest.add_particlespawner({ + amount = 128, + time = 1, + minpos = vector.subtract(pos, radius / 2), + maxpos = vector.add(pos, radius / 2), + minvel = {x=-20, y=-20, z=-20}, + maxvel = {x=20, y=20, z=20}, + minacc = vector.new(), + maxacc = vector.new(), + minexptime = 1, + maxexptime = 3, + minsize = 8, + maxsize = 16, + texture = "tnt_smoke.png", + }) +end + +local function destroy(pos, cid) + if minetest.is_protected(pos, "") then + return + end + local def = cid_data[cid] + if def and def.on_blast then + def.on_blast(vector.new(pos), 1) + return + end + if def.snappy == nil and def.choppy == nil and def.fleshy == nil and def.name ~= "fire:basic_flame" then + return + end + local new = "air" + --if math.random(1,2) == 1 then + if true then + local node_under = minetest.get_node_or_nil({x = pos.x, + y = pos.y - 1, z = pos.z}) + if node_under and node_under.name ~= "air" then + --new = node.name + end + end + minetest.set_node(pos, {name=new}) +end + +local function explode(pos, radius) + local pos = vector.round(pos) + local vm = VoxelManip() + local p1 = vector.subtract(pos, radius) + local p2 = vector.add(pos, radius) + local minp, maxp = vm:read_from_map(p1, p2) + local a = VoxelArea:new({MinEdge = minp, MaxEdge = maxp}) + local data = vm:get_data() + + local drops = {} + local p = {} + + local c_air = minetest.get_content_id("air") + + for z = -radius, radius do + for y = -radius, 4*radius do + local vi = a:index(pos.x + (-radius), pos.y + y, pos.z + z) + for x = -radius, radius do + if (x * x) + (y * y / 4) + (z * z) <= + (radius * radius) + math.random(-radius, radius) then + local cid = data[vi] + p.x = pos.x + x + p.y = pos.y + y + p.z = pos.z + z + if cid ~= c_air then + destroy(p, cid) + end + end + vi = vi + 1 + end + end + end +end + +local function calc_velocity(pos1, pos2, old_vel, power) + local vel = vector.direction(pos1, pos2) + vel = vector.normalize(vel) + vel = vector.multiply(vel, power) + + -- Divide by distance + local dist = vector.distance(pos1, pos2) + dist = math.max(dist, 1) + vel = vector.divide(vel, dist) + + -- Add old velocity + vel = vector.add(vel, old_vel) + return vel +end + +local function entity_physics(pos, radius) + -- Make the damage radius larger than the destruction radius + radius = radius * 2 + local objs = minetest.get_objects_inside_radius(pos, radius) + for _, obj in pairs(objs) do + local obj_pos = obj:getpos() + local obj_vel = obj:getvelocity() + local dist = math.max(1, vector.distance(pos, obj_pos)) + + if obj_vel ~= nil then + obj:setvelocity(calc_velocity(pos, obj_pos, + obj_vel, radius * 10)) + end + + local damage = (4 / dist) * radius + obj:set_hp(obj:get_hp() - damage) + end +end + + +local function boom(pos) + if not pos then + return + end + local node = minetest.get_node_or_nil(pos) + if not node then + return + end + + minetest.sound_play("tnt_explode", {pos=pos, gain=1.5, max_hear_distance=2*64}) + local radius = 5 + minetest.set_node(pos, {name="air"}) + explode(pos, radius) + entity_physics(pos, radius) + add_effects(pos, radius) +end + +local function burn(pos) + minetest.get_node_timer(pos):start(1) +end + + +-- Exploding fruit +minetest.register_abm({ + nodenames = {"fun_caves:fungal_tree_fruit"}, + interval = 3 * fun_caves.time_factor, + chance = 20, + action = function(pos, node) + local pos1, count = minetest.find_nodes_in_area(vector.subtract(pos, 1), vector.add(pos, 1), {"fire:basic_flame"}) + if #pos1 > 0 then + boom(pos) + return + end + + local pos1, count = minetest.find_nodes_in_area(vector.subtract(pos, 1), vector.add(pos, 1), fun_caves.fungal_tree_leaves) + if #pos1 < 3 then + minetest.set_node(pos, {name="air"}) + return + end + + local g = find_ground(pos) + if g > 4 and g < 17 then + if math.random(1,17 - g) == 1 then + boom(pos) + end + elseif math.random(1,2) == 1 then + minetest.set_node(pos, {name="air"}) + end + end +}) + + +minetest.register_node("fun_caves:fungal_tree_fruit", { + description = "Fungal tree fruit", + drawtype = "plantlike", + visual_scale = 0.75, + tiles = {"fun_caves_fungal_tree_fruit.png"}, + --inventory_image = ".png", + paramtype = "light", + sunlight_propagates = true, + light_source = 6, + walkable = false, + is_ground_content = false, + selection_box = { + type = "fixed", + fixed = {-0.2, -0.5, -0.2, 0.2, 0, 0.2} + }, + groups = {fleshy = 3, dig_immediate = 3, flammable = 2}, + --on_use = minetest.item_eat(2), + sounds = default.node_sound_leaves_defaults(), + on_timer = boom, + on_punch = boom, +}) + + diff --git a/init.lua b/init.lua index c75b644..13bf403 100644 --- a/init.lua +++ b/init.lua @@ -2,35 +2,46 @@ fun_caves = {} fun_caves.version = "1.0" fun_caves.path = minetest.get_modpath(minetest.get_current_modname()) fun_caves.world = false +fun_caves.time_factor = 10 -if fun_caves.world then - minetest.register_on_mapgen_init(function(mgparams) - minetest.set_mapgen_params({mgname="singlenode", flags="nolight"}) - end) +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 - if flowers.register_decorations then - flowers.register_decorations() - 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 + if flowers.register_decorations then + flowers.register_decorations() end -else - minetest.set_mapgen_params({flags="nocaves"}) end +-- Check if the table contains an element. +function table.contains(table, element) + for key, value in pairs(table) do + if value == element then + if key then + return key + else + return true + end + end + end + return false +end + -- Modify a node to add a group function minetest.add_group(node, groups) local def = minetest.registered_items[node] @@ -71,14 +82,17 @@ function fun_caves.node(name) end ---dofile(fun_caves.path .. "/nodes.lua") +dofile(fun_caves.path .. "/nodes.lua") +dofile(fun_caves.path .. "/fungal_tree.lua") dofile(fun_caves.path .. "/mapgen.lua") -if fun_caves.world then - minetest.register_on_newplayer(fun_caves.respawn) - minetest.register_on_respawnplayer(fun_caves.respawn) -end +minetest.register_on_newplayer(fun_caves.respawn) +minetest.register_on_respawnplayer(fun_caves.respawn) -- Inserting helps to ensure that fun_caves operates first. table.insert(minetest.registered_on_generateds, 1, fun_caves.generate) + +minetest.register_on_joinplayer(function(player) + player:set_sky("#000000", "plain", {}) +end) diff --git a/mapgen.lua b/mapgen.lua index b8c6702..fd925e6 100644 --- a/mapgen.lua +++ b/mapgen.lua @@ -2,27 +2,31 @@ -- cavegen.cpp, and is likewise distributed under the LGPL2.1 ---local DEBUG = true +local DEBUG = false +-- Cave blend distance near YMIN, YMAX +local massive_cave_blend = 128 +-- noise threshold for massive caves +local massive_cave_threshold = 0.6 +-- mct: 1 = small rare caves, 0.5 1/3rd ground volume, 0 = 1/2 ground volume. + +local seed_noise = {offset = 0, scale = 32768, seed = 5202, spread = {x = 80, y = 80, z = 80}, octaves = 2, persist = 0.4, lacunarity = 2} +local cave_noise_v6 = {offset = 6, scale = 6, seed = 34329, spread = {x = 250, y = 250, z = 250}, octaves = 3, persist = 0.5, lacunarity = 2} +local intersect_cave_noise_1 = {offset = 0, scale = 1, seed = -8402, spread = {x = 64, y = 64, z = 64}, octaves = 3, persist = 0.5, lacunarity = 2} +local intersect_cave_noise_2 = {offset = 0, scale = 1, seed = 3944, spread = {x = 64, y = 64, z = 64}, octaves = 3, persist = 0.5, lacunarity = 2} +local massive_cave_noise = {offset = 0, scale = 1, seed = 59033, spread = {x = 768, y = 256, z = 768}, octaves = 6, persist = 0.63, lacunarity = 2} +local biome_noise = {offset = 0.0, scale = 1.0, spread = {x = 400, y = 400, z = 400}, seed = 903, octaves = 3, persist = 0.5, lacunarity = 2.0} +local biome_blend = {offset = 0.0, scale = 0.1, spread = {x = 8, y = 8, z = 8}, seed = 4023, octaves = 2, persist = 1.0, lacunarity = 2.0} + + + local node = fun_caves.node local data = {} local p2data = {} -- vm rotation data buffer local lightmap = {} -local vm, emin, emax, a, csize, heightmap, biomemap +local vm, emin, emax, area, csize local div_sz_x, div_sz_z, minp, maxp, terrain, cave -local 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 seed_noise = {offset = 0, scale = 32768, -seed = 5202, spread = {x = 80, y = 80, z = 80}, octaves = 2, -persist = 0.4, lacunarity = 2} - if fun_caves.world then fun_caves.biomes = {} local biomes = fun_caves.biomes @@ -118,7 +122,7 @@ local function place_schematic(pos, schem, center) local dz = pos.z - minp.z + z local dx = pos.x - minp.x + x if pos.x + x > minp.x and pos.x + x < maxp.x and pos.z + z > minp.z and pos.z + z < maxp.z then - local ivm = a:index(pos.x + x, pos.y, pos.z + z) + local ivm = area:index(pos.x + x, pos.y, pos.z + z) local isch = z1 * schem.size.y * schem.size.x + x1 + 1 for y = 0, schem.size.y - 1 do local dy = pos.y - minp.y + y @@ -133,7 +137,7 @@ local function place_schematic(pos, schem, center) end end - ivm = ivm + a.ystride + ivm = ivm + area.ystride isch = isch + schem.size.x end end @@ -157,13 +161,11 @@ local function get_decoration(biome) end -local np_cave = {offset = 6, scale = 6, seed = 34329, spread = {x = 250, y = 250, z = 250}, octaves = 3, persist = 0.5, lacunarity = 2} - local function rangelim(x, y, z) return math.max(math.min(x, z), y) end -local function carveRoute(this, vec, f, randomize_xz, tunnel_above_ground) +local function carveRoute(this, vec, f, randomize_xz) local startp = vector.new(this.orp) startp = vector.add(startp, this.of) @@ -182,52 +184,48 @@ local function carveRoute(this, vec, f, randomize_xz, tunnel_above_ground) for z0 = d0, d1 do local si = this.rs / 2 - math.max(0, math.abs(z0) - this.rs / 7 - 1) for x0 = -si - math.random(0,1), si - 1 + math.random(0,1) do - if (tunnel_above_ground) then - --continue - else - local maxabsxz = math.max(math.abs(x0), math.abs(z0)) - local si2 = this.rs / 2 - math.max(0, maxabsxz - this.rs / 7 - 1) - for y0 = -si2, si2 do - if (this.large_cave_is_flat) then - -- Make large caves not so tall - if (this.rs > 7 and math.abs(y0) >= this.rs / 3) then + local maxabsxz = math.max(math.abs(x0), math.abs(z0)) + local si2 = this.rs / 2 - math.max(0, maxabsxz - this.rs / 7 - 1) + for y0 = -si2, si2 do + if (this.large_cave_is_flat) then + -- Make large caves not so tall + if (this.rs > 7 and math.abs(y0) >= this.rs / 3) then + --continue + else + local p = vector.new(cp.x + x0, cp.y + y0, cp.z + z0) + p = vector.add(p, this.of) + + if not area:containsp(p) then --continue else - local p = vector.new(cp.x + x0, cp.y + y0, cp.z + z0) - p = vector.add(p, this.of) + local i = area:indexp(vector.round(p)) + local c = data[i] + --if (not ndef.get(c).is_ground_content) then + -- ** check for ground content? ** + local donotdig = false + if c == node("default:desert_sand") then + donotdig = true + end - if not a:containsp(p) then + if donotdig then --continue else - local i = a:indexp(vector.round(p)) - local c = data[i] - --if (not ndef.get(c).is_ground_content) then - -- ** check for ground content? ** - local donotdig = false - if c == node("default:desert_sand") then - donotdig = true - end + if (this.large_cave) then + local full_ymin = minp.y - 16 + local full_ymax = maxp.y + 16 - if donotdig then - --continue - else - if (this.large_cave) then - local full_ymin = minp.y - 16 - local full_ymax = maxp.y + 16 - - if this.flooded and not this.lava_cave then - data[i] = (p.y <= this.water_level) and node("default:water_source") or node("air") - elseif this.flooded then - data[i] = (p.y < startp.y - 2) and node("default:lava_source") or node("air") - else - data[i] = node("air") - end + if this.flooded and not this.lava_cave then + data[i] = (p.y <= this.water_level) and node("default:water_source") or node("air") + elseif this.flooded then + data[i] = (p.y < startp.y - 2) and node("default:lava_source") or node("air") else - if (c == node("ignore") or c == node("air")) then - --continue - else - data[i] = node("air") - end + data[i] = node("air") + end + else + if (c == node("ignore") or c == node("air")) then + --continue + else + data[i] = node("air") end end end @@ -239,7 +237,7 @@ local function carveRoute(this, vec, f, randomize_xz, tunnel_above_ground) end end -local function makeTunnel(this, dirswitch) +local function makeV6Tunnel(this, dirswitch) if dirswitch and not this.large_cave then this.main_direction = vector.new( ((math.random() * 20) - 10) / 10, @@ -285,38 +283,6 @@ local function makeTunnel(this, dirswitch) ) end - -- Do not make caves that are entirely above ground, to fix - -- shadow bugs caused by overgenerated large caves. - -- It is only necessary to check the startpoint and endpoint. - local orpi = vector.new(this.orp.x, this.orp.y, this.orp.z) - local veci = vector.new(vec.x, vec.y, vec.z) - local h1 - local h2 - - local p1 = vector.add(orpi, veci, this.of, this.rs / 2) - if (p1.z >= minp.z and p1.z <= maxp.z and - p1.x >= minp.x and p1.x <= maxp.x) then - local index1 = math.floor(p1.z - minp.z + 0.5) * csize.x + math.floor(p1.x - minp.x + 0.5) + 1 - h1 = heightmap[index1] - else - h1 = this.water_level -- If not in heightmap - end - - local p2 = vector.add(orpi, this.of, this.rs / 2) - if (p2.z >= minp.z and p2.z <= maxp.z and - p2.x >= minp.x and p2.x <= maxp.x) then - local index2 = math.floor(p2.z - minp.z + 0.5) * csize.x + math.floor(p2.x - minp.x + 0.5) + 1 - h2 = heightmap[index2] - else - h2 = this.water_level - end - - -- If startpoint and endpoint are above ground, - -- disable placing of nodes in carveRoute while - -- still running all pseudorandom calls to ensure - -- caves consistent with existing worlds. - local tunnel_above_ground = p1.y > h1 and p2.y > h2 - vec = vector.add(vec, this.main_direction) local rp = vector.add(this.orp, vec) @@ -352,16 +318,15 @@ local function makeTunnel(this, dirswitch) -- Carve routes for f = 0, 1, 1.0 / veclen do --print(dump(vec)) - carveRoute(this, vec, f, randomize_xz, tunnel_above_ground) + carveRoute(this, vec, f, randomize_xz) end this.orp = rp end -local function makeCave(this, max_stone_height) - this.max_stone_y = max_stone_height +local function makeV6Cave(this) + this.max_stone_y = 32000 this.main_direction = vector.new(0, 0, 0) - --print(dump(this)) -- Allowed route area size in nodes this.ar = vector.add(vector.subtract(maxp, minp), 1) @@ -409,7 +374,7 @@ local function makeCave(this, max_stone_height) -- Generate some tunnel starting from orp for j = 0, this.tunnel_routepoints do --print(dump(this.orp)) - makeTunnel(this, j % this.dswitchint == 0) + makeV6Tunnel(this, j % this.dswitchint == 0) end end @@ -424,7 +389,7 @@ local function CaveV6(is_large_cave) this.flooded = true this.lava_cave = false - if maxp.y < this.water_level and minp.y / 31000 - math.random() < -0.5 then + if math.random(2) == 1 then this.lava_cave = true end @@ -446,8 +411,8 @@ local function getBiome(x, z) return nil end -local function generateCaves(max_stone_y) - local cave_amount = minetest.get_perlin(np_cave):get2d({x=minp.x, y=minp.y}) +local function generateV6Caves() + local cave_amount = minetest.get_perlin(cave_noise_v6):get2d({x=minp.x, y=minp.y}) local volume_nodes = (maxp.x - minp.x + 1) * (maxp.y - minp.y + 1) * 16 cave_amount = math.max(0.0, cave_amount) local caves_count = cave_amount * volume_nodes / 50000 @@ -457,17 +422,11 @@ local function generateCaves(max_stone_y) bruises_count = math.random(0, math.random(0, 2)) end - if (getBiome(minp.x, minp.z) == "desert") then - caves_count = caves_count / 3 - bruises_count = caves_count / 3 - end - for i = 0, caves_count + bruises_count do local large_cave = (i >= caves_count) local cave = CaveV6(large_cave) - --print(dump(cave)) - makeCave(cave, max_stone_y) + makeV6Cave(cave) end end @@ -477,20 +436,8 @@ function fun_caves.generate(p_minp, p_maxp, seed) vm, emin, emax = minetest.get_mapgen_object("voxelmanip") vm:get_data(data) --p2data = vm:get_param2_data() - a = VoxelArea:new({MinEdge = emin, MaxEdge = emax}) + area = VoxelArea:new({MinEdge = emin, MaxEdge = emax}) csize = vector.add(vector.subtract(maxp, minp), 1) - heightmap = minetest.get_mapgen_object("heightmap") - - local max_stone_height = -40000 - local index = 0 - for z = minp.z, maxp.z do - for x = minp.x, maxp.x do - index = index + 1 - if max_stone_height < heightmap[index] then - max_stone_height = heightmap[index] - end - end - end -- Deal with memory issues. This, of course, is supposed to be automatic. local mem = math.floor(collectgarbage("count")/1024) @@ -506,31 +453,209 @@ function fun_caves.generate(p_minp, p_maxp, seed) local px = math.floor((minp.x + 32) / csize.x) local pz = math.floor((minp.z + 32) / csize.z) - generateCaves(max_stone_height) + -- Fill with stone. + for z = minp.z, maxp.z do + for y = minp.y, maxp.y do + local ivm = area:index(minp.x, y, z) + for x = minp.x, maxp.x do + data[ivm] = node("default:stone") + ivm = ivm + 1 + end + end + end - --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 made_a_big_one = false + local massive_cave = minetest.get_perlin_map(massive_cave_noise, csize):get3dMap_flat(minp) + local cave_1 = minetest.get_perlin_map(intersect_cave_noise_1, csize):get3dMap_flat(minp) + local cave_2 = minetest.get_perlin_map(intersect_cave_noise_2, csize):get3dMap_flat(minp) + local biome_n = minetest.get_perlin_map(biome_noise, {x=csize.x, y=csize.z}):get2dMap_flat({x=minp.x, y=minp.z}) + local biome_bn = minetest.get_perlin_map(biome_blend, {x=csize.x, y=csize.z}):get2dMap_flat({x=minp.x, y=minp.z}) - -- for y = minp.y, maxp.y do - -- local dy = y - minp.y + 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 = area:index(x, minp.y, z) - -- ivm = ivm + a.ystride - -- index3d = index3d + csize.x - -- end - -- end - --end + for y = minp.y, maxp.y do + local dy = y - minp.y + + if massive_cave[index3d] > massive_cave_threshold then + data[ivm] = node("air") + made_a_big_one = true + else + local n1 = (math.abs(cave_1[index3d]) < 0.08) + local n2 = (math.abs(cave_2[index3d]) < 0.08) + + if n1 and n2 then + local sr = 1000 + if data[ivm] == node("default:stone") then + sr = math.random(1000) + end + + --if sr == 1 then + -- data[ivm] = node("default:lava_source") + --elseif sr == 2 then + -- data[ivm] = node("default:water_source") + --else + data[ivm] = node("air") + --end + end + end + + ivm = ivm + area.ystride + index3d = index3d + csize.x + end + end + end + + if made_a_big_one then + --print("massive cave at "..minp.x..","..minp.y..","..minp.z) + else + generateV6Caves() + end + + 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 + 1) * csize.y * csize.x + dx + local air_count = 0 + local ivm = area:index(x, maxp.y, z) + + for y = maxp.y, minp.y, -1 do + local ivm_below = ivm - area.ystride + local ivm_above = ivm + area.ystride + local dy = y - minp.y + + if data[ivm] == node("air") then + ------------------- + local stone_type = node("default:stone") + local stone_depth = 1 + local biome_val = biome_n[index] + biome_bn[index] + if biome_val < -0.8 then + if true then + stone_type = node("default:ice") + stone_depth = 2 + else + stone_type = node("fun_caves:thinice") + stone_depth = 2 + end + elseif biome_val < -0.7 then + stone_type = node("fun_caves:stone_with_lichen") + elseif biome_val < -0.3 then + stone_type = node("fun_caves:stone_with_moss") + elseif biome_val < 0.2 then + stone_type = node("fun_caves:stone_with_lichen") + elseif biome_val < 0.5 then + stone_type = node("fun_caves:stone_with_algae") + elseif biome_val < 0.6 then + stone_type = node("fun_caves:stone_with_salt") + stone_depth = 2 + elseif biome_val < 0.8 then + stone_type = node("default:coalblock") + stone_depth = 2 + else + stone_type = node("fun_caves:hot_cobble") + end + -- "glow" + + -- Change stone per biome. + if data[ivm_below] == node("default:stone") then + data[ivm_below] = stone_type + if stone_depth == 2 then + data[ivm_below - area.ystride] = stone_type + end + end + if data[ivm_above] == node("default:stone") then + data[ivm_above] = stone_type + if stone_depth == 2 then + data[ivm_above + area.ystride] = stone_type + end + end + + if (data[ivm_above] == node("fun_caves:stone_with_lichen") or data[ivm_above] == node("fun_caves:stone_with_moss")) and math.random(1,20) == 1 then + data[ivm_above] = node("fun_caves:glowing_fungal_stone") + end + + if data[ivm] == node("air") then + local sr = math.random(1,1000) + + -- fluids + if (not made_a_big_one) and data[ivm_below] == node("default:stone") and sr < 10 then + data[ivm] = node("default:lava_source") + elseif (not made_a_big_one) and data[ivm_below] == node("fun_caves:stone_with_moss") and sr < 10 then + data[ivm] = node("default:water_source") + -- hanging down + elseif data[ivm_above] == node("default:ice") and sr < 80 then + data[ivm] = node("fun_caves:icicle_down") + elseif (data[ivm_above] == node("fun_caves:stone_with_lichen") or data[ivm_above] == node("fun_caves:stone_with_moss") or data[ivm_above] == node("fun_caves:stone_with_algae") or data[ivm_above] == node("default:stone")) and sr < 80 then + if data[ivm_above] == node("fun_caves:stone_with_algae") then + data[ivm] = node("fun_caves:stalactite_slimy") + elseif data[ivm_above] == node("fun_caves:stone_with_moss") then + data[ivm] = node("fun_caves:stalactite_mossy") + else + data[ivm] = node("fun_caves:stalactite") + end + -- standing up + elseif data[ivm_below] == node("default:coalblock") and sr < 20 then + data[ivm] = node("fun_caves:constant_flame") + elseif data[ivm_below] == node("default:ice") and sr < 80 then + data[ivm] = node("fun_caves:icicle_up") + elseif (data[ivm_below] == node("fun_caves:stone_with_lichen") or data[ivm_below] == node("fun_caves:stone_with_algae") or data[ivm_below] == node("default:stone") or data[ivm_below] == node("fun_caves:stone_with_moss")) and sr < 80 then + if data[ivm_below] == node("fun_caves:stone_with_algae") then + data[ivm] = node("fun_caves:stalagmite_slimy") + elseif data[ivm_below] == node("fun_caves:stone_with_moss") then + data[ivm] = node("fun_caves:stalagmite_mossy") + elseif data[ivm_below] == node("fun_caves:stone_with_lichen") or data[ivm_above] == node("default:stone") then + data[ivm] = node("fun_caves:stalagmite") + end + -- vegetation + elseif (data[ivm_below] == node("fun_caves:stone_with_lichen") or data[ivm_below] == node("fun_caves:stone_with_algae")) and biome_val >= -0.7 then + if sr < 110 then + data[ivm] = node("flowers:mushroom_red") + elseif sr < 140 then + data[ivm] = node("flowers:mushroom_brown") + elseif air_count > 1 and sr < 160 then + data[ivm_above] = node("fun_caves:huge_mushroom_cap") + data[ivm] = node("fun_caves:giant_mushroom_stem") + elseif air_count > 2 and sr < 170 then + data[ivm + 2 * area.ystride] = node("fun_caves:giant_mushroom_cap") + data[ivm_above] = node("fun_caves:giant_mushroom_stem") + data[ivm] = node("fun_caves:giant_mushroom_stem") + elseif made_a_big_one and air_count > 5 and sr < 180 then + fun_caves.make_fungal_tree(data, area, ivm, math.random(2,math.min(air_count, 12)), node(fun_caves.fungal_tree_leaves[math.random(1,#fun_caves.fungal_tree_leaves)]), node("fun_caves:fungal_tree_fruit")) + data[ivm_below] = node("dirt") + elseif sr < 300 then + data[ivm_below] = node("dirt") + end + if data[ivm] ~= node("air") then + data[ivm_below] = node("dirt") + end + end + end + + if data[ivm] == node("air") then + air_count = air_count + 1 + end + end + + ivm = ivm - area.ystride + index3d = index3d - csize.x + end + end + end vm:set_data(data) - --minetest.generate_ores(vm, minp, maxp) - --minetest.generate_decorations(vm, minp, maxp) + minetest.generate_ores(vm, minp, maxp) --vm:set_param2_data(p2data) if DEBUG then vm:set_lighting({day = 15, night = 15}) @@ -541,5 +666,36 @@ function fun_caves.generate(p_minp, p_maxp, seed) vm:update_liquids() vm:write_to_map() - vm, a, lightmap, heightmap, biomemap, terrain, cave = nil, nil, nil, nil, nil, nil, nil + vm, area, lightmap, terrain, cave = nil, nil, nil, nil, nil +end + +function fun_caves.respawn(player) + local pos = {x=0,y=0,z=0} + local massive_cave = minetest.get_perlin(massive_cave_noise):get3d(pos) + local biome_n = minetest.get_perlin(biome_noise):get2d({x=pos.x, y=pos.z}) + local biome_bn = minetest.get_perlin(biome_blend):get2d({x=pos.x, y=pos.z}) + local biome = biome_n + biome_bn + + while biome < 0.3 or biome > 0.5 do + pos.x = pos.x + math.random(20) - 10 + pos.z = pos.z + math.random(20) - 10 + + biome_n = minetest.get_perlin(biome_noise):get2d({x=pos.x, y=pos.z}) + biome_bn = minetest.get_perlin(biome_blend):get2d({x=pos.x, y=pos.z}) + biome = biome_n + biome_bn + end + + while massive_cave <= massive_cave_threshold do + pos.y = pos.y + 80 + massive_cave = minetest.get_perlin(massive_cave_noise):get3d(pos) + end + + while massive_cave > massive_cave_threshold do + pos.y = pos.y - 1 + massive_cave = minetest.get_perlin(massive_cave_noise):get3d(pos) + end + + pos.y = pos.y + 1 + player:setpos(pos) + return true -- Disable default player spawner end diff --git a/nodes.lua b/nodes.lua new file mode 100644 index 0000000..bb8d10f --- /dev/null +++ b/nodes.lua @@ -0,0 +1,544 @@ +---------------------- +-- Cave Decorations -- +---------------------- + +-- Mushrooms and Speleothems +-- These are instantiated by voxel.lua since the decoration manager +-- only works at the surface of the world. + +local light_max = 12 + +minetest.register_node("fun_caves:huge_mushroom_cap", { + description = "Huge Mushroom Cap", + tiles = {"vmg_mushroom_giant_cap.png", "vmg_mushroom_giant_under.png", "vmg_mushroom_giant_cap.png"}, + is_ground_content = false, + paramtype = "light", + drawtype = "nodebox", + node_box = { type = "fixed", + fixed = { + {-0.5, -0.5, -0.33, 0.5, -0.33, 0.33}, + {-0.33, -0.5, 0.33, 0.33, -0.33, 0.5}, + {-0.33, -0.5, -0.33, 0.33, -0.33, -0.5}, + {-0.33, -0.33, -0.33, 0.33, -0.17, 0.33}, + } }, + light_source = 10, + groups = {fleshy=1, dig_immediate=3, flammable=2, plant=1, leafdecay=1}, +}) + +minetest.register_node("fun_caves:giant_mushroom_cap", { + description = "Giant Mushroom Cap", + tiles = {"vmg_mushroom_giant_cap.png", "vmg_mushroom_giant_under.png", "vmg_mushroom_giant_cap.png"}, + is_ground_content = false, + paramtype = "light", + drawtype = "nodebox", + node_box = { type = "fixed", + fixed = { + {-0.4, -0.5, -0.4, 0.4, 0.0, 0.4}, + {-0.75, -0.5, -0.4, -0.4, -0.25, 0.4}, + {0.4, -0.5, -0.4, 0.75, -0.25, 0.4}, + {-0.4, -0.5, -0.75, 0.4, -0.25, -0.4}, + {-0.4, -0.5, 0.4, 0.4, -0.25, 0.75}, + } }, + light_source = 10, + groups = {fleshy=1, dig_immediate=3, flammable=2, plant=1, leafdecay=1}, +}) + +minetest.register_node("fun_caves:giant_mushroom_stem", { + description = "Giant Mushroom Stem", + tiles = {"vmg_mushroom_giant_stem.png", "vmg_mushroom_giant_stem.png", "vmg_mushroom_giant_stem.png"}, + is_ground_content = false, + groups = {tree=1,choppy=2,oddly_breakable_by_hand=1,flammable=2, plant=1}, + sounds = default.node_sound_wood_defaults(), + paramtype = "light", + drawtype = "nodebox", + node_box = { type = "fixed", fixed = { {-0.25, -0.5, -0.25, 0.25, 0.5, 0.25}, }}, +}) + +-- Mushroom stems can be used as wood, ala Journey to the Center of the Earth. +minetest.register_craft({ + output = "default:wood", + recipe = { + {"fun_caves:giant_mushroom_stem"} + } +}) + +-- Caps can be cooked and eaten. +minetest.register_node("fun_caves:mushroom_steak", { + description = "Mushroom Steak", + drawtype = "plantlike", + paramtype = "light", + tiles = {"vmg_mushroom_steak.png"}, + inventory_image = "vmg_mushroom_steak.png", + on_use = minetest.item_eat(4), + groups = {dig_immediate = 3, attached_node = 1}, +}) + +minetest.register_craft({ + type = "cooking", + output = "fun_caves:mushroom_steak", + recipe = "fun_caves:huge_mushroom_cap", + cooktime = 2, +}) + +minetest.register_craft({ + type = "cooking", + output = "fun_caves:mushroom_steak 2", + recipe = "fun_caves:giant_mushroom_cap", + cooktime = 2, +}) + +-- Glowing fungal stone provides an eerie light. +minetest.register_node("fun_caves:glowing_fungal_stone", { + description = "Glowing Fungal Stone", + tiles = {"default_stone.png^vmg_glowing_fungal.png",}, + is_ground_content = true, + light_source = 12, + groups = {cracky=3, stone=1}, + drop = {items={ {items={"default:cobble"},}, {items={"fun_caves:glowing_fungus",},},},}, + sounds = default.node_sound_stone_defaults(), +}) + +minetest.register_node("fun_caves:glowing_fungus", { + description = "Glowing Fungus", + drawtype = "plantlike", + paramtype = "light", + tiles = {"vmg_glowing_fungus.png"}, + inventory_image = "vmg_glowing_fungus.png", + groups = {dig_immediate = 3, attached_node = 1}, +}) + +-- The fungus can be made into juice and then into glowing glass. +minetest.register_node("fun_caves:moon_juice", { + description = "Moon Juice", + drawtype = "plantlike", + paramtype = "light", + tiles = {"vmg_moon_juice.png"}, + inventory_image = "vmg_moon_juice.png", + groups = {dig_immediate = 3, attached_node = 1}, + sounds = default.node_sound_glass_defaults(), +}) + +minetest.register_node("fun_caves:moon_glass", { + description = "Moon Glass", + drawtype = "glasslike", + tiles = {"default_glass.png",}, + inventory_image = minetest.inventorycube("default_glass.png"), + is_ground_content = true, + light_source = default.LIGHT_MAX, + groups = {cracky=3}, + sounds = default.node_sound_glass_defaults(), +}) + +minetest.register_craft({ + output = "fun_caves:moon_juice", + recipe = { + {"fun_caves:glowing_fungus", "fun_caves:glowing_fungus", "fun_caves:glowing_fungus"}, + {"fun_caves:glowing_fungus", "fun_caves:glowing_fungus", "fun_caves:glowing_fungus"}, + {"fun_caves:glowing_fungus", "vessels:glass_bottle", "fun_caves:glowing_fungus"}, + }, +}) + +minetest.register_craft({ + output = "fun_caves:moon_glass", + type = "shapeless", + recipe = { + "fun_caves:moon_juice", + "fun_caves:moon_juice", + "default:glass", + }, +}) + +-- What's a cave without speleothems? +local spel = { + {type1="stalactite", type2="stalagmite", tile="default_stone.png"}, + {type1="stalactite_slimy", type2="stalagmite_slimy", tile="default_stone.png^fun_caves_algae.png"}, + {type1="stalactite_mossy", type2="stalagmite_mossy", tile="default_stone.png^fun_caves_moss.png"}, + {type1="icicle_down", type2="icicle_up", desc="Icicle", tile="caverealms_thin_ice.png", drop="default:ice"}, +} + +for _, desc in pairs(spel) do + minetest.register_node("fun_caves:"..desc.type1, { + description = (desc.desc or "Stalactite"), + tiles = {desc.tile}, + is_ground_content = true, + walkable = false, + paramtype = "light", + --light_source = 14, + drop = (desc.drop or "fun_caves:stalactite"), + drawtype = "nodebox", + node_box = { type = "fixed", + fixed = { + {-0.07, 0.0, -0.07, 0.07, 0.5, 0.07}, + {-0.04, -0.25, -0.04, 0.04, 0.0, 0.04}, + {-0.02, -0.5, -0.02, 0.02, 0.25, 0.02}, + } }, + groups = {rock=1, cracky=3}, + sounds = default.node_sound_stone_defaults(), + }) + + minetest.register_node("fun_caves:"..desc.type2, { + description = (desc.desc or "Stalagmite"), + tiles = {desc.tile}, + is_ground_content = true, + walkable = false, + paramtype = "light", + --light_source = 14, + drop = "fun_caves:stalagmite", + drawtype = "nodebox", + node_box = { type = "fixed", + fixed = { + {-0.07, -0.5, -0.07, 0.07, 0.0, 0.07}, + {-0.04, 0.0, -0.04, 0.04, 0.25, 0.04}, + {-0.02, 0.25, -0.02, 0.02, 0.5, 0.02}, + } }, + groups = {rock=1, cracky=3}, + sounds = default.node_sound_stone_defaults(), + }) +end + +-- They can be made into cobblestone, to get them out of inventory. +minetest.register_craft({ + output = "default:cobble", + recipe = { + {"", "", ""}, + {"fun_caves:stalactite", "fun_caves:stalactite", ""}, + {"fun_caves:stalactite", "fun_caves:stalactite", ""}, + }, +}) + +minetest.register_craft({ + output = "default:cobble", + recipe = { + {"", "", ""}, + {"fun_caves:stalagmite", "fun_caves:stalagmite", ""}, + {"fun_caves:stalagmite", "fun_caves:stalagmite", ""}, + }, +}) + +minetest.register_node("fun_caves:glowing_dirt", { + description = "Glowing Dirt", + tiles = {"default_dirt.png"}, + groups = {crumbly = 3, soil = 1}, + light_source = default.LIGHT_MAX, + sounds = default.node_sound_dirt_defaults(), + soil = { + base = "fun_caves:glowing_dirt", + dry = "fun_caves:glowing_soil", + wet = "fun_caves:glowing_soil_wet" + }, +}) + +minetest.register_node("fun_caves:glowing_soil", { + description = "Glowing Soil", + tiles = {"default_dirt.png^farming_soil.png", "default_dirt.png"}, + drop = "fun_caves:glowing_dirt", + groups = {crumbly=3, not_in_creative_inventory=1, soil=2, grassland = 1, field = 1}, + sounds = default.node_sound_dirt_defaults(), + light_source = default.LIGHT_MAX, + soil = { + base = "fun_caves:glowing_dirt", + dry = "fun_caves:glowing_soil", + wet = "fun_caves:glowing_soil_wet" + }, +}) + +minetest.register_node("fun_caves:glowing_soil_wet", { + description = "Wet Glowing Soil", + tiles = {"default_dirt.png^farming_soil_wet.png", "default_dirt.png^farming_soil_wet_side.png"}, + drop = "fun_caves:glowing_dirt", + groups = {crumbly=3, not_in_creative_inventory=1, soil=3, wet = 1, grassland = 1, field = 1}, + sounds = default.node_sound_dirt_defaults(), + light_source = default.LIGHT_MAX, + soil = { + base = "fun_caves:glowing_dirt", + dry = "fun_caves:glowing_soil", + wet = "fun_caves:glowing_soil_wet" + }, +}) + +minetest.register_craft({ + output = "fun_caves:glowing_dirt", + type = "shapeless", + recipe = { + "fun_caves:moon_juice", + "default:dirt", + }, +}) + +--thin (transparent) ice +minetest.register_node("fun_caves:thin_ice", { + description = "Thin Ice", + tiles = {"caverealms_thin_ice.png"}, + is_ground_content = true, + groups = {cracky=3}, + sounds = default.node_sound_glass_defaults(), + use_texture_alpha = true, + light_source = 1, + drawtype = "glasslike", + sunlight_propagates = true, + freezemelt = "default:water_source", + paramtype = "light", +}) + +minetest.register_node("fun_caves:stone_with_moss", { + description = "Cave Stone with Moss", + tiles = {"default_stone.png^fun_caves_moss.png"}, + is_ground_content = true, + light_source = 10, + groups = {stone=1, crumbly=3}, + drop = 'default:cobble', + sounds = default.node_sound_dirt_defaults({ + footstep = {name="default_grass_footstep", gain=0.25}, + }), +}) + +minetest.register_node("fun_caves:stone_with_lichen", { + description = "Cave Stone with Lichen", + tiles = {"default_stone.png^fun_caves_lichen.png"}, + is_ground_content = true, + light_source = 10, + groups = {stone=1, crumbly=3}, + drop = 'default:cobble', + sounds = default.node_sound_dirt_defaults({ + footstep = {name="default_grass_footstep", gain=0.25}, + }), +}) + +minetest.register_node("fun_caves:stone_with_algae", { + description = "Cave Stone with Algae", + tiles = {"default_stone.png^fun_caves_algae.png"}, + is_ground_content = true, + light_source = 10, + groups = {stone=1, crumbly=3}, + drop = 'default:cobble', + sounds = default.node_sound_dirt_defaults({ + footstep = {name="default_grass_footstep", gain=0.25}, + }), +}) + +minetest.register_node("fun_caves:stone_with_salt", { + description = "Cave Stone with Salt", + tiles = {"caverealms_salty2.png"},--{"caverealms_salty2.png^caverealms_salty.png", "caverealms_salty2.png", "caverealms_salty2.png^caverealms_salty_side.png"}, + light_source = 9, + paramtype = "light", + use_texture_alpha = true, + drawtype = "glasslike", + sunlight_propagates = true, + is_ground_content = true, + groups = {stone=1, crumbly=3}, + sounds = default.node_sound_glass_defaults(), +}) + +--Glow Obsidian +minetest.register_node("fun_caves:glow_obsidian", { + description = "Glowing Obsidian", + tiles = {"caverealms_glow_obsidian.png"}, + is_ground_content = true, + groups = {stone=2, crumbly=1}, + light_source = 7, + sounds = default.node_sound_stone_defaults({ + footstep = {name="default_stone_footstep", gain=0.25}, + }), +}) + +--Glow Obsidian 2 - has traces of lava +minetest.register_node("fun_caves:glow_obsidian_2", { + description = "Hot Glow Obsidian", + tiles = {"caverealms_glow_obsidian2.png"}, + is_ground_content = true, + groups = {stone=2, crumbly=1, hot=1}, + damage_per_second = 1, + light_source = 9, + sounds = default.node_sound_stone_defaults({ + footstep = {name="default_stone_footstep", gain=0.25}, + }), +}) + + +--minetest.register_node("fun_caves:bright_air", { +-- drawtype = "glasslike", +-- tiles = {"technic_light.png"}, +-- paramtype = "light", +-- groups = {not_in_creative_inventory=1}, +-- drop = "", +-- walkable = false, +-- buildable_to = true, +-- sunlight_propagates = true, +-- light_source = LIGHT_MAX, +-- pointable = false, +--}) + +--define special flame so that it does not expire +minetest.register_node("fun_caves:constant_flame", { + description = "Fire", + drawtype = "plantlike", + tiles = {{ + name="fire_basic_flame_animated.png", + animation={type="vertical_frames", aspect_w=16, aspect_h=16, length=1}, + }}, + inventory_image = "fire_basic_flame.png", + light_source = 14, + groups = {igniter=2,dig_immediate=3,hot=3, not_in_creative_inventory=1}, + drop = '', + walkable = false, + buildable_to = true, + damage_per_second = 4, +}) + +--Hot Cobble - cobble with lava instead of mortar XD +minetest.register_node("fun_caves:hot_cobble", { + description = "Hot Cobble", + tiles = {"caverealms_hot_cobble.png"}, + is_ground_content = true, + groups = {crumbly=2, hot=1}, + damage_per_second = 1, + light_source = 6, + sounds = default.node_sound_stone_defaults({ + footstep = {name="default_stone_footstep", gain=0.25}, + }), +}) + +-- mushroom growth +minetest.register_abm({ + nodenames = {"flowers:mushroom_brown", "flowers:mushroom_red"}, + interval = 50 * fun_caves.time_factor, + chance = 100, + action = function(pos, node) + local pos_up = {x=pos.x,y=pos.y+1,z=pos.z} + local node_up = minetest.get_node_or_nil(pos_up) + if not node_up then + return + end + if node_up.name ~= "air" then + return + end + local node_under = minetest.get_node_or_nil({x = pos.x, y = pos.y - 1, z = pos.z}) + if not node_under then + return + end + if minetest.get_item_group(node_under.name, "soil") ~= 0 and + minetest.get_node_light(pos_up, nil) <= light_max then + minetest.set_node(pos_up, {name = "fun_caves:huge_mushroom_cap"}) + minetest.set_node(pos, {name = "fun_caves:giant_mushroom_stem"}) + end + end +}) + +-- mushroom growth +minetest.register_abm({ + nodenames = {"fun_caves:huge_mushroom_cap"}, + interval = 100 * fun_caves.time_factor, + chance = 150, + action = function(pos, node) + if minetest.get_node_light(pos, nil) >= 14 then + minetest.set_node(pos, {name = "air"}) + return + end + local pos_up = {x=pos.x,y=pos.y+1,z=pos.z} + local node_up = minetest.get_node_or_nil(pos_up) + if not node_up then + return + end + if node_up.name ~= "air" then + return + end + local node_under = minetest.get_node_or_nil({x = pos.x, y = pos.y - 1, z = pos.z}) + if not node_under or node_under.name ~= "fun_caves:giant_mushroom_stem" then + return + end + node_under = minetest.get_node_or_nil({x = pos.x, y = pos.y - 2, z = pos.z}) + if not node_under then + return + end + if minetest.get_item_group(node_under.name, "soil") ~= 0 and + minetest.get_node_light(pos_up, nil) <= light_max then + minetest.set_node(pos_up, {name = "fun_caves:giant_mushroom_cap"}) + minetest.set_node(pos, {name = "fun_caves:giant_mushroom_stem"}) + end + end +}) + +-- mushroom growth +minetest.register_abm({ + nodenames = {"fun_caves:giant_mushroom_stem"}, + interval = 5 * fun_caves.time_factor, + chance = 5, + action = function(pos, node) + local pos_up = {x=pos.x,y=pos.y+1,z=pos.z} + local node_up = minetest.get_node_or_nil(pos_up) + if not node_up then + return + end + if node_up.name ~= "air" then + return + end + if minetest.get_node_light(pos_up, nil) <= light_max then + minetest.set_node(pos_up, {name = "fun_caves:huge_mushroom_cap"}) + end + end +}) + +-- mushroom spread +minetest.register_abm({ + nodenames = {"fun_caves:giant_mushroom_cap", "fun_caves:huge_mushroom_cap"}, + interval = 3 * fun_caves.time_factor, + chance = 40, + action = function(pos, node) + if minetest.get_node_light(pos, nil) >= 14 then + minetest.set_node(pos, {name = "air"}) + return + end + local pos_down = pos + pos_down.y = pos_down.y - 1 + local pos1, count = minetest.find_nodes_in_area_under_air(vector.subtract(pos_down, 4), vector.add(pos_down, 4), {"group:soil"}) + if #pos1 < 1 then + return + end + local random = pos1[math.random(1, #pos1)] + random.y = random.y + 1 + local mushroom_type + if math.random(1,2) == 1 then + mushroom_type = "flowers:mushroom_red" + else + mushroom_type = "flowers:mushroom_brown" + end + if minetest.get_node_light(random, nil) <= light_max then + minetest.set_node(random, {name = mushroom_type}) + end + end +}) + +-- Mushroom spread and death +minetest.register_abm({ + nodenames = {"flowers:mushroom_brown", "flowers:mushroom_red"}, + interval = 3 * fun_caves.time_factor, + chance = 50, + action = function(pos, node) + if minetest.get_node_light(pos, nil) == 15 then + minetest.remove_node(pos) + return + end + local random = { + x = pos.x + math.random(-2, 2), + y = pos.y + math.random(-1, 1), + z = pos.z + math.random(-2, 2) + } + local random_node = minetest.get_node_or_nil(random) + if not random_node or random_node.name ~= "air" then + return + end + local node_under = minetest.get_node_or_nil({x = random.x, + y = random.y - 1, z = random.z}) + if not node_under then + return + end + + if (minetest.get_item_group(node_under.name, "soil") ~= 0 or + minetest.get_item_group(node_under.name, "tree") ~= 0) and + minetest.get_node_light(pos, 0.5) <= light_max and + minetest.get_node_light(random, 0.5) <= light_max then + minetest.set_node(random, {name = node.name}) + end + end +}) + diff --git a/textures/caverealms_algae.png b/textures/caverealms_algae.png new file mode 100644 index 0000000..980a4a1 Binary files /dev/null and b/textures/caverealms_algae.png differ diff --git a/textures/caverealms_glow_obsidian.png b/textures/caverealms_glow_obsidian.png new file mode 100644 index 0000000..a157738 Binary files /dev/null and b/textures/caverealms_glow_obsidian.png differ diff --git a/textures/caverealms_glow_obsidian2.png b/textures/caverealms_glow_obsidian2.png new file mode 100644 index 0000000..2702d59 Binary files /dev/null and b/textures/caverealms_glow_obsidian2.png differ diff --git a/textures/caverealms_hot_cobble.png b/textures/caverealms_hot_cobble.png new file mode 100644 index 0000000..2e873e8 Binary files /dev/null and b/textures/caverealms_hot_cobble.png differ diff --git a/textures/caverealms_salty2.png b/textures/caverealms_salty2.png new file mode 100644 index 0000000..7f8b521 Binary files /dev/null and b/textures/caverealms_salty2.png differ diff --git a/textures/caverealms_thin_ice.png b/textures/caverealms_thin_ice.png new file mode 100644 index 0000000..b16036d Binary files /dev/null and b/textures/caverealms_thin_ice.png differ diff --git a/textures/fun_caves_algae.png b/textures/fun_caves_algae.png new file mode 100644 index 0000000..2e75111 Binary files /dev/null and b/textures/fun_caves_algae.png differ diff --git a/textures/fun_caves_brain_coral.png b/textures/fun_caves_brain_coral.png new file mode 100644 index 0000000..0e7de78 Binary files /dev/null and b/textures/fun_caves_brain_coral.png differ diff --git a/textures/fun_caves_dragon_eye.png b/textures/fun_caves_dragon_eye.png new file mode 100644 index 0000000..ec9294d Binary files /dev/null and b/textures/fun_caves_dragon_eye.png differ diff --git a/textures/fun_caves_fungal_tree_fruit.png b/textures/fun_caves_fungal_tree_fruit.png new file mode 100644 index 0000000..b4e6eb3 Binary files /dev/null and b/textures/fun_caves_fungal_tree_fruit.png differ diff --git a/textures/fun_caves_fungal_tree_leaves.png b/textures/fun_caves_fungal_tree_leaves.png new file mode 100644 index 0000000..58ebb53 Binary files /dev/null and b/textures/fun_caves_fungal_tree_leaves.png differ diff --git a/textures/fun_caves_lichen.png b/textures/fun_caves_lichen.png new file mode 100644 index 0000000..446836d Binary files /dev/null and b/textures/fun_caves_lichen.png differ diff --git a/textures/fun_caves_lumin_tree.png b/textures/fun_caves_lumin_tree.png new file mode 100644 index 0000000..4578023 Binary files /dev/null and b/textures/fun_caves_lumin_tree.png differ diff --git a/textures/fun_caves_moss.png b/textures/fun_caves_moss.png new file mode 100644 index 0000000..ea0f75a Binary files /dev/null and b/textures/fun_caves_moss.png differ diff --git a/textures/fun_caves_pillar_coral.png b/textures/fun_caves_pillar_coral.png new file mode 100644 index 0000000..0c5b515 Binary files /dev/null and b/textures/fun_caves_pillar_coral.png differ diff --git a/textures/fun_caves_staghorn_coral.png b/textures/fun_caves_staghorn_coral.png new file mode 100644 index 0000000..05857aa Binary files /dev/null and b/textures/fun_caves_staghorn_coral.png differ diff --git a/textures/vmg_glowing_fungal.png b/textures/vmg_glowing_fungal.png new file mode 100644 index 0000000..d3a7134 Binary files /dev/null and b/textures/vmg_glowing_fungal.png differ diff --git a/textures/vmg_glowing_fungus.png b/textures/vmg_glowing_fungus.png new file mode 100644 index 0000000..0645e30 Binary files /dev/null and b/textures/vmg_glowing_fungus.png differ diff --git a/textures/vmg_moon_juice.png b/textures/vmg_moon_juice.png new file mode 100644 index 0000000..931b736 Binary files /dev/null and b/textures/vmg_moon_juice.png differ diff --git a/textures/vmg_moon_weed.png b/textures/vmg_moon_weed.png new file mode 100644 index 0000000..ea67943 Binary files /dev/null and b/textures/vmg_moon_weed.png differ diff --git a/textures/vmg_mushroom_giant_cap.png b/textures/vmg_mushroom_giant_cap.png new file mode 100644 index 0000000..73f4aba Binary files /dev/null and b/textures/vmg_mushroom_giant_cap.png differ diff --git a/textures/vmg_mushroom_giant_stem.png b/textures/vmg_mushroom_giant_stem.png new file mode 100644 index 0000000..6c94eca Binary files /dev/null and b/textures/vmg_mushroom_giant_stem.png differ diff --git a/textures/vmg_mushroom_giant_under.png b/textures/vmg_mushroom_giant_under.png new file mode 100644 index 0000000..4f51b31 Binary files /dev/null and b/textures/vmg_mushroom_giant_under.png differ diff --git a/textures/vmg_mushroom_steak.png b/textures/vmg_mushroom_steak.png new file mode 100644 index 0000000..73b7509 Binary files /dev/null and b/textures/vmg_mushroom_steak.png differ diff --git a/textures/vmg_small_rocks.png b/textures/vmg_small_rocks.png new file mode 100644 index 0000000..9b108fc Binary files /dev/null and b/textures/vmg_small_rocks.png differ