diff --git a/nether/LICENSE.txt b/nether/LICENSE.txt new file mode 100644 index 00000000..c43a1797 --- /dev/null +++ b/nether/LICENSE.txt @@ -0,0 +1,2 @@ +GPLv3 (lkloel's version) +MIT for the changes diff --git a/nether/README.md b/nether/README.md new file mode 100644 index 00000000..a2a9712b --- /dev/null +++ b/nether/README.md @@ -0,0 +1,15 @@ +For a description of this Minetest mod, please refer to the forum topic: +https://forum.minetest.net/viewtopic.php?f=9&t=10265 + + +TODO: +* Find a way to get the perlin noise inside [-1; 1] or use another noise +* Add some node which containing items to the simple pyramid "buildings" +* Change the sky background, fog, etc. in the nether +* Improve the guide formspec. + Writing it in Markdown would be nice. + These could be useful: + * https://forum.minetest.net/viewtopic.php?t=23855 + Minetest Bedrock Markup Language + * https://github.com/mpeterv/markdown + Markdown to HTML converter; Minetest formspecs support HTML diff --git a/nether/modpack.txt b/nether/modpack.txt new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/nether/modpack.txt @@ -0,0 +1 @@ +0 diff --git a/nether/nether/crafting.lua b/nether/nether/crafting.lua new file mode 100644 index 00000000..73e1b8f7 --- /dev/null +++ b/nether/nether/crafting.lua @@ -0,0 +1,253 @@ +minetest.register_craft({ + output = "nether:fim", + recipe = { + {"nether:shroom_head"}, + {"nether:fruit_no_leaf"}, + {"nether:shroom_head"}, + } +}) + +minetest.register_craft({ + output = "nether:fruit_leaves", + recipe = { + {"nether:fruit_leaf", "nether:fruit_leaf", "nether:fruit_leaf"}, + {"nether:fruit_leaf", "nether:fruit_leaf", "nether:fruit_leaf"}, + {"nether:fruit_leaf", "nether:fruit_leaf", "nether:fruit_leaf"}, + } +}) + +minetest.register_craft({ + output = "nether:pick_mushroom", + recipe = { + {"nether:shroom_head", "nether:shroom_head", "nether:shroom_head"}, + {"", "nether:shroom_stem", ""}, + {"", "nether:shroom_stem", ""}, + } +}) + +minetest.register_craft({ + output = "nether:pick_wood", + recipe = { + {"nether:wood_cooked", "nether:wood_cooked", "nether:wood_cooked"}, + {"", "group:stick", ""}, + {"", "group:stick", ""}, + } +}) + +for _,m in pairs({"netherrack", "netherrack_blue", "white"}) do + local input = "nether:"..m + + minetest.register_craft({ + output = "nether:pick_"..m, + recipe = { + {input, input, input}, + {"", "group:stick", ""}, + {"", "group:stick", ""}, + } + }) + + minetest.register_craft({ + output = "nether:axe_"..m, + recipe = { + {input, input}, + {input, "group:stick"}, + {"", "group:stick"}, + } + }) + + minetest.register_craft({ + output = "nether:sword_"..m, + recipe = { + {input}, + {input}, + {"group:stick"}, + } + }) + + minetest.register_craft({ + output = "nether:shovel_"..m, + recipe = { + {input}, + {"group:stick"}, + {"group:stick"}, + } + }) +end + +minetest.register_craft({ + output = "nether:netherrack_brick 4", + recipe = { + {"nether:netherrack", "nether:netherrack"}, + {"nether:netherrack", "nether:netherrack"}, + } +}) + +minetest.register_craft({ + output = "nether:netherrack_brick_black 4", + recipe = { + {"nether:netherrack_black", "nether:netherrack_black"}, + {"nether:netherrack_black", "nether:netherrack_black"}, + } +}) + +minetest.register_craft({ + output = "nether:netherrack_brick_blue 4", + recipe = { + {"nether:netherrack_blue", "nether:netherrack_blue"}, + {"nether:netherrack_blue", "nether:netherrack_blue"}, + } +}) + +minetest.register_craft({ + output = "default:furnace", + recipe = { + {"nether:netherrack_brick", "nether:netherrack_brick", "nether:netherrack_brick"}, + {"nether:netherrack_brick", "", "nether:netherrack_brick"}, + {"nether:netherrack_brick", "nether:netherrack_brick", "nether:netherrack_brick"}, + } +}) + +minetest.register_craft({ + output = "nether:extractor", + recipe = { + {"nether:netherrack_brick", "nether:blood_top_cooked", "nether:netherrack_brick"}, + {"nether:blood_cooked", "nether:shroom_stem", "nether:blood_cooked"}, + {"nether:netherrack_brick", "nether:blood_stem_cooked", "nether:netherrack_brick"}, + } +}) + +minetest.register_craft({ + output = "nether:wood 4", + recipe = { + {"nether:blood_stem"}, + } +}) + +minetest.register_craft({ + output = "nether:wood_empty 4", + recipe = { + {"nether:blood_stem_empty"}, + } +}) + +minetest.register_craft({ + output = "nether:stick 4", + recipe = { + {"nether:wood_empty"}, + } +}) + +minetest.register_craft({ + output = "nether:torch", + recipe = { + {"nether:bark"}, + {"group:stick"}, + } +}) + +minetest.register_craft({ + output = "nether:forest_wood", + recipe = { + {"nether:forest_planks", "nether:forest_planks", "nether:forest_planks"}, + {"nether:forest_planks", "", "nether:forest_planks"}, + {"nether:forest_planks", "nether:forest_planks", "nether:forest_planks"}, + } +}) + +minetest.register_craft({ + output = "nether:forest_planks 8", + recipe = { + {"nether:forest_wood"}, + } +}) + +minetest.register_craft({ + output = "nether:forest_planks 7", + recipe = { + {"nether:tree"}, + }, +}) + +local sound_allowed = true +minetest.register_on_craft(function(itemstack, player, old_craft_grid, craft_inv) + if itemstack:get_name() ~= "nether:forest_planks" + or itemstack:get_count() ~= 7 then + return + end + local tree + for i = 1,9 do + if old_craft_grid[i]:get_name() == "nether:tree" then + tree = i + break + end + end + if not tree then -- do nth if theres no tree + return + end + local rdif = math.random(-1,1) -- add a bit randomness + local barkstack = ItemStack("nether:bark "..4-rdif) + local inv = player:get_inventory() + if not inv:room_for_item("main", barkstack) then -- disallow crafting if there's not enough free space + craft_inv:set_list("craft", old_craft_grid) + itemstack:set_name("") + return + end + itemstack:set_count(7+rdif) + inv:add_item("main", barkstack) + if not sound_allowed then -- avoid playing the sound multiple times, e.g. when middle mouse click + return + end + minetest.sound_play("default_wood_footstep", {pos=player:get_pos(), gain=0.25}) + sound_allowed = false + minetest.after(0, function() + sound_allowed = true + end) +end) + +minetest.register_craft({ + output = "default:paper", + recipe = { + {"nether:grass_dried", "nether:grass_dried", "nether:grass_dried"}, + } +}) + + +minetest.register_craft({ + type = "cooking", + output = "default:coal_lump", + recipe = "nether:tree", +}) + +minetest.register_craft({ + type = "cooking", + output = "nether:grass_dried", + recipe = "nether:grass", +}) + +minetest.register_craft({ + type = "cooking", + output = "nether:pearl", + recipe = "nether:fim", +}) + +minetest.register_craft({ + type = "cooking", + output = "nether:hotbed", + recipe = "nether:blood_extracted", +}) + +for _,i in ipairs({"nether:blood", "nether:blood_top", "nether:blood_stem", "nether:wood"}) do + local cooked = i.."_cooked" + + minetest.register_craft({ + type = "cooking", + output = cooked, + recipe = i, + }) + + minetest.register_craft({ + type = "fuel", + recipe = cooked, + burntime = 30, + }) +end diff --git a/nether/nether/furnace.lua b/nether/nether/furnace.lua new file mode 100644 index 00000000..577d7374 --- /dev/null +++ b/nether/nether/furnace.lua @@ -0,0 +1,346 @@ +-- minetest time speed +local time_speed = tonumber(minetest.settings:get("time_speed")) +if not time_speed then + time_speed = 1 +else + time_speed = time_speed/72 +end + +local function get_date() + return os.date("%y %d %H %M %S") +end + +-- returns the time difference in seconds +local function get_timediff(d1, d2) + local d = string.split(d1, " ") + for n,i in pairs(string.split(d2, " ")) do + d[n] = i-d[n] + end + local secs = 0 + local y,d,h,m,s = unpack(d) + if s ~= 0 then + secs = secs+s + end + if m ~= 0 then + secs = secs+m*60 + end + if h ~= 0 then + secs = secs+h*3600 -- 60*60 + end + if d ~= 0 then + secs = secs+d*86400 -- 60*60*24 + end + if y ~= 0 then + secs = secs+y*31557600 -- 60*60*24*365.25 + end + --secs = math.floor(secs+0.5) + if secs < 0 then + minetest.log("action", "play warzone2100?") + end + return secs*time_speed +end + +-- copied from older default furnace code and edited a bit + +function nether.get_furnace_active_formspec(pos, percent) + local formspec = + "size[8,9]".. + "image[2,2;1,1;default_furnace_fire_bg.png^[lowpart:".. + (100-percent)..":default_furnace_fire_fg.png]".. + "list[current_name;fuel;2,3;1,1;]".. + "list[current_name;src;2,1;1,1;]".. + "list[current_name;dst;5,1;2,2;]".. + "list[current_player;main;0,5;8,4;]" + return formspec +end + +nether.furnace_inactive_formspec = + "size[8,9]".. + "image[2,2;1,1;default_furnace_fire_bg.png]".. + "list[current_name;fuel;2,3;1,1;]".. + "list[current_name;src;2,1;1,1;]".. + "list[current_name;dst;5,1;2,2;]".. + "list[current_player;main;0,5;8,4;]" + +minetest.register_node("nether:furnace", { + description = "Furnace", + tiles = {"default_furnace_top.png", "default_furnace_bottom.png", "default_furnace_side.png", + "default_furnace_side.png", "default_furnace_side.png", "default_furnace_front.png"}, + paramtype2 = "facedir", + groups = {cracky=2}, + legacy_facedir_simple = true, + is_ground_content = false, + sounds = default.node_sound_stone_defaults(), + on_construct = function(pos) + local meta = minetest.get_meta(pos) + meta:set_string("formspec", nether.furnace_inactive_formspec) + meta:set_string("infotext", "Furnace") + local inv = meta:get_inventory() + inv:set_size("fuel", 1) + inv:set_size("src", 1) + inv:set_size("dst", 4) + end, + can_dig = function(pos,player) + local meta = minetest.get_meta(pos); + local inv = meta:get_inventory() + if not inv:is_empty("fuel") then + return false + elseif not inv:is_empty("dst") then + return false + elseif not inv:is_empty("src") then + return false + end + return true + end, + allow_metadata_inventory_put = function(pos, listname, index, stack, player) + local meta = minetest.get_meta(pos) + meta:set_string("last_active", get_date()) + local inv = meta:get_inventory() + if listname == "fuel" then + if minetest.get_craft_result({method="fuel",width=1,items={stack}}).time ~= 0 then + if inv:is_empty("src") then + meta:set_string("infotext","Furnace is empty") + end + return stack:get_count() + else + return 0 + end + elseif listname == "src" then + return stack:get_count() + elseif listname == "dst" then + return 0 + end + end, + allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player) + local meta = minetest.get_meta(pos) + meta:set_string("last_active", get_date()) + local inv = meta:get_inventory() + local stack = inv:get_stack(from_list, from_index) + if to_list == "fuel" then + if minetest.get_craft_result({method="fuel",width=1,items={stack}}).time ~= 0 then + if inv:is_empty("src") then + meta:set_string("infotext","Furnace is empty") + end + return count + else + return 0 + end + elseif to_list == "src" then + return count + elseif to_list == "dst" then + return 0 + end + end, +}) + +minetest.register_node("nether:furnace_active", { + description = "Furnace", + tiles = { + "default_furnace_top.png", + "default_furnace_bottom.png", + "default_furnace_side.png", + "default_furnace_side.png", + "default_furnace_side.png", + { + image = "default_furnace_front_active.png", + backface_culling = false, + animation = { + type = "vertical_frames", + aspect_w = 16, + aspect_h = 16, + length = 1.5 + }, + } + }, + paramtype2 = "facedir", + light_source = 8, + drop = "nether:furnace", + groups = {cracky=2, not_in_creative_inventory=1,hot=1}, + legacy_facedir_simple = true, + is_ground_content = false, + sounds = default.node_sound_stone_defaults(), + on_construct = function(pos) + local meta = minetest.get_meta(pos) + meta:set_string("formspec", nether.furnace_inactive_formspec) + meta:set_string("infotext", "Furnace"); + local inv = meta:get_inventory() + inv:set_size("fuel", 1) + inv:set_size("src", 1) + inv:set_size("dst", 4) + end, + can_dig = function(pos,player) + local meta = minetest.get_meta(pos); + local inv = meta:get_inventory() + if not inv:is_empty("fuel") then + return false + elseif not inv:is_empty("dst") then + return false + elseif not inv:is_empty("src") then + return false + end + return true + end, + allow_metadata_inventory_put = function(pos, listname, index, stack, player) + local meta = minetest.get_meta(pos) + meta:set_string("last_active", get_date()) + local inv = meta:get_inventory() + if listname == "fuel" then + if minetest.get_craft_result({method="fuel",width=1,items={stack}}).time ~= 0 then + if inv:is_empty("src") then + meta:set_string("infotext","Furnace is empty") + end + return stack:get_count() + else + return 0 + end + elseif listname == "src" then + return stack:get_count() + elseif listname == "dst" then + return 0 + end + end, + allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player) + local meta = minetest.get_meta(pos) + meta:set_string("last_active", get_date()) + local inv = meta:get_inventory() + local stack = inv:get_stack(from_list, from_index) + if to_list == "fuel" then + if minetest.get_craft_result({method="fuel",width=1,items={stack}}).time ~= 0 then + if inv:is_empty("src") then + meta:set_string("infotext","Furnace is empty") + end + return count + else + return 0 + end + elseif to_list == "src" then + return count + elseif to_list == "dst" then + return 0 + end + end, +}) + +local function swap_node(pos,name) + local node = minetest.get_node(pos) + if node.name == name then + return + end + node.name = name + minetest.swap_node(pos,node) +end + +minetest.register_abm({ + nodenames = {"nether:furnace","nether:furnace_active"}, + interval = 1.0, + chance = 1, + action = function(pos) + local meta = minetest.get_meta(pos) + if meta:get_string("timedif") == "" then + meta:set_float("timedif", 0.0) + end + + -- lag shouldn't control the furnace speed + local current_time = get_date() + local last_time = meta:get_string("last_active") + if last_time == "" then + meta:set_string("last_active", current_time) + return + end + if last_time == current_time then + return + end + + local timediff = get_timediff(last_time, current_time)+meta:get_string("timedif") + local times = math.floor(timediff) + meta:set_string("last_active", current_time) + meta:set_float("timedif", timediff-times) + + + for _ = 1,times do + for _,name in pairs({ + "fuel_totaltime", + "fuel_time", + "src_totaltime", + "src_time", + }) do + if meta:get_string(name) == "" then + meta:set_float(name, 0.0) + end + end + local inv = meta:get_inventory() + local srclist = inv:get_list("src") + local cooked = nil + local aftercooked + + if srclist then + cooked, aftercooked = minetest.get_craft_result({method = "cooking", width = 1, items = srclist}) + end + + local was_active = false + + if meta:get_float("fuel_time") < meta:get_float("fuel_totaltime") then + was_active = true + meta:set_float("fuel_time", meta:get_float("fuel_time") + 1) + meta:set_float("src_time", meta:get_float("src_time") + 1) + if cooked + and cooked.item + and meta:get_float("src_time") >= cooked.time then + -- check if there's room for output in "dst" list + if inv:room_for_item("dst",cooked.item) then + -- Put result in "dst" list + inv:add_item("dst", cooked.item) + -- take stuff from "src" list + inv:set_stack("src", 1, aftercooked.items[1]) + --~ else + --print("Could not insert '"..cooked.item:to_string().."'") + end + meta:set_string("src_time", 0) + end + end + + if meta:get_float("fuel_time") < meta:get_float("fuel_totaltime") then + local percent = math.floor(meta:get_float("fuel_time") / + meta:get_float("fuel_totaltime") * 100) + meta:set_string("infotext","Furnace active: "..percent.."%") + swap_node(pos,"nether:furnace_active") + meta:set_string("formspec",nether.get_furnace_active_formspec(pos, percent)) + return + end + + local fuel = nil + local afterfuel + local cooked = nil + local fuellist = inv:get_list("fuel") + local srclist = inv:get_list("src") + + if srclist then + cooked = minetest.get_craft_result({method = "cooking", width = 1, items = srclist}) + end + if fuellist then + fuel, afterfuel = minetest.get_craft_result({method = "fuel", width = 1, items = fuellist}) + end + + if not fuel or fuel.time <= 0 then + meta:set_string("infotext","Furnace out of fuel") + swap_node(pos,"nether:furnace") + meta:set_string("formspec", nether.furnace_inactive_formspec) + return + end + + if cooked.item:is_empty() then + if was_active then + meta:set_string("infotext","Furnace is empty") + swap_node(pos,"nether:furnace") + meta:set_string("formspec", nether.furnace_inactive_formspec) + end + return + end + + meta:set_string("fuel_totaltime", fuel.time) + meta:set_string("fuel_time", 0) + + inv:set_stack("fuel", 1, afterfuel.items[1]) + end + end, +}) diff --git a/nether/nether/guide.lua b/nether/nether/guide.lua new file mode 100644 index 00000000..c90f3204 --- /dev/null +++ b/nether/nether/guide.lua @@ -0,0 +1,411 @@ +local cube = minetest.inventorycube + +-- the content of the guide +local guide_infos = { + { + description = "Mushrooms", + {"text", "Nether mushrooms can be found on the nether's ground and\n".. + "on netherrack soil, it can be dug by hand."}, + {"image", {1, 1, "riesenpilz_nether_shroom_side.png"}}, + {"y", 0.2}, + {"text", "If you drop it without holding the fast key, you can split it into its stem and head:"}, + {"image", {1, 1, "nether_shroom_top.png", 1}}, + {"image", {1, 1, "nether_shroom_stem.png"}}, + {"y", 0.1}, + {"text", "You can get more mushrooms by using a netherrack soil:\n".. + "1. search a dark place and, if necessary, place netherrack with air about it\n".. + "2. right click with cooked blood onto the netherrack to make it soiled\n".. + "3. right click onto the netherrack soil with a nether mushroom head to add some spores\n".. + "4. dig the mushroom which grew after some time to make place for another one"}, + {"image", {1, 1, "riesenpilz_nether_shroom_side.png", 6, 0.12}}, + {"y", 1}, + {"image", {1, 1, "nether_netherrack.png^nether_netherrack_soil.png", 1.8}}, + {"image", {1, 1, "nether_hotbed.png", 1.3, -0.4}}, + {"image", {1, 1, "nether_netherrack.png^nether_netherrack_soil.png", 3.6}}, + {"image", {1, 1, "nether_shroom_top.png", 3.1, -0.5}}, + {"image", {1, 1, "nether_netherrack.png^nether_netherrack_soil.png", 6}}, + {"image", {1, 1, "nether_netherrack.png"}}, + }, + { + description = "Tools", + {"text", "You can craft 5 kinds of tools in the nether,\n".. + "which (except the mushroom pick) require sticks to be crafted:"}, + {"image", {1, 1, "nether_pick_mushroom.png"}}, + {"y", 0.1}, + {"text", "strength : 1\n".. + "The mushroom pick needs mushroom stems and heads to be crafted."}, + {"image", {1, 1, "nether_pick_wood.png"}}, + {"y", 0.1}, + {"text", "strength : 2\n".. + "The nether wood pick can be crafted with cooked nether blood wood."}, + {"image", {1, 1, "nether_axe_netherrack.png", 1.5}}, + {"image", {1, 1, "nether_shovel_netherrack.png", 3}}, + {"image", {1, 1, "nether_sword_netherrack.png", 4.5}}, + {"image", {1, 1, "nether_pick_netherrack.png"}}, + {"y", 0.1}, + {"text", "strength : 3\n".. + "The red netherrack tools can be crafted with usual netherrack."}, + {"image", {1, 1, "nether_axe_netherrack_blue.png", 1.5}}, + {"image", {1, 1, "nether_shovel_netherrack_blue.png", 3}}, + {"image", {1, 1, "nether_sword_netherrack_blue.png", 4.5}}, + {"image", {1, 1, "nether_pick_netherrack_blue.png"}}, + {"y", 0.1}, + {"text", "strength : 3\n".. + "The blue netherrack tools can be crafted with blue netherrack."}, + {"image", {1, 1, "nether_axe_white.png", 1.5}}, + {"image", {1, 1, "nether_shovel_white.png", 3}}, + {"image", {1, 1, "nether_sword_white.png", 4.5}}, + {"image", {1, 1, "nether_pick_white.png"}}, + {"y", 0.1}, + {"text", "strength : 3\n".. + "The siwtonic tools can be crafted with the siwtonic ore."}, + }, + { + description = "Blood structures", + {"text", "You can find blood structures on the ground and\n".. + "dig their nodes even with the bare hand."}, + {"y", 0.5}, + {"text", "One contains 4 kinds of blocks :"}, + {"image", {1, 1, cube("nether_blood.png"), 1}}, + {"image", {1, 1, + cube("nether_blood_top.png", + "nether_blood.png^nether_blood_side.png", + "nether_blood.png^nether_blood_side.png"), + 2}}, + {"image", {1, 1, "nether_fruit.png", 3}}, + {"image", {1, 1, cube("nether_blood_stem_top.png", + "nether_blood_stem.png", "nether_blood_stem.png")}}, + {"y", 0.1}, + {"text", "Blood stem, blood, blood head and nether fruit"}, + {"y", 0.1}, + {"text", "You can craft 4 blood wood with the stem :"}, + {"image", {1, 1, cube("nether_wood.png")}}, + {"y", 0.1}, + {"text", "The 4 blood nodes can be cooked and, except\n".. + "blood wood, their blood can be extracted."}, + }, + { + description = "Fruits", + {"text", "You can find the nether fruits on blood structures\n".. + "and dig them even with the bare hand."}, + {"image", {1, 1, "nether_fruit.png"}}, + {"text", "Eating it will make you lose life but\n".. + "it might feed you and give you blood :"}, + {"image", {1, 1, "nether_blood_extracted.png"}}, + {"y", 0.2}, + {"text", "If you eat it at the right place inside a portal,\n".. + "you will teleport instead of getting blood."}, + {"y", 0.2}, + {"text", "If you drop it without holding the fast key,\n".. + "you can split it into its fruit and leaf:"}, + {"image", {1, 1, "nether_fruit_leaf.png", 1}}, + {"image", {1, 1, "nether_fruit_no_leaf.png"}}, + {"y", 0.2}, + {"text", "Craft a fruit leave block out of 9 fruit leaves\n".. + "The fruit can be used to craft a nether pearl."}, + {"image", {1, 1, cube("nether_fruit_leaves.png")}}, + {"y", 0.2}, + {"text", "A fruit leaves block"}, + }, + { + description = "Cooking", + {"text", "To get a furnace you need to dig at least 8 netherrack bricks.\n".. + "They can be found at pyramid like constructions and require at least\n".. + "a strength 1 nether pick to be dug.\n".. + "To craft the furnace, use the netherrack bricks like cobble:"}, + {"image", {0.5, 0.5, cube("nether_netherrack_brick.png"), 0.5}}, + {"image", {0.5, 0.5, cube("nether_netherrack_brick.png"), 1}}, + {"image", {0.5, 0.5, cube("nether_netherrack_brick.png")}}, + {"image", {0.5, 0.5, cube("nether_netherrack_brick.png"), 1}}, + {"image", {0.5, 0.5, cube("nether_netherrack_brick.png")}}, + {"image", {0.5, 0.5, cube("nether_netherrack_brick.png"), 0.5}}, + {"image", {0.5, 0.5, cube("nether_netherrack_brick.png"), 1}}, + {"image", {0.5, 0.5, cube("nether_netherrack_brick.png")}}, + {"y", 0.2}, + {"text", "To begin cooking stuff, you can use a mushroom or fruit.\n".. + "After that it's recommended to use cooked blood nodes."}, + {"y", 0.1}, + {"text", "Some nether items can be cooked:"}, + {"image", {1, 1, cube("nether_blood_stem_top_cooked.png", + "nether_blood_stem_cooked.png", "nether_blood_stem_cooked.png"), + 0.35}}, + {"image", {1, 1, cube("nether_blood_cooked.png"), 1.6}}, + {"image", {1, 1, + cube("nether_blood_top_cooked.png", + "nether_blood_cooked.png^nether_blood_side_cooked.png", + "nether_blood_cooked.png^nether_blood_side_cooked.png"), + 2.9}}, + {"image", {1, 1, cube("nether_wood_cooked.png"), 4.3}}, + {"y", 1.2}, + {"text", "Some cooked blood stem, cooked blood,\n".. + "cooked blood head and cooked blood wood,"}, + {"image", {1, 1, "nether_hotbed.png", 0.3}}, + {"image", {1, 1, "nether_pearl.png", 2}}, + {"y", 1.2}, + {"text", "Some cooked extracted blood and a nether pearl"}, + }, + { + description = "Extractors", + {"text", "Here you can find out information about the nether extractor."}, + {"y", 0.2}, + {"text", "Here you can see its craft recipe:"}, + {"image", {0.5, 0.5, cube("nether_blood_top_cooked.png", + "nether_blood_cooked.png^nether_blood_side_cooked.png", + "nether_blood_cooked.png^nether_blood_side_cooked.png"), 0.5}}, + {"image", {0.5, 0.5, cube("nether_netherrack_brick.png"), 1}}, + {"image", {0.5, 0.5, cube("nether_netherrack_brick.png")}}, + {"image", {0.5, 0.5, cube("nether_blood_extractor.png"), 2.5}}, + {"image", {0.5, 0.5, "nether_shroom_stem.png", 0.5}}, + {"image", {0.5, 0.5, cube("nether_blood_cooked.png"), 1}}, + {"image", {0.5, 0.5, cube("nether_blood_cooked.png")}}, + {"image", {0.5, 0.5, cube("nether_blood_stem_top_cooked.png", + "nether_blood_stem_cooked.png", "nether_blood_stem_cooked.png"), + 0.5}}, + {"image", {0.5, 0.5, cube("nether_netherrack_brick.png"), 1}}, + {"image", {0.5, 0.5, cube("nether_netherrack_brick.png")}}, + {"y", 0.2}, + {"text", "Extract blood from the blood nodes you get from the blood structures.\n".. + "You can also get blood with a nether fruit."}, + {"y", 0.2}, + {"text", "So you can use it:\n".. + "1. place it somewhere\n".. + "2. place blood blocks next to it (4 or less)\n".. + "3. right click with extracted blood onto it to power it\n".. + "4. take the new extracted blood and dig the extracted nodes"}, + {"y", 0.2}, + {"text", "Example (view from the top):"}, + {"y", 0.88}, + {"image", {1, 1, "nether_blood_stem_top.png", 0.82, -0.88}}, + {"image", {1, 1, "nether_blood.png", 1.63}}, + {"image", {1, 1, "nether_blood_extractor.png", 0.82}}, + {"image", {1, 1, "nether_blood_stem_top_empty.png", 3.82, -0.88}}, + {"image", {1, 1, "nether_blood_empty.png", 4.63}}, + {"image", {1, 1, "nether_blood_empty.png", 3.001}}, + {"image", {1, 1, "nether_blood_extractor.png", 3.82}}, + {"image", {1, 1, "nether_blood.png"}}, + {"image", {1, 1, "nether_blood.png", 0.82, -0.12}}, + {"image", {1, 1, "nether_blood_empty.png", 3.82, -0.12}}, + {"y", 1.2}, + {"text", "The empty blood stem can be crafted into empty nether wood,\n".. + "which can be crafted into nether sticks."}, + }, + { + description = "Ores", + {"text", "You can find 5 types of ores:"}, + {"image", {1, 1, cube("nether_netherrack_black.png"), 4}}, + {"image", {1, 1, cube("nether_netherrack.png")}}, + {"y", 0.2}, + {"text", "The red netherrack is generated like stone.\n".. + "The black netherrack is generated like gravel.\n".. + "Both require at least a strength 2 nether pick to be dug."}, + {"image", {1, 1, cube("nether_white.png"), 4}}, + {"image", {1, 1, cube("nether_netherrack_blue.png")}}, + {"y", 0.2}, + {"text", "The blue netherrack is generated like diamond ore.\n".. + "The siwtonic ore is generated like mese blocks.\n".. + "Both require at least a strength 3 nether pick to be dug."}, + {"image", {1, 1, cube("nether_netherrack_tiled.png"), 4}}, + {"image", {1, 1, cube("glow_stone.png")}}, + {"y", 0.2}, + {"text", "Glow stone can be used for lighting.\n".. + "Tiled netherrack is generated like coal ore.\n".. + "Glow stone requires at least a strength 1 pick to be dug.\n".. + "Dig tiled netherrack with at least a level 2 pickaxe."}, + }, + { + description = "Vines", + {"text", "Feed nether vines with blood.\n".. + "Dig them with anything."}, + {"image", {1, 1, "nether_vine.png"}}, + {"y", 0.2}, + {"text", "Grow nether child by placing\n".. + "placing it to a dark place onto a\n".. + "blood structure head node."}, + {"image", {1, 1, "nether_sapling.png"}}, + {"y", -0.10}, + {"image", {1, 1, "nether_blood.png^nether_blood_side.png"}}, + }, + { + description = "Pearls", + {"text", "The nether pearl can be used to teleport by throwing it.\n".. + "Here is how to get one :"}, + {"y", 0.2}, + {"text", "First of all craft 2 mushroom heads and 1 nether fruit\n".. + "without leaf together :"}, + {"image", {1, 1, "nether_shroom_top.png"}}, + {"image", {1, 1, "nether_fim.png", 3}}, + {"image", {1, 1, "nether_fruit_no_leaf.png"}}, + {"image", {1, 1, "nether_shroom_top.png"}}, + {"y", 0.2}, + {"text", "Put the result into the furnace\n".. + "to cook it into a nether pearl :"}, + {"image", {1, 1, "nether_pearl.png"}}, + }, + { + description = "Bricks", + {"text", "Craft bricks out of red,\n".. + "black and blue netherrack."}, + {"image", {1, 1, cube("nether_netherrack_brick_black.png"), 1}}, + {"image", {1, 1, cube("nether_netherrack_brick_blue.png"), 2}}, + {"image", {1, 1, cube("nether_netherrack_brick.png")}}, + {"y", 0.4}, + {"text", "Dig them with at least a level 1 pickaxe."}, + {"y", 0.2}, + }, + { + description = "Portals", + {"text", "Here you can find out how to built the nether portal."}, + {"y", 0.3}, + {"text", "A nether portal requires following nodes:"}, + {"y", 0.05}, + {"text", "25 empty nether wooden planks\n".. + "16 black netherrack\n".. + "12 blue netherrack bricks\n".. + "8 red netherrack\n".. + "8 cooked nether blood\n".. + "4 nether fruits\n".. + "2 siwtonic blocks"}, + {"y", 0.2}, + {"text", "It should look approximately like this one:"}, + {"image", {5.625, 6, "nether_teleporter.png", 0, -1.5}}, + {"y", 5.5}, + {"text", "Activate it by standing in the middle,\n".. + "on the siwtonic block and eating a nether fruit.\n".. + "Take enough stuff with you to build a portal when you'll come back."}, + }, + { + description = "Forests", + {"text", "The nether forest is generated in caves,\n".. + "above the usual nether."}, + {"y", 0.2}, + {"text", "There you can find some plants:"}, + {"image", {1, 1, "nether_grass_middle.png", 1}}, + {"image", {1, 1, "nether_grass_big.png", 2}}, + {"image", {1, 1, "nether_grass_small.png"}}, + {"y", 0.2}, + {"text", "Use the nether forest grass to get paper.\n".. + "Craft paper out of the dried grass."}, + {"image", {1, 1, cube("nether_tree_top.png", "nether_tree.png", "nether_tree.png")}}, + {"y", 0.2}, + {"text", "Nether trunks can be found at nether trees.\n".. + "Craft nether wood out of nether trunk."}, + {"image", {1, 1, "nether_glowflower.png"}}, + {"y", 0.2}, + {"text", "Use it for lighting and decoration."}, + }, +} + +-- the size of guide pages +local guide_size = {x=40, y=10, cx=0.2, cy=0.2} + +-- informations about settings and ... +local formspec_offset = {x=0.25, y=0.50} +local font_size +if minetest.is_singleplayer() then + font_size = tonumber(minetest.settings:get("font_size")) or 13 +else + font_size = 13 +end +guide_size.fx = math.floor((40*(guide_size.cx+formspec_offset.x))*font_size) +guide_size.fy = font_size/40 + +-- the default guide formspecs +local guide_forms = { + contents = "size[3.6,"..(#guide_infos)-2 ..";]label["..guide_size.cx+0.7 ..","..guide_size.cy+0.2 ..";Contents:]", +} + +-- change the infos to formspecs +for n,data in ipairs(guide_infos) do + local form = "" + local y = 0 + local x = guide_size.cx + for _,i in ipairs(data) do + local typ, content = unpack(i) + if typ == "y" then + y = y+content + elseif typ == "x" then + x = math.max(x, content) + elseif typ == "text" then + local tab = minetest.wrap_text(content, guide_size.fx, true) + local l = guide_size.cx + for _,str in ipairs(tab) do + form = form.."label["..guide_size.cx ..","..guide_size.cy+y..";"..str.."]" + y = y+guide_size.fy + l = math.max(l, #str) + end + x = math.max(x, l/font_size) + elseif typ == "image" then + local w, h, texture_name, px, py = unpack(content) + if not px then + form = form.."image["..guide_size.cx..","..guide_size.cy+y+h*0.3 ..";"..w..","..h..";"..texture_name.."]" + y = y+h + else + px = guide_size.cx+px + py = py or 0 + form = form.."image["..px..",".. + guide_size.cy+y+h*0.3+py ..";"..w..","..h..";"..texture_name.."]" + x = math.max(x, px+w) + end + end + end + form = "size["..x*1.8 ..","..y+1 ..";]"..form.."button["..x/2-0.5 ..","..y ..";1,2;quit;Back]" + guide_forms[n] = {data.description, form} +end + +local desc_tab = {} +for n,i in ipairs(guide_forms) do + desc_tab[i[1]] = n +end + +-- creates contents formspec +for y,i in ipairs(guide_forms) do + local desc = i[1] + local s = #desc * 1.3 / font_size + 1.5 + guide_forms.contents = guide_forms.contents .. + "button[" .. guide_size.cx * 12 / s - 0.5 .. "," .. + guide_size.cy + y / 1.3 .. ";" .. s .. ",1;name;" .. desc .. "]" +end + +-- shows the contents of the formspec +local function show_guide(pname) + minetest.show_formspec(pname, "nether_guide_contents", guide_forms["contents"]) +end + +minetest.register_on_player_receive_fields(function(player, formname, fields) + if formname == "nether_guide_contents" then + local fname = fields.name + local pname = player:get_player_name() + if fname + and pname then + minetest.show_formspec(pname, "nether_guide", guide_forms[desc_tab[fname]][2]) + end + elseif formname == "nether_guide" then + local fname = fields.quit + local pname = player:get_player_name() + if fname + and pname then + minetest.show_formspec(pname, "nether_guide_contents", guide_forms["contents"]) + end + end +end) + +minetest.register_chatcommand("nether_help", { + params = "", + description = "Shows a nether guide", + func = function(name) + local player = minetest.get_player_by_name(name) + if not player then + minetest.chat_send_player(name, "Something went wrong.") + return false + end + if player:get_pos().y > nether.start then + minetest.chat_send_player(name, + "Usually you don't neet this guide here. " .. + "You can view it in the nether.") + return false + end + minetest.chat_send_player(name, "Showing guide...") + show_guide(name) + return true + end +}) diff --git a/nether/nether/init.lua b/nether/nether/init.lua new file mode 100644 index 00000000..184338ee --- /dev/null +++ b/nether/nether/init.lua @@ -0,0 +1,1046 @@ +-- Nether Mod (based on Nyanland by Jeija, Catapult by XYZ, and Livehouse by neko259) +-- lkjoel (main developer, code, ideas, textures) +-- == CONTRIBUTERS == +-- jordan4ibanez (code, ideas, textures) +-- Gilli (code, ideas, textures, mainly for the Glowstone) +-- Death Dealer (code, ideas, textures) +-- LolManKuba (ideas, textures) +-- IPushButton2653 (ideas, textures) +-- Menche (textures) +-- sdzen (ideas) +-- godkiller447 (ideas) +-- If I didn't list you, please let me know! + +local load_time_start = minetest.get_us_time() + +if not rawget(_G, "nether") then + nether = {} +end + +--== EDITABLE OPTIONS ==-- + +--says some information. +nether.info = true + +-- tell everyone about the generation +nether.inform_all = minetest.is_singleplayer() + +--1: 2: 3: +nether.max_spam = 2 + +-- Depth of the nether +local nether_middle = -20000 + +-- forest bottom perlin multiplication +local f_bottom_scale = 4 + +-- forest bottom height +local f_h_min = nether_middle+10 + +-- forest top height +local f_h_max = f_h_min+250 + +-- Frequency of trees in the nether forest (higher is less frequent) +local tree_rarity = 200 + +-- Frequency of glowflowers in the nether forest (higher is less frequent) +local glowflower_rarity = 120 + +-- Frequency of nether grass in the nether forest (higher is less frequent) +local grass_rarity = 2 + +-- Frequency of nether mushrooms in the nether forest (higher is less frequent) +local mushroom_rarity = 80 + +local abm_tree_interval = 864 +local abm_tree_chance = 100 + +-- height of the nether generation's end +nether.start = f_h_max+100 + +-- Height of the nether (bottom of the nether is nether_middle - NETHER_HEIGHT) +local NETHER_HEIGHT = 30 + +-- Maximum amount of randomness in the map generation +local NETHER_RANDOM = 2 + +-- Frequency of Glowstone on the "roof" of the Nether (higher is less frequent) +local GLOWSTONE_FREQ_ROOF = 500 + +-- Frequency of lava (higher is less frequent) +local LAVA_FREQ = 100 + +local nether_structure_freq = 350 +local NETHER_SHROOM_FREQ = 100 + +-- Maximum height of lava +--LAVA_HEIGHT = 2 +-- Frequency of Glowstone on lava (higher is less frequent) +--GLOWSTONE_FREQ_LAVA = 2 +-- Height of nether structures +--NETHER_TREESIZE = 2 +-- Frequency of apples in a nether structure (higher is less frequent) +--NETHER_APPLE_FREQ = 5 +-- Frequency of healing apples in a nether structure (higher is less frequent) +--NETHER_HEAL_APPLE_FREQ = 10 +-- Start position for the Throne of Hades (y is relative to the bottom of the +-- nether) +--HADES_THRONE_STARTPOS = {x=0, y=1, z=0} +-- Spawn pos for when the nether hasn't been loaded yet (i.e. no portal in the +-- nether) (y is relative to the bottom of the nether) +--NETHER_SPAWNPOS = {x=0, y=5, z=0} +-- Structure of the nether portal (all is relative to the nether portal creator +-- block) + +--== END OF EDITABLE OPTIONS ==-- + +if nether.info then + function nether:inform(msg, spam, t) + if spam <= self.max_spam then + local info + if t then + info = "[nether] " .. msg .. (" after ca. %.3g s"):format( + (minetest.get_us_time() - t) / 1000000) + else + info = "[nether] " .. msg + end + print(info) + if self.inform_all then + minetest.chat_send_all(info) + end + end + end +else + function nether.inform() + end +end + + +local path = minetest.get_modpath"nether" +local nether_weird_noise = dofile(path.."/weird_mapgen_noise.lua") +dofile(path.."/items.lua") +--dofile(path.."/furnace.lua") +dofile(path.."/pearl.lua") + +-- Weierstrass function stuff from https://github.com/slemonide/gen +local SIZE = 1000 +local ssize = math.ceil(math.abs(SIZE)) +local function do_ws_func(depth, a, x) + local n = math.pi * x / (16 * SIZE) + local y = 0 + for k=1,depth do + y = y + math.sin(k^a * n) / k^a + end + return SIZE * y / math.pi +end + +local chunksize = minetest.settings:get"chunksize" or 5 +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 + (chunksize*16 - 1) do + local y = do_ws_func(ssize, a, x) + v[x] = y + end + ws_lists[a][x] = v + return v +end + + +local function dif(z1, z2) + return math.abs(z1-z2) +end + +local function pymg(x1, x2, z1, z2) + return math.max(dif(x1, x2), dif(z1, z2)) +end + +local function r_area(manip, width, height, pos) + local emerged_pos1, emerged_pos2 = manip:read_from_map( + {x=pos.x-width, y=pos.y, z=pos.z-width}, + {x=pos.x+width, y=pos.y+height, z=pos.z+width} + ) + return VoxelArea:new({MinEdge=emerged_pos1, MaxEdge=emerged_pos2}) +end + +local function set_vm_data(manip, nodes, pos, t1, name, generated) + manip:set_data(nodes) + manip:write_to_map(not generated) + nether:inform(name.." grew at " .. minetest.pos_to_string(pos), + generated and 3 or 2, t1) +end + +-- Generated variables +local NETHER_BOTTOM = (nether_middle - NETHER_HEIGHT) +nether.buildings = NETHER_BOTTOM+12 +--~ local NETHER_ROOF_ABS = (nether_middle - NETHER_RANDOM) +local f_yscale_top = (f_h_max-f_h_min)/2 +local f_yscale_bottom = f_yscale_top/2 +--HADES_THRONE_STARTPOS_ABS = {x=HADES_THRONE_STARTPOS.x, y=(NETHER_BOTTOM + +--HADES_THRONE_STARTPOS.y), z=HADES_THRONE_STARTPOS.z} +--LAVA_Y = (NETHER_BOTTOM + LAVA_HEIGHT) +--HADES_THRONE_ABS = {} +--HADES_THRONE_ENDPOS_ABS = {} +--HADES_THRONE_GENERATED = minetest.get_worldpath() .. "/netherhadesthrone.txt" +--NETHER_SPAWNPOS_ABS = {x=NETHER_SPAWNPOS.x, y=(NETHER_BOTTOM + +--NETHER_SPAWNPOS.y), z=NETHER_SPAWNPOS.z} +--[[for i,v in ipairs(HADES_THRONE) do + v.pos.x = v.pos.x + HADES_THRONE_STARTPOS_ABS.x + v.pos.y = v.pos.y + HADES_THRONE_STARTPOS_ABS.y + v.pos.z = v.pos.z + HADES_THRONE_STARTPOS_ABS.z + HADES_THRONE_ABS[i] = v +end +local htx = 0 +local hty = 0 +local htz = 0 +for i,v in ipairs(HADES_THRONE_ABS) do + if v.pos.x > htx then + htx = v.pos.x + end + if v.pos.y > hty then + hty = v.pos.y + end + if v.pos.z > htz then + htz = v.pos.z + end +end +HADES_THRONE_ENDPOS_ABS = {x=htx, y=hty, z=htz}]] + +local c, nether_tree_nodes +local function define_contents() + c = { + ignore = minetest.get_content_id("ignore"), + air = minetest.get_content_id("air"), + lava = minetest.get_content_id("default:lava_source"), + gravel = minetest.get_content_id("default:gravel"), + coal = minetest.get_content_id("default:stone_with_coal"), + diamond = minetest.get_content_id("default:stone_with_diamond"), + mese = minetest.get_content_id("default:mese"), + + --https://github.com/Zeg9/minetest-glow + glowstone = minetest.get_content_id("glow:stone"), + + nether_shroom = minetest.get_content_id("riesenpilz:nether_shroom"), + + netherrack = minetest.get_content_id("nether:netherrack"), + netherrack_tiled = minetest.get_content_id("nether:netherrack_tiled"), + netherrack_black = minetest.get_content_id("nether:netherrack_black"), + netherrack_blue = minetest.get_content_id("nether:netherrack_blue"), + netherrack_brick = minetest.get_content_id("nether:netherrack_brick"), + white = minetest.get_content_id("nether:white"), + + nether_vine = minetest.get_content_id("nether:vine"), + blood = minetest.get_content_id("nether:blood"), + blood_top = minetest.get_content_id("nether:blood_top"), + blood_stem = minetest.get_content_id("nether:blood_stem"), + nether_apple = minetest.get_content_id("nether:apple"), + + nether_tree = minetest.get_content_id("nether:tree"), + nether_tree_corner = minetest.get_content_id("nether:tree_corner"), + nether_leaves = minetest.get_content_id("nether:leaves"), + nether_grass = { + minetest.get_content_id("nether:grass_small"), + minetest.get_content_id("nether:grass_middle"), + minetest.get_content_id("nether:grass_big") + }, + glowflower = minetest.get_content_id("nether:glowflower"), + nether_dirt = minetest.get_content_id("nether:dirt"), + nether_dirt_top = minetest.get_content_id("nether:dirt_top"), + nether_dirt_bottom = minetest.get_content_id("nether:dirt_bottom"), + } + local trn = {c.nether_tree, c.nether_tree_corner, c.nether_leaves, + c.nether_fruit} + nether_tree_nodes = {} + for i = 1,#trn do + nether_tree_nodes[trn[i]] = true + end +end + +local pr, contents_defined + +local function return_nether_ore(id, glowstone) + if glowstone + and pr:next(0,GLOWSTONE_FREQ_ROOF) == 1 then + return c.glowstone + end + if id == c.coal then + return c.netherrack_tiled + end + if id == c.gravel then + return c.netherrack_black + end + if id == c.diamond then + return c.netherrack_blue + end + if id == c.mese then + return c.white + end + return c.netherrack +end + +local f_perlins = {} + +-- abs(v) < 1-(persistance^octaves))/(1-persistance) = amp +--local perlin1 = minetest.get_perlin(13,3, 0.5, 50) --Get map specific perlin +-- local perlin2 = minetest.get_perlin(133,3, 0.5, 10) +-- local perlin3 = minetest.get_perlin(112,3, 0.5, 5) +local tmp = f_yscale_top*4 +local tmp2 = tmp/f_bottom_scale +local perlins = { + { -- amp 1.75 + seed = 13, + octaves = 3, + persist = 0.5, + spread = {x=50, y=50, z=50}, + scale = 1, + offset = 0, + }, + {-- amp 1.75 + seed = 133, + octaves = 3, + persist = 0.5, + spread = {x=10, y=10, z=10}, + scale = 1, + offset = 0, + }, + {-- amp 1.75 + seed = 112, + octaves = 3, + persist = 0.5, + spread = {x=5, y=5, z=5}, + scale = 1, + offset = 0, + }, + --[[forest_bottom = { + seed = 11, + octaves = 3, + persist = 0.8, + spread = {x=tmp2, y=tmp2, z=tmp2}, + scale = 1, + offset = 0, + },]] + forest_top = {-- amp 2.44 + seed = 21, + octaves = 3, + persist = 0.8, + spread = {x=tmp, y=tmp, z=tmp}, + scale = 1, + offset = 0, + }, +} + +-- buffers, see https://forum.minetest.net/viewtopic.php?f=18&t=16043 +local pelin_maps +local pmap1 = {} +local pmap2 = {} +local pmap3 = {} +local pmap_f_top = {} +local data = {} + +local structures_enabled = true +local vine_maxlength = math.floor(NETHER_HEIGHT/4+0.5) +-- Create the Nether +minetest.register_on_generated(function(minp, maxp, seed) + --avoid big map generation + if not (maxp.y >= NETHER_BOTTOM-100 and minp.y <= nether.start) then + return + end + + local t1 = minetest.get_us_time() + nether:inform("generates at: x=["..minp.x.."; "..maxp.x.."]; y=[" .. + minp.y.."; "..maxp.y.."]; z=["..minp.z.."; "..maxp.z.."]", 2) + + if not contents_defined then + define_contents() + contents_defined = true + end + + local buildings = 0 + if maxp.y <= NETHER_BOTTOM then + buildings = 1 + elseif minp.y <= nether.buildings then + buildings = 2 + end + + local vm, emin, emax = minetest.get_mapgen_object("voxelmanip") + vm:get_data(data) + local area = VoxelArea:new{MinEdge=emin, MaxEdge=emax} + + pr = PseudoRandom(seed+33) + local tab,num = {},1 + local trees,num_trees = {},1 + + --local perlin1 = minetest.get_perlin(13,3, 0.5, 50) + --local perlin2 = minetest.get_perlin(133,3, 0.5, 10) + --local perlin3 = minetest.get_perlin(112,3, 0.5, 5) + + local side_length = maxp.x - minp.x + 1 + local map_lengths_xyz = {x=side_length, y=side_length, z=side_length} + + if not pelin_maps then + pelin_maps = { + a = minetest.get_perlin_map(perlins[1], map_lengths_xyz), + b = minetest.get_perlin_map(perlins[2], map_lengths_xyz), + c = minetest.get_perlin_map(perlins[3], map_lengths_xyz), + forest_top = minetest.get_perlin_map(perlins.forest_top, + map_lengths_xyz), + } + end + pelin_maps.a:get_2d_map_flat({x=minp.x, y=minp.z}, pmap1) + pelin_maps.b:get_2d_map_flat({x=minp.x, y=minp.z}, pmap2) + pelin_maps.c:get_2d_map_flat({x=minp.x, y=minp.z}, pmap3) + + local forest_possible = maxp.y > f_h_min and minp.y < f_h_max + + --local pmap_f_bottom = minetest.get_perlin_map(perlins.forest_bottom, + -- map_lengths_xyz):get_2d_map_flat({x=minp.x, y=minp.z}) + local perlin_f_bottom, strassx, strassz + if forest_possible then + perlin_f_bottom = minetest.get_perlin(11, 3, 0.8, tmp2) + pelin_maps.forest_top:get_2d_map_flat({x=minp.x, y=minp.z}, pmap_f_top) + strassx = get_ws_list(2, minp.x) + strassz = get_ws_list(2, minp.z) + end + + local num2, tab2 + if buildings >= 1 then + num2 = 1 + tab2 = nether_weird_noise({x=minp.x, y=nether.buildings-79, z=minp.z}, + pymg, 200, 8, 10, side_length-1) + end + + local count = 0 + for z=minp.z, maxp.z do + for x=minp.x, maxp.x do + + count = count+1 + + local test = pmap1[count]+1 + local test2 = pmap2[count] + local test3 = math.abs(pmap3[count]) + + local t = math.floor(test*3+0.5) + + local h + if test2 < 0 then + h = math.floor(test2*3+0.5)-1 + else + h = 3+t+pr:next(0,NETHER_RANDOM) + end + + local generate_vine = false + if test3 >= 0.72+pr:next(0,NETHER_RANDOM)/10 + and pr:next(0,NETHER_RANDOM) == 1 then + generate_vine = true + end + + local bottom = NETHER_BOTTOM+h + local top = nether_middle-pr:next(0,NETHER_RANDOM)+t + + local py_h = 0 + local difn, noisp, py_h_g + if buildings >= 1 then + py_h = tab2[num2].y + num2 = num2+1 + + difn = nether.buildings-py_h + if difn == 5 then + noisp = 1 + elseif difn < 5 then + noisp = 2 + end + py_h_g = nether.buildings-7 + end + + local vi = area:index(x, minp.y, z) + if buildings == 1 + and noisp then + if noisp == 1 then + for _ = 1,side_length do + data[vi] = c.netherrack_brick + vi = vi + area.ystride + end + else + for _ = 1,side_length do + data[vi] = c.lava + vi = vi + area.ystride + end + end + else + + local r_structure = pr:next(1,nether_structure_freq) + local r_shroom = pr:next(1,NETHER_SHROOM_FREQ) + local r_glowstone = pr:next(0,GLOWSTONE_FREQ_ROOF) + local r_vine_length = pr:next(1,vine_maxlength) + + local f_bottom, f_top, is_forest, f_h_dirt + if forest_possible then + local p = {x=math.floor(x/f_bottom_scale), + z=math.floor(z/f_bottom_scale)} + local pstr = p.x.." "..p.z + if not f_perlins[pstr] then + f_perlins[pstr] = math.floor(f_h_min + (math.abs( + perlin_f_bottom:get_2d{x=p.x, y=p.z} + 1)) + * f_yscale_bottom + 0.5) + end + local top_noise = pmap_f_top[count]+1 + if top_noise < 0 then + top_noise = -top_noise/10 + --nether:inform("ERROR: (perlin noise) ".. + -- pmap_f_top[count].." is not inside [-1; 1]", 1) + end + f_top = math.floor(f_h_max - top_noise*f_yscale_top + 0.5) + f_bottom = f_perlins[pstr]+pr:next(0,f_bottom_scale-1) + is_forest = f_bottom < f_top + f_h_dirt = f_bottom-pr:next(0,1) + end + + for y=minp.y, maxp.y do + local d_p_addp = data[vi] + --if py_h >= maxp.y-4 then + if y <= py_h + and noisp then + if noisp == 1 then + data[vi] = c.netherrack_brick + elseif noisp == 2 then + if y == py_h then + data[vi] = c.netherrack_brick + elseif y == py_h_g + and pr:next(1,3) <= 2 then + data[vi] = c.netherrack + elseif y <= py_h_g then + data[vi] = c.lava + else + data[vi] = c.air + end + end + elseif d_p_addp ~= c.air then + + if is_forest + and y == f_bottom then + data[vi] = c.nether_dirt_top + elseif is_forest + and y < f_bottom + and y >= f_h_dirt then + data[vi] = c.nether_dirt + elseif is_forest + and y == f_h_dirt-1 then + data[vi] = c.nether_dirt_bottom + elseif is_forest + and y == f_h_dirt+1 then + if pr:next(1,tree_rarity) == 1 then + trees[num_trees] = {x=x, y=y, z=z} + num_trees = num_trees+1 + elseif pr:next(1,mushroom_rarity) == 1 then + data[vi] = c.nether_shroom + elseif pr:next(1,glowflower_rarity) == 1 then + data[vi] = c.glowflower + elseif pr:next(1,grass_rarity) == 1 then + data[vi] = c.nether_grass[pr:next(1,3)] + else + data[vi] = c.air + end + elseif is_forest + and y > f_bottom + and y < f_top then + if not nether_tree_nodes[d_p_addp] then + data[vi] = c.air + end + elseif is_forest + and y == f_top then + local sel = math.floor(strassx[x]+strassz[z]+0.5)%10 + if sel <= 5 then + data[vi] = return_nether_ore(d_p_addp, true) + elseif sel == 6 then + data[vi] = c.netherrack_black + elseif sel == 7 then + data[vi] = c.glowstone + else + data[vi] = c.air + end + + elseif y <= NETHER_BOTTOM then + if y <= bottom then + data[vi] = return_nether_ore(d_p_addp, true) + else + data[vi] = c.lava + end + elseif r_structure == 1 + and y == bottom then + tab[num] = {x=x, y=y-1, z=z} + num = num+1 + elseif y <= bottom then + if pr:next(1,LAVA_FREQ) == 1 then + data[vi] = c.lava + else + data[vi] = return_nether_ore(d_p_addp, false) + end + elseif r_shroom == 1 + and r_structure ~= 1 + and y == bottom+1 then + data[vi] = c.nether_shroom + elseif (y == top and r_glowstone == 1) then + data[vi] = c.glowstone + elseif y >= top then + data[vi] = return_nether_ore(d_p_addp, true) + elseif y <= top-1 + and generate_vine + and y >= top-r_vine_length then + data[vi] = c.nether_vine + else + data[vi] = c.air + end + end + vi = vi + area.ystride + end + end + end + end + vm:set_data(data) +-- vm:set_lighting(12) +-- vm:calc_lighting() +-- vm:update_liquids() + vm:write_to_map(false) + + nether:inform("nodes set", 2, t1) + + local t2 = minetest.get_us_time() + local tr_bl_cnt = 0 + + if structures_enabled then -- Blood netherstructures + tr_bl_cnt = #tab + for i = 1,tr_bl_cnt do + nether.grow_netherstructure(tab[i], true) + end + end + + if forest_possible then -- Forest trees + tr_bl_cnt = tr_bl_cnt + #trees + for i = 1,#trees do + nether.grow_tree(trees[i], true) + end + end + + if tr_bl_cnt > 0 then + nether:inform(tr_bl_cnt .. " trees and blood structures set", 2, t2) + end + + t2 = minetest.get_us_time() + minetest.fix_light(minp, maxp) + + nether:inform("light fixed", 2, t2) + + nether:inform("done", 1, t1) +end) + + +function nether.grow_netherstructure(pos, generated) + local t1 = minetest.get_us_time() + + if not contents_defined then + define_contents() + contents_defined = true + end + + if not pos.x then print(dump(pos)) + nether:inform("Error: "..dump(pos), 1) + return + end + + local height = 6 + local manip = minetest.get_voxel_manip() + local area = r_area(manip, 2, height, pos) + local nodes = manip:get_data() + + local vi = area:indexp(pos) + for _ = 0, height-1 do + nodes[vi] = c.blood_stem + vi = vi + area.ystride + end + + for i = -1,1 do + for j = -1,1 do + nodes[area:index(pos.x+i, pos.y+height, pos.z+j)] = c.blood_top + end + end + + for k = -1, 1, 2 do + for l = -2+1, 2 do + local p1 = {pos.x+2*k, pos.y+height, pos.z-l*k} + local p2 = {pos.x+l*k, pos.y+height, pos.z+2*k} + local udat = c.blood_top + if math.random(2) == 1 then + nodes[area:index(p1[1], p1[2], p1[3])] = c.blood_top + nodes[area:index(p2[1], p2[2], p2[3])] = c.blood_top + udat = c.blood + end + nodes[area:index(p1[1], p1[2]-1, p1[3])] = udat + nodes[area:index(p2[1], p2[2]-1, p2[3])] = udat + end + for l = 0, 1 do + for _,p in ipairs({ + {pos.x+k, pos.y+height-1, pos.z-l*k}, + {pos.x+l*k, pos.y+height-1, pos.z+k}, + }) do + if math.random(2) == 1 then + nodes[area:index(p[1], p[2], p[3])] = c.nether_apple + --elseif math.random(10) == 1 then + -- nodes[area:index(p[1], p[2], p[3])] = c.apple + end + end + end + end + set_vm_data(manip, nodes, pos, t1, "blood", generated) +end + + +local poshash = minetest.hash_node_position +local pos_from_hash = minetest.get_position_from_hash + +local function soft_node(id) + return id == c.air or id == c.ignore +end + +local function update_minmax(min, max, p) + min.x = math.min(min.x, p.x) + max.x = math.max(max.x, p.x) + min.z = math.min(min.z, p.z) + max.z = math.max(max.z, p.z) +end + +local fruit_chances = {} +for y = -2,1 do --like a hyperbola + fruit_chances[y] = math.floor(-4/(y-2)+0.5) +end + +local dirs = { + {-1, 0, 12, 19}, + {1, 0, 12, 13}, + {0, 1, 4}, + {0, -1, 4, 10}, +} + +local h_max = 26 +local h_stem_min = 3 +local h_stem_max = 7 +local h_arm_min = 2 +local h_arm_max = 6 +local r_arm_min = 1 +local r_arm_max = 5 +local fruit_rarity = 25 --a bigger number results in less fruits +local leaf_thickness = 3 --a bigger number results in more blank trees + +local h_trunk_max = h_max-h_arm_max + +function nether.grow_tree(pos, generated) + local t1 = minetest.get_us_time() + + if not contents_defined then + define_contents() + contents_defined = true + end + + local min = vector.new(pos) + local max = vector.new(pos) + min.y = min.y-1 + max.y = max.y+h_max + + local trunks = {} + local trunk_corners = {} + local h_stem = math.random(h_stem_min, h_stem_max) + local todo,n = {{x=pos.x, y=pos.y+h_stem, z=pos.z}},1 + while n do + local p = todo[n] + todo[n] = nil + n = next(todo) + + local used_dirs,u = {},1 + for _,dir in pairs(dirs) do + if math.random(1,2) == 1 then + used_dirs[u] = dir + u = u+1 + end + end + if not used_dirs[1] then + local dir1 = math.random(4) + local dir2 = math.random(3) + if dir1 <= dir2 then + dir2 = dir2+1 + end + used_dirs[1] = dirs[dir1] + used_dirs[2] = dirs[dir2] + end + for _,dir in pairs(used_dirs) do + local p = vector.new(p) + local r = math.random(r_arm_min, r_arm_max) + for j = 1,r do + local x = p.x+j*dir[1] + local z = p.z+j*dir[2] + trunks[poshash{x=x, y=p.y, z=z}] = dir[3] + end + r = r+1 + p.x = p.x+r*dir[1] + p.z = p.z+r*dir[2] + trunk_corners[poshash(p)] = dir[4] or dir[3] + local h = math.random(h_arm_min, h_arm_max) + for i = 1,h do + p.y = p.y + i + trunks[poshash(p)] = true + p.y = p.y - i + end + p.y = p.y+h + --n = #todo+1 -- caused small trees + todo[#todo+1] = p + end + if p.y > pos.y+h_trunk_max then + break + end + + n = n or next(todo) + end + local leaves = {} + local fruits = {} + local trunk_ps = {} + local count = 0 + + local ps = {} + local trunk_count = 0 + for i,par2 in pairs(trunks) do + local pos = pos_from_hash(i) + update_minmax(min, max, pos) + local z,y,x = pos.z, pos.y, pos.x + trunk_count = trunk_count+1 + ps[trunk_count] = {z,y,x, par2} + end + + for _,d in pairs(ps) do + if d[4] == true then + d[4] = nil + end + trunk_ps[#trunk_ps+1] = d + local pz, py, px = unpack(d) + count = count+1 + if count > leaf_thickness then + count = 0 + for y = -2,2 do + local fruit_chance = fruit_chances[y] + for z = -2,2 do + for x = -2,2 do + local distq = x*x+y*y+z*z + if distq ~= 0 + and math.random(1, math.sqrt(distq)) == 1 then + local x = x+px + local y = y+py + local z = z+pz + local vi = poshash{x=x, y=y, z=z} + if not trunks[vi] then + if fruit_chance + and math.random(1, fruit_rarity) == 1 + and math.random(1, fruit_chance) == 1 then + fruits[vi] = true + else + leaves[vi] = true + end + update_minmax(min, max, {x=x, z=z}) + end + end + end + end + end + end + end + + --ps = nil + --collectgarbage() + + for i = -1,h_stem+1 do + -- param2 explicitly set 0 due to possibly previous leaves node + trunk_ps[#trunk_ps+1] = {pos.z, pos.y+i, pos.x, 0} + end + + local manip = minetest.get_voxel_manip() + local emerged_pos1, emerged_pos2 = manip:read_from_map(min, max) + local area = VoxelArea:new({MinEdge=emerged_pos1, MaxEdge=emerged_pos2}) + local nodes = manip:get_data() + local param2s = manip:get_param2_data() + + for i in pairs(leaves) do + local p = area:indexp(pos_from_hash(i)) + if soft_node(nodes[p]) then + nodes[p] = c.nether_leaves + param2s[p] = math.random(0,179) + --param2s[p] = math.random(0,44) + end + end + + for i in pairs(fruits) do + local p = area:indexp(pos_from_hash(i)) + if soft_node(nodes[p]) then + nodes[p] = c.nether_apple + end + end + + for i = 1,#trunk_ps do + local p = trunk_ps[i] + local par = p[4] + p = area:index(p[3], p[2], p[1]) + if par then + param2s[p] = par + end + nodes[p] = c.nether_tree + end + + for i,par2 in pairs(trunk_corners) do + local vi = area:indexp(pos_from_hash(i)) + nodes[vi] = c.nether_tree_corner + param2s[vi] = par2 + end + + manip:set_data(nodes) + manip:set_param2_data(param2s) + manip:write_to_map(not generated) + nether:inform("a nether tree with " .. trunk_count .. + " branch trunk nodes grew at " .. minetest.pos_to_string(pos), + generated and 3 or 2, t1) +end + + +--abms + +minetest.register_abm({ + nodenames = {"nether:sapling"}, + neighbors = {"nether:blood_top"}, + interval = 20, + chance = 8, + action = function(pos) + local under = {x=pos.x, y=pos.y-1, z=pos.z} + if minetest.get_node_light(pos) < 4 + and minetest.get_node({x=pos.x, y=pos.y+1, z=pos.z}).name == "air" + and minetest.get_node(under).name == "nether:blood_top" then + nether.grow_netherstructure(under) + end + end +}) + +minetest.register_abm({ + nodenames = {"nether:tree_sapling"}, + neighbors = {"group:nether_dirt"}, + interval = abm_tree_interval, + chance = abm_tree_chance, + action = function(pos) + if minetest.get_node({x=pos.x, y=pos.y+2, z=pos.z}).name == "air" + and minetest.get_node({x=pos.x, y=pos.y+1, z=pos.z}).name == "air" then + local udata = minetest.registered_nodes[ + minetest.get_node{x=pos.x, y=pos.y-1, z=pos.z}.name] + if udata + and udata.groups + and udata.groups.nether_dirt then + nether.grow_tree(pos) + end + end + end +}) + +minetest.register_abm({ + nodenames = {"nether:netherrack_soil"}, + neighbors = {"air"}, + interval = 20, + chance = 20, + action = function(pos, node) + local par2 = node.param2 + if par2 == 0 then + return + end + pos.y = pos.y+1 + --mushrooms grow at dark places + if (minetest.get_node_light(pos) or 16) > 7 then + return + end + if minetest.get_node(pos).name == "air" then + minetest.set_node(pos, {name="riesenpilz:nether_shroom"}) + pos.y = pos.y-1 + minetest.set_node(pos, + {name="nether:netherrack_soil", param2=par2-1}) + end + end +}) + +local function grass_allowed(pos) + local nd = minetest.get_node(pos).name + if nd == "air" then + return true + end + if nd == "ignore" then + return 0 + end + local data = minetest.registered_nodes[nd] + if not data then + -- unknown node + return false + end + local drawtype = data.drawtype + if drawtype + and drawtype ~= "normal" + and drawtype ~= "liquid" + and drawtype ~= "flowingliquid" then + return true + end + local light = data.light_source + if light + and light > 0 then + return true + end + return false +end + +minetest.register_abm({ + nodenames = {"nether:dirt"}, + interval = 20, + chance = 9, + action = function(pos) + local allowed = grass_allowed({x=pos.x, y=pos.y+1, z=pos.z}) + if allowed == 0 then + return + end + if allowed then + minetest.set_node(pos, {name="nether:dirt_top"}) + end + end +}) + +minetest.register_abm({ + nodenames = {"nether:dirt_top"}, + interval = 30, + chance = 9, + action = function(pos) + local allowed = grass_allowed({x=pos.x, y=pos.y+1, z=pos.z}) + if allowed == 0 then + return + end + if not allowed then + minetest.set_node(pos, {name="nether:dirt"}) + end + end +}) + + +minetest.register_privilege("nether", + "Allows sending players to nether and extracting them") + +dofile(path.."/crafting.lua") +dofile(path.."/portal.lua") +dofile(path.."/guide.lua") + + +local time = (minetest.get_us_time() - load_time_start) / 1000000 +local msg = ("[nether] loaded after ca. %g seconds."):format(time) +if time > 0.01 then + print(msg) +else + minetest.log("info", msg) +end diff --git a/nether/nether/items.lua b/nether/nether/items.lua new file mode 100644 index 00000000..1e3b28c9 --- /dev/null +++ b/nether/nether/items.lua @@ -0,0 +1,1030 @@ +local nether_sound = default.node_sound_stone_defaults({ + dig = {name="nether_dig", gain=0.7}, + dug = {name="nether_dug", gain=1}, + footstep = {name="nether_footstep", gain=0.4} +}) + +local add_fence = minetest.register_fence +local function add_more_nodes(name) + local nd = "nether:"..name + if not string.find(name, "nether") then + name = "nether_"..name + end + local data = minetest.registered_nodes[nd] + stairs.register_stair_and_slab(name, nd, + data.groups, + data.tiles, + data.description.." Stair", + data.description.." Slab", + data.sounds + ) + if add_fence then + add_fence({fence_of = nd}) + end +end + +--[[ +local function add_fence(name) + local def = minetest.registered_nodes[name] + local fencedef = {} + for _,i in pairs({"walkable", "sunlike_propagates"}) do + if def[i] ~= nil then + fencedef[i] = def[i] + end + end +end +--]] + +local creative_installed = minetest.global_exists("creative") + +local function digging_allowed(player, v) + if not player then + return false + end + if creative_installed + and creative.is_enabled_for(player:get_player_name()) then + return true + end + local tool = player:get_wielded_item():get_name() + tool = minetest.registered_tools[tool] or tool == "" + and minetest.registered_items[tool] + if not tool + or not tool.tool_capabilities then + return false + end + local groups = tool.tool_capabilities.groupcaps + if not groups then + return false + end + if groups.nether + and groups.nether.times[v] then + return true + end + return false +end + +-- Netherrack +minetest.register_node("nether:netherrack", { + description = "Netherrack", + tiles = {"nether_netherrack.png"}, + groups = {nether=2}, + sounds = nether_sound, + can_dig = function(_, player) + return digging_allowed(player, 2) + end, +}) +add_more_nodes("netherrack") + +minetest.register_node("nether:netherrack_tiled", { + description = "Tiled Netherrack", + tiles = {"nether_netherrack_tiled.png"}, + groups = {nether=2}, + sounds = nether_sound, + can_dig = function(_, player) + return digging_allowed(player, 2) + end, +}) +add_more_nodes("netherrack_tiled") + +minetest.register_node("nether:netherrack_soil", { + description = "Dirty Netherrack", + tiles = {"nether_netherrack.png^nether_netherrack_soil.png"}, + groups = {nether=2}, + sounds = nether_sound, + can_dig = function(_, player) + return digging_allowed(player, 2) + end, +}) + +minetest.register_node("nether:netherrack_black", { + description = "Black Netherrack", + tiles = {"nether_netherrack_black.png"}, + groups = {nether=2}, + sounds = nether_sound, + can_dig = function(_, player) + return digging_allowed(player, 2) + end, +}) +add_more_nodes("netherrack_black") + +minetest.register_node("nether:netherrack_blue", { + description = "Blue Netherrack", + tiles = {"nether_netherrack_blue.png"}, + groups = {nether=1}, + sounds = nether_sound, + can_dig = function(_, player) + return digging_allowed(player, 1) + end, +}) +add_more_nodes("netherrack_blue") + +-- Netherbrick +minetest.register_node("nether:netherrack_brick", { + description = "Netherrack Brick", + tiles = {"nether_netherrack_brick.png"}, + groups = {nether=3}, + sounds = nether_sound, + can_dig = function(_, player) + return digging_allowed(player, 3) + end, +}) +add_more_nodes("netherrack_brick") + +minetest.register_node("nether:netherrack_brick_blue", { + description = "Blue Netherrack Brick", + tiles = {"nether_netherrack_brick_blue.png"}, + groups = {nether=3}, + sounds = nether_sound, + can_dig = function(_, player) + return digging_allowed(player, 3) + end, +}) +add_more_nodes("netherrack_brick_blue") + +minetest.register_node("nether:netherrack_brick_black", { + description = "Black Netherrack Brick", + tiles = {"nether_netherrack_brick_black.png"}, + groups = {nether=3}, + sounds = nether_sound, + can_dig = function(_, player) + return digging_allowed(player, 3) + end, +}) +add_more_nodes("netherrack_brick_black") + +minetest.register_node("nether:white", { + description = "Siwtonic block", + tiles = {"nether_white.png"}, + groups = {nether=1}, + sounds = nether_sound, + can_dig = function(_, player) + return digging_allowed(player, 1) + end, +}) +add_more_nodes("white") + + +-- Nether blood +minetest.register_node("nether:sapling", { + description = "Nether Blood Child", + drawtype = "plantlike", + tiles = {"nether_sapling.png"}, + inventory_image = "nether_sapling.png", + wield_image = "nether_sapling.png", + paramtype = "light", + walkable = false, + selection_box = { + type = "fixed", + fixed = {-0.3, -0.5, -0.3, 0.3, 0.35, 0.3} + }, + groups = {snappy=2, oddly_breakable_by_hand=2, attached_node=1}, + sounds = default.node_sound_leaves_defaults(), +}) + +minetest.register_node("nether:blood", { + description = "Nether Blood", + tiles = {"nether_blood.png"}, + groups = {snappy=2, choppy=2, oddly_breakable_by_hand=1}, + sounds = default.node_sound_wood_defaults(), +}) +add_more_nodes("blood") + +minetest.register_node("nether:blood_cooked", { + description = "Cooked Nether Blood", + tiles = {"nether_blood_cooked.png"}, + groups = {nether=3}, + sounds = nether_sound, + furnace_burntime = 10, + can_dig = function(_, player) + return digging_allowed(player, 3) + end, +}) +add_more_nodes("blood_cooked") + +minetest.register_node("nether:blood_empty", { + description = "Nether Blood Extracted", + tiles = {"nether_blood_empty.png"}, + groups = {snappy=2, choppy=2, oddly_breakable_by_hand=1}, + sounds = default.node_sound_wood_defaults(), +}) +add_more_nodes("blood_empty") + + +minetest.register_node("nether:blood_top", { + description = "Nether Blood Head", + tiles = {"nether_blood_top.png", "nether_blood.png", + "nether_blood.png^nether_blood_side.png"}, + groups = {snappy=2, choppy=2, oddly_breakable_by_hand=1}, + sounds = default.node_sound_wood_defaults(), +}) +add_more_nodes("blood_top") + +minetest.register_node("nether:blood_top_cooked", { + description = "Cooked Nether Blood Head", + tiles = {"nether_blood_top_cooked.png", "nether_blood_cooked.png", + "nether_blood_cooked.png^nether_blood_side_cooked.png"}, + groups = {nether=3}, + sounds = nether_sound, + furnace_burntime = 10, + can_dig = function(_, player) + return digging_allowed(player, 3) + end, +}) +add_more_nodes("blood_top_cooked") + +minetest.register_node("nether:blood_top_empty", { + description = "Nether Blood Head Extracted", + tiles = {"nether_blood_top_empty.png", "nether_blood_empty.png", + "nether_blood_empty.png^nether_blood_side_empty.png"}, + groups = {snappy=2, choppy=2, oddly_breakable_by_hand=1}, + sounds = default.node_sound_wood_defaults(), +}) +add_more_nodes("blood_top_empty") + + +minetest.register_node("nether:blood_stem", { + description = "Nether Blood Stem", + tiles = {"nether_blood_stem_top.png", "nether_blood_stem_top.png", + "nether_blood_stem.png"}, + groups = {snappy=2, choppy=2, oddly_breakable_by_hand=1}, + sounds = default.node_sound_wood_defaults(), +}) +add_more_nodes("blood_stem") + +minetest.register_node("nether:blood_stem_cooked", { + description = "Cooked Nether Blood Stem", + tiles = {"nether_blood_stem_top_cooked.png", + "nether_blood_stem_top_cooked.png", "nether_blood_stem_cooked.png"}, + groups = {nether=3}, + sounds = nether_sound, + furnace_burntime = 30, + can_dig = function(_, player) + return digging_allowed(player, 3) + end, +}) +add_more_nodes("blood_stem_cooked") + +minetest.register_node("nether:blood_stem_empty", { + description = "Nether Blood Stem Extracted", + tiles = {"nether_blood_stem_top_empty.png", + "nether_blood_stem_top_empty.png", "nether_blood_stem_empty.png"}, + groups = {tree=1, choppy=2, oddly_breakable_by_hand=1}, + sounds = default.node_sound_wood_defaults(), +}) +add_more_nodes("blood_stem_empty") + + +minetest.register_node("nether:wood", { + description = "Nether Blood Wood", + tiles = {"nether_wood.png"}, + groups = {choppy=2, oddly_breakable_by_hand=2}, + sounds = default.node_sound_wood_defaults(), +}) +add_more_nodes("wood") + +minetest.register_node("nether:wood_cooked", { + description = "Cooked Nether Blood Wood", + tiles = {"nether_wood_cooked.png"}, + groups = {nether=3}, + sounds = nether_sound, + furnace_burntime = 8, + can_dig = function(_, player) + return digging_allowed(player, 3) + end, +}) +add_more_nodes("wood_cooked") + +minetest.register_node("nether:wood_empty", { + description = "Nether Wood", + tiles = {"nether_wood_empty.png"}, + groups = {choppy=2, oddly_breakable_by_hand=2, wood=1}, + sounds = default.node_sound_wood_defaults(), +}) +add_more_nodes("wood_empty") + +minetest.register_node("nether:extractor", { + description = "Nether Blood Extractor", + tiles = {"nether_blood_extractor.png"}, + groups = {nether=3}, + sounds = nether_sound, + can_dig = function(_, player) + return digging_allowed(player, 3) + end, +}) + +-- Nether fruit +minetest.register_node("nether:fruit_leaves", { + description = "Nether Fruit Leaves", + tiles = {"nether_fruit_leaves.png"}, + groups = {fleshy=3, dig_immediate=2}, + sounds = default.node_sound_defaults(), + furnace_burntime = 18, +}) +add_more_nodes("fruit_leaves") + +local function room_for_items(inv) + local free_slots = 0 + for _,i in ipairs(inv:get_list("main")) do + if i:get_count() == 0 then + free_slots = free_slots+1 + end + end + if free_slots < 2 then + return false + end + return true +end + +local drop_mushroom = minetest.registered_nodes["riesenpilz:nether_shroom"].on_drop +minetest.override_item("riesenpilz:nether_shroom", { + on_drop = function(itemstack, dropper, pos) + if dropper:get_player_control().aux1 then + return drop_mushroom(itemstack, dropper, pos) + end + local inv = dropper:get_inventory() + if not inv then + return + end + if not room_for_items(inv) then + return + end + minetest.sound_play("nether_remove_leaf", {pos = pos, gain = 0.25}) + itemstack:take_item() + inv:add_item("main", "nether:shroom_head") + inv:add_item("main", "nether:shroom_stem") + return itemstack + end, +}) + +minetest.register_node("nether:apple", { + description = "Nether Fruit", + drawtype = "nodebox", + tiles = {"nether_fruit_top.png", "nether_fruit_bottom.png", + "nether_fruit.png", "nether_fruit.png^[transformFX", + "nether_fruit.png^[transformFX", "nether_fruit.png"}, + use_texture_alpha = "opaque", + node_box = { + type = "fixed", + fixed = { + {-1/6, -1/4, -1/6, 1/6, -1/6, 1/6}, + + {-1/6, -1/6, -1/4, 1/6, 1/6, 1/4}, + {-1/4, -1/6, -1/6, 1/4, 1/6, 1/6}, + + {-1/4, 1/6, -1/12, 1/4, 1/4, 1/12}, + {-1/12, 1/6, -1/4, 1/12, 1/4, 1/4}, + + {-1/6, 1/6, -1/6, 1/6, 1/3, 1/6}, + + {-1/12, 1/3, -1/12, 0, 5/12, 0}, + + {-1/12, 5/12, -1/6, 0, 0.5, 1/12}, + {-1/6, 5/12, -1/12, 1/12, 0.5, 0}, + } + }, + paramtype = "light", + groups = {fleshy=3, dig_immediate=3}, + on_use = function(itemstack, user) + local inv = user:get_inventory() + if not inv then + return + end + itemstack:take_item() + if nether.teleport_player(user) then + return itemstack + end + local amount = math.random(4, 6) + inv:add_item("main", {name="nether:blood_extracted", count=math.floor(amount/3)}) + user:set_hp(user:get_hp()-amount) + return itemstack + end, + sounds = default.node_sound_defaults(), + furnace_burntime = 6, +}) + +local drop_fruit = minetest.registered_nodes["nether:apple"].on_drop +minetest.override_item("nether:apple", { + on_drop = function(itemstack, dropper, pos) + if dropper:get_player_control().aux1 then + return drop_fruit(itemstack, dropper, pos) + end + local inv = dropper:get_inventory() + if not inv then + return + end + if not room_for_items(inv) then + return + end + minetest.sound_play("nether_remove_leaf", {pos = pos, gain = 0.25}) + itemstack:take_item() + inv:add_item("main", "nether:fruit_leaf") + inv:add_item("main", "nether:fruit_no_leaf") + return itemstack + end, +}) + +-- Nether vine +minetest.register_node("nether:vine", { + description = "Nether vine", + walkable = false, + drop = "nether:sapling", + sunlight_propagates = true, + paramtype = "light", + tiles = { "nether_vine.png" }, + drawtype = "plantlike", + inventory_image = "nether_vine.png", + groups = { snappy = 3,flammable=2 }, + sounds = default.node_sound_leaves_defaults(), + after_dig_node = function(pos, _, _, digger) + if digger then + local p = {x=pos.x, y=pos.y-1, z=pos.z} + local nn = minetest.get_node(p) + if nn.name == "nether:vine" then + minetest.node_dig(p, nn, digger) + end + end + end +}) + + +-- forest stuff + +for n,i in pairs({"small", "middle", "big"}) do + minetest.register_node("nether:grass_"..i, { + description = "Nether Grass", + drawtype = "plantlike", + waving = 1, + tiles = {"nether_grass_"..i..".png"}, + inventory_image = "nether_grass_"..i..".png", + wield_image = "nether_grass_"..i..".png", + paramtype = "light", + walkable = false, + buildable_to = true, + drop = "nether:grass "..n, + groups = {snappy=3,flora=1,attached_node=1}, + sounds = default.node_sound_leaves_defaults(), + selection_box = { + type = "fixed", + fixed = {-0.5, -0.5, -0.5, 0.5, -5/16, 0.5}, + }, + }) +end + +minetest.register_node("nether:glowflower", { + description = "Glowing Flower", + drawtype = "plantlike", + tiles = {"nether_glowflower.png"}, + inventory_image = "nether_glowflower.png", + wield_image = "nether_glowflower.png", + sunlight_propagates = true, + paramtype = "light", + walkable = false, + buildable_to = true, + light_source = 10, + groups = {snappy=3,flammable=2,flower=1,flora=1,attached_node=1}, + sounds = default.node_sound_leaves_defaults(), + selection_box = { + type = "fixed", + fixed = { -0.15, -0.5, -0.15, 0.15, 0.2, 0.15 }, + }, +}) + +minetest.register_node("nether:tree_sapling", { + description = "Nether Tree Sapling", + drawtype = "plantlike", + tiles = {"nether_tree_sapling.png"}, + inventory_image = "nether_tree_sapling.png", + wield_image = "nether_tree_sapling.png", + paramtype = "light", + walkable = false, + selection_box = { + type = "fixed", + fixed = {-0.3, -0.5, -0.3, 0.3, 0.35, 0.3} + }, + groups = {snappy=2, oddly_breakable_by_hand=2, attached_node=1}, + sounds = default.node_sound_leaves_defaults(), +}) + +minetest.register_node("nether:tree", { + description = "Nether Trunk", + tiles = {"nether_tree_top.png", "nether_tree_top.png", "nether_tree.png"}, + paramtype2 = "facedir", + is_ground_content = false, + groups = {tree=1,choppy=2,oddly_breakable_by_hand=1}, + sounds = default.node_sound_wood_defaults(), + on_place = minetest.rotate_node +}) + +minetest.register_node("nether:tree_corner", { + description = "Nether Trunk Corner", + tiles = {"nether_tree.png^[transformR180", "nether_tree_top.png", + "nether_tree_corner.png^[transformFY", + "nether_tree_corner.png^[transformR180", "nether_tree.png", + "nether_tree_top.png"}, + paramtype2 = "facedir", + is_ground_content = false, + groups = {tree=1,choppy=2,oddly_breakable_by_hand=1,not_in_creative_inventory=1}, + drop = "nether:tree", + sounds = default.node_sound_wood_defaults(), + on_place = minetest.rotate_node +}) + +minetest.register_node("nether:forest_wood", { + description = "Nether Wood Block", + tiles = {"nether_forest_wood.png"}, + groups = {choppy=2,oddly_breakable_by_hand=2,wood=1}, + sounds = default.node_sound_wood_defaults(), +}) +add_more_nodes("forest_wood") + +minetest.register_node("nether:leaves", { + description = "Nether Leaves", + drawtype = "plantlike", + waving = 1, + visual_scale = math.sqrt(2) + 0.01, + tiles = {"nether_leaves.png"}, + inventory_image = "nether_leaves.png", + wield_image = "nether_leaves.png", + paramtype = "light", + paramtype2 = "degrotate", + is_ground_content = false, + groups = {snappy=3, leafdecay=3, leaves=1}, + drop = { + max_items = 1, + items = { + { + items = {"nether:tree_sapling"}, + rarity = 30, + }, + { + items = {"nether:leaves"}, + } + } + }, + sounds = default.node_sound_leaves_defaults(), +}) + +minetest.register_node("nether:dirt", { + description = "Nether Dirt", + tiles = {"nether_dirt.png"}, + groups = {crumbly=3,soil=1,nether_dirt=1}, + sounds = default.node_sound_dirt_defaults(), +}) + +minetest.register_node("nether:dirt_top", { + description = "Nether Dirt Top", + tiles = {"nether_dirt_top.png", "nether_dirt.png", + {name="nether_dirt.png^nether_dirt_top_side.png", tileable_vertical = false} + }, + groups = {crumbly=3,soil=1,nether_dirt=1}, + drop = "nether:dirt", + sounds = default.node_sound_dirt_defaults({ + footstep = {name="default_grass_footstep", gain=0.25}, + }), +}) + +minetest.register_node("nether:dirt_bottom", { + description = "Netherrack Dirt Transition", + tiles = {"nether_dirt.png", "nether_netherrack.png", + {name="nether_netherrack.png^nether_dirt_transition.png", tileable_vertical = false} + }, + groups = {nether=2}, + drop = "nether:netherrack", + sounds = default.node_sound_dirt_defaults({ + dig = {name="nether_dig", gain=0.7}, + dug = {name="nether_dug", gain=1}, + }), + can_dig = function(_, player) + return digging_allowed(player, 2) + end, +}) + + +-- Nether torch +minetest.register_node("nether:torch", { + description = "Nether Torch", + drawtype = "torchlike", + tiles = {"nether_torch_on_floor.png", "nether_torch_on_ceiling.png", + { + name = "nether_torch.png", + animation = { + type = "vertical_frames", + aspect_w = 16, + aspect_h = 16, + length = 2.0, + }, + }, + }, + inventory_image = "nether_torch_on_floor.png", + wield_image = "nether_torch_on_floor.png", + paramtype = "light", + paramtype2 = "wallmounted", + sunlight_propagates = true, + walkable = false, + light_source = 13, + selection_box = { + type = "wallmounted", + wall_top = {-0.1, 0.5-0.6, -0.1, 0.1, 0.5, 0.1}, + wall_bottom = {-0.1, -0.5, -0.1, 0.1, -0.5+0.6, 0.1}, + wall_side = {-0.5, -0.3, -0.1, -0.5+0.3, 0.3, 0.1}, + }, + groups = {choppy=2, dig_immediate=3, attached_node=1, hot=3, igniter=1}, + legacy_wallmounted = true, + sounds = default.node_sound_defaults(), +}) + +local invisible = "nether_transparent.png" +minetest.register_node("nether:portal", { + description = "Nether Portal Essence", + tiles = {invisible, invisible, invisible, invisible, "nether_portal_stuff.png"}, + inventory_image = "nether_portal_stuff.png", + wield_image = "nether_portal_stuff.png", + light_source = 12, + paramtype = "light", + sunlight_propagates = true, + use_texture_alpha = "blend", + walkable = false, + pointable = false, + buildable_to = false, + drop = "", + diggable = false, + groups = {not_in_creative_inventory=1}, + post_effect_color = {a=200, r=50, g=0, b=60},--{a=180, r=128, g=0, b=128} + drawtype = "nodebox", + paramtype2 = "facedir", + node_box = { + type = "fixed", + fixed = { + {-0.5, -0.5, -0.1, 0.5, 0.5, 0.1}, + }, + }, +}) + + +minetest.register_craftitem("nether:grass", { + description = "Nether Grass", + inventory_image = "nether_grass.png", +}) + +minetest.register_craftitem("nether:grass_dried", { + description = "Dried Nether Grass", + inventory_image = "nether_grass_dried.png", + furnace_burntime = 1, +}) + +minetest.register_craftitem("nether:forest_planks", { + description = "Nether Wooden Planks", + inventory_image = "nether_forest_planks.png", + stack_max = 990, +}) + +minetest.register_craftitem("nether:bark", { + description = "Nether Trunk Bark", + inventory_image = "nether_bark.png", + furnace_burntime = 5, +}) + +-- Nether Pearl +minetest.register_craftitem("nether:pearl", { + description = "Nether Pearl", + inventory_image = "nether_pearl.png", +}) + +minetest.register_craftitem("nether:stick", { + description = "Nether Stick", + inventory_image = "nether_stick.png", + groups = {stick=1}, +}) + +local tmp = {} +minetest.register_craftitem("nether:shroom_head", { + description = "Nether Mushroom Head", + inventory_image = "nether_shroom_top.png", + furnace_burntime = 3, + on_place = function(itemstack, _, pointed_thing) + if not pointed_thing then + return + end + + if pointed_thing.type ~= "node" then + return + end + + local pos = minetest.get_pointed_thing_position(pointed_thing) + local node = minetest.get_node(pos) + local pstr = pos.x.." "..pos.y.." "..pos.z + + if node.name == "nether:netherrack_soil" + and not tmp[pstr] then + minetest.sound_play("default_grass_footstep", {pos=pos}) + minetest.set_node(pos, {name="nether:netherrack_soil", param2=math.max(node.param2, math.random(3, 10))}) + tmp[pstr] = true + minetest.after(3, function() tmp[pos.x.." "..pos.y.." "..pos.z] = nil end) + end + end +}) + +minetest.register_craftitem("nether:shroom_stem", { + description = "Nether Mushroom Stem", + inventory_image = "nether_shroom_stem.png", + furnace_burntime = 3, +}) + +minetest.register_craftitem("nether:fruit_leaf", { + description = "Nether Fruit Leaf", + inventory_image = "nether_fruit_leaf.png", + furnace_burntime = 2, +}) + +minetest.register_craftitem("nether:fruit_no_leaf", { + description = "Nether Fruit Without Leaf", + inventory_image = "nether_fruit_no_leaf.png", + furnace_burntime = 4, +}) + +minetest.register_craftitem("nether:fim", { + description = "Nether FIM", --fruit in mushroom + inventory_image = "nether_fim.png", + furnace_burntime = 10, +}) + +local blood_exno = {} +for _,i in ipairs({"nether:blood", "nether:blood_top", "nether:blood_stem"}) do + blood_exno[i] = i.."_empty" +end + +minetest.register_craftitem("nether:blood_extracted", { + description = "Blood", + inventory_image = "nether_blood_extracted.png", + on_place = function(itemstack, _, pointed_thing) + if not pointed_thing then + return + end + + if pointed_thing.type ~= "node" then + return + end + + local pos = minetest.get_pointed_thing_position(pointed_thing) + local node = minetest.get_node_or_nil(pos) + + if not node then + return + end + + if node.name == "nether:vine" then + pos = {x=pos.x, y=pos.y-1, z=pos.z} + if minetest.get_node(pos).name == "air" then + minetest.set_node(pos, {name = "nether:vine"}) + end + itemstack:take_item() + return itemstack + end + + if node.name ~= "nether:extractor" then + return + end + itemstack:take_item() + minetest.after(1, function(pos) + for i = -1,1,2 do + for _,p in ipairs({ + {x=pos.x+i, y=pos.y, z=pos.z}, + {x=pos.x, y=pos.y, z=pos.z+i}, + }) do + local nodename = blood_exno[minetest.get_node(p).name] + if nodename then + minetest.set_node(p, {name=nodename}) + p = vector.add(p, {x=math.random()-0.5, y=math.random()+0.5, z=math.random()-0.5}) + minetest.sound_play("nether_extract_blood", {pos = p, gain = 1}) + minetest.add_item(p, "nether:blood_extracted") + end + end + end + end, pos) + + return itemstack + end +}) + +minetest.register_craftitem("nether:hotbed", { + description = "Cooked Blood", + inventory_image = "nether_hotbed.png", + on_place = function(itemstack, _, pointed_thing) + if not pointed_thing then + return + end + if pointed_thing.type ~= "node" then + return + end + local pos = minetest.get_pointed_thing_position(pointed_thing) + local node = minetest.get_node(pos) + + if node.name ~= "nether:netherrack" then + return + end + + minetest.sound_play("default_place_node", {pos=pos}) + minetest.set_node(pos, {name = "nether:netherrack_soil"}) + + itemstack:take_item() + return itemstack + end +}) + + +minetest.register_tool("nether:pick_mushroom", { + description = "Nether Mushroom Pickaxe", + inventory_image = "nether_pick_mushroom.png", + tool_capabilities = { + max_drop_level=0, + groupcaps={ + cracky = {times={[3]=3}, uses=1, maxlevel=1}, + nether = {times={[3]=3}, uses=1, maxlevel=1}, + }, + }, +}) + +minetest.register_tool("nether:pick_wood", { + description = "Nether Wood Pickaxe", + inventory_image = "nether_pick_wood.png", + tool_capabilities = { + full_punch_interval = 1.2, + max_drop_level=0, + groupcaps={ + cracky = {times={[3]=1.6}, uses=10, maxlevel=1}, + nether = {times={[2]=6, [3]=1.6}, uses=10, maxlevel=1}, + }, + damage_groups = {fleshy=2}, + }, +}) + +minetest.register_tool("nether:pick_netherrack", { + description = "Netherrack Pickaxe", + inventory_image = "nether_pick_netherrack.png", + tool_capabilities = { + full_punch_interval = 1.3, + max_drop_level=0, + groupcaps={ + cracky = {times={[2]=2.0, [3]=1.20}, uses=20, maxlevel=1}, + nether = {times={[1]=16, [2]=2, [3]=1.20}, uses=20, maxlevel=1}, + }, + damage_groups = {fleshy=3}, + }, +}) + +minetest.register_tool("nether:pick_netherrack_blue", { + description = "Blue Netherrack Pickaxe", + inventory_image = "nether_pick_netherrack_blue.png", + tool_capabilities = { + full_punch_interval = 1.0, + max_drop_level=1, + groupcaps={ + cracky = {times={[1]=4.00, [2]=1.60, [3]=0.80}, uses=30, maxlevel=2}, + nether = {times={[1]=4.00, [2]=1.60, [3]=0.80}, uses=30, maxlevel=2}, + }, + damage_groups = {fleshy=4}, + }, +}) + +minetest.register_tool("nether:pick_white", { + description = "Siwtonic Pickaxe", + inventory_image = "nether_pick_white.png", + tool_capabilities = { + full_punch_interval = 0.9, + max_drop_level=3, + groupcaps={ + cracky = {times={[1]=1, [2]=0.8, [3]=0.3}, uses=180, maxlevel=3}, + nether = {times={[1]=1, [2]=0.5, [3]=0.3}, uses=180, maxlevel=3}, + }, + damage_groups = {fleshy=5}, + }, +}) + +minetest.register_tool("nether:axe_netherrack", { + description = "Netherrack Axe", + inventory_image = "nether_axe_netherrack.png", + tool_capabilities = { + full_punch_interval = 1.3, + max_drop_level=0, + groupcaps={ + choppy={times={[1]=2.9, [2]=1.9, [3]=1.4}, uses=20, maxlevel=1}, + }, + damage_groups = {fleshy=4}, + }, +}) + +minetest.register_tool("nether:axe_netherrack_blue", { + description = "Blue Netherrack Axe", + inventory_image = "nether_axe_netherrack_blue.png", + tool_capabilities = { + full_punch_interval = 0.9, + max_drop_level=1, + groupcaps={ + choppy={times={[1]=2.5, [2]=1.5, [3]=1}, uses=30, maxlevel=2}, + }, + damage_groups = {fleshy=6}, + }, +}) + +minetest.register_tool("nether:axe_white", { + description = "Siwtonic Axe", + inventory_image = "nether_axe_white.png", + tool_capabilities = { + full_punch_interval = 0.9, + max_drop_level=1, + groupcaps={ + choppy={times={[1]=1.2, [2]=0.5, [3]=0.3}, uses=180, maxlevel=2}, + }, + damage_groups = {fleshy=8}, + }, +}) + +minetest.register_tool("nether:shovel_netherrack", { + description = "Netherrack Shovel", + inventory_image = "nether_shovel_netherrack.png", + wield_image = "nether_shovel_netherrack.png^[transformR90", + tool_capabilities = { + full_punch_interval = 1.4, + max_drop_level=0, + groupcaps={ + crumbly = {times={[1]=1.7, [2]=1.1, [3]=0.45}, uses=22, maxlevel=2}, + }, + damage_groups = {fleshy=2}, + }, +}) + +minetest.register_tool("nether:shovel_netherrack_blue", { + description = "Blue Netherrack Shovel", + inventory_image = "nether_shovel_netherrack_blue.png", + wield_image = "nether_shovel_netherrack_blue.png^[transformR90", + tool_capabilities = { + full_punch_interval = 1.1, + max_drop_level=1, + groupcaps={ + crumbly = {times={[1]=1.4, [2]=0.8, [3]=0.35}, uses=50, maxlevel=2}, + }, + damage_groups = {fleshy=3}, + }, +}) + +minetest.register_tool("nether:shovel_white", { + description = "Siwtonic Shovel", + inventory_image = "nether_shovel_white.png", + wield_image = "nether_shovel_white.png^[transformR90", + tool_capabilities = { + full_punch_interval = 1, + max_drop_level=1, + groupcaps={ + crumbly = {times={[1]=0.95, [2]=0.45, [3]=0.1}, uses=151, maxlevel=3}, + }, + damage_groups = {fleshy=4}, + }, +}) + +minetest.register_tool("nether:sword_netherrack", { + description = "Netherrack Sword", + inventory_image = "nether_sword_netherrack.png", + tool_capabilities = { + full_punch_interval = 1, + max_drop_level=0, + groupcaps={ + snappy={times={[2]=1.3, [3]=0.38}, uses=40, maxlevel=1}, + }, + damage_groups = {fleshy=5}, + }, +}) + +minetest.register_tool("nether:sword_netherrack_blue", { + description = "Blue Netherrack Sword", + inventory_image = "nether_sword_netherrack_blue.png", + tool_capabilities = { + full_punch_interval = 0.8, + max_drop_level=1, + groupcaps={ + snappy={times={[1]=2.5, [2]=1.1, [3]=0.33}, uses=40, maxlevel=2}, + }, + damage_groups = {fleshy=7}, + }, +}) + +minetest.register_tool("nether:sword_white", { + description = "Siwtonic Sword", + inventory_image = "nether_sword_white.png", + wield_image = "nether_sword_white.png^[transformR90", + tool_capabilities = { + full_punch_interval = 0.7, + max_drop_level=1, + groupcaps={ + snappy={times={[1]=1.7, [2]=0.8, [3]=0.2}, uses=100, maxlevel=3}, + }, + damage_groups = {fleshy=11}, + }, +}) + + +-- override creative hand +if minetest.settings:get_bool("creative_mode") then + local capas = minetest.registered_items[""].tool_capabilities + capas.groupcaps.nether = capas.groupcaps.cracky + minetest.override_item("", {tool_capabilities = capas}) +end diff --git a/nether/nether/mod.conf b/nether/nether/mod.conf new file mode 100644 index 00000000..eb8e675d --- /dev/null +++ b/nether/nether/mod.conf @@ -0,0 +1,3 @@ +name = nether +depends = default,glow,riesenpilz,stairs,vector_extras +optional_depends = creative,fence_registration,function_delayer,watershed diff --git a/nether/nether/pearl.lua b/nether/nether/pearl.lua new file mode 100644 index 00000000..236efce1 --- /dev/null +++ b/nether/nether/pearl.lua @@ -0,0 +1,190 @@ + +local function throw_pearl(item, player) + local playerpos = player:get_pos() + playerpos.y = playerpos.y+1.625 + local obj = minetest.add_entity(playerpos, "nether:pearl_entity") + local dir = player:get_look_dir() + obj:setvelocity(vector.multiply(dir, 30)) + obj:setacceleration({x=dir.x*-3, y=-dir.y^8*80-10, z=dir.z*-3}) + local pname = player:get_player_name() + obj:get_luaentity().player = pname + if not minetest.is_creative_enabled(pname) then + item:take_item() + return item + end +end + +local function get_node(pos) + local name = minetest.get_node(pos).name + if name ~= "ignore" then + return name + end + minetest.get_voxel_manip():read_from_map(pos, pos) + name = minetest.get_node_or_nil(pos) + if not name then + return + end + return name.name +end + +local softs = {} +local function is_soft(pos) + local name = get_node(pos) + if not name then + return false + end + local is_soft = softs[name] + if is_soft ~= nil then + return is_soft + end + if not minetest.registered_nodes[name] then + softs[name] = false + return false + end + is_soft = minetest.registered_nodes[name].walkable == false + softs[name] = is_soft + return is_soft +end + +-- teleports the player there if there's free space +local function teleport_player(pos, player) + if not is_soft(pos) then + return false + end + if not is_soft({x=pos.x, y=pos.y+1, z=pos.z}) + and not is_soft({x=pos.x, y=pos.y-1, z=pos.z}) then + return false + end + pos.y = pos.y+0.05 + player:moveto(pos) + return true +end + +--[[ +local dg_ps = {} +local function forceload(pos) + dg_ps[#dg_ps+1] = pos + minetest.forceload_block(pos) + minetest.after(5, function(pos) + minetest.forceload_free_block(pos) + for i,p in pairs(dg_ps) do + if vector.equals(p, pos) then + dg_ps[i] = nil + return + end + end + end, pos) +end +minetest.register_on_shutdown(function() + for _,p in pairs(dg_ps) do + minetest.forceload_free_block(p) + end +end)--]] + +minetest.register_entity("nether:pearl_entity", { + collisionbox = {0,0,0,0,0,0}, --not pointable + visual_size = {x=0.1, y=0.1}, + physical = false, -- Collides with things + textures = {"nether_pearl.png"}, + on_activate = function(self, staticdata) + if not staticdata + or staticdata == "" then + return + end + local tmp = minetest.deserialize(staticdata) + if not tmp then + minetest.log("error", "[nether] pearl: invalid staticdata ") + return + end + self.player = tmp.player + end, + get_staticdata = function(self) + --forceload(vector.round(self.object:get_pos())) + return minetest.serialize({ + player = self.player, + }) + end, + timer = 0, + on_step = function(self, dtime) + self.timer = self.timer+dtime + + --[[ + local delay = self.delay + if delay < 0.1 then + self.delay = delay+dtime + return + end + self.delay = 0--]] + + if self.timer > 20 then + self.object:remove() + return + end + + local pos = self.object:get_pos() + local rpos = vector.round(pos) + local lastpos = self.lastpos + if not lastpos then + self.lastpos = vector.new(rpos) + return + end + if lastpos.x + and vector.equals(vector.round(lastpos), rpos) then + return + end + + local player = self.player + if not player then + minetest.log("error", "[nether] pearl: missing playername") + self.object:remove() + return + end + player = minetest.get_player_by_name(player) + if not player then + minetest.log("error", "[nether] pearl: missing player") + self.object:remove() + return + end + + if not get_node(rpos) then + minetest.log("error", "[nether] pearl: missing node") + self.object:remove() + return + end + + self.lastpos = vector.new(pos) + + local free, p = minetest.line_of_sight(lastpos, pos) + if free then + return + end + if is_soft(p) then + return + end + self.object:remove() + minetest.after(0, function(p) --minetest.after is used that the sound is played after the teleportation + minetest.sound_play("nether_pearl", {pos=p, max_hear_distance=10}) + end, p) + p.y = p.y+1 + if teleport_player(vector.new(p), player) then + return + end + p.y = p.y-2 + for i = -1,1,2 do + for _,j in pairs({{i, 0}, {0, i}}) do + if teleport_player({x=p.x+j[1], y=p.y, z=p.z+j[2]}, player) then + return + end + end + end + for i = -1,1,2 do + for j = -1,1,2 do + if teleport_player({x=p.x+j, y=p.y, z=p.z+i}, player) then + return + end + end + end + end +}) + +minetest.override_item("nether:pearl", {on_use = throw_pearl}) diff --git a/nether/nether/portal.lua b/nether/nether/portal.lua new file mode 100644 index 00000000..619e64f7 --- /dev/null +++ b/nether/nether/portal.lua @@ -0,0 +1,697 @@ +--code copied from Pilzadam's nether mod and edited + +-- kills the player if he uses PilzAdam portal +local portal_target = nether.buildings+1 +local nether_prisons = minetest.settings:get_bool("enable_damage") +local obsidian_portal_kills = nether_prisons and true +local mclike_portal = false + +local abm_allowed +minetest.after(5, function() + abm_allowed = true +end) + +local save_path = minetest.get_worldpath() .. "/nether_players" +local players_in_nether = {} +-- only get info from file if nether prisons +if nether_prisons then + local file = io.open(save_path, "r") + if not file then + return + end + local contents = file:read"*all" + io.close(file) + if not contents then + return + end + local playernames = string.split(contents, " ") + for i = 1,#playernames do + players_in_nether[playernames[i]] = true + end +end + +local function save_nether_players() + local playernames,n = {},1 + for name in pairs(players_in_nether) do + playernames[n] = name + n = n+1 + end + local f = io.open(save_path, "w") + assert(f, "Could not open nether_players file for writing.") + f:write(table.concat(playernames, " ")) + io.close(f) +end + +local update_background +if nether_prisons then + function update_background(player, down) + if down then + player:set_sky({r=15, g=0, b=0}, "plain") + else + player:set_sky(nil, "regular") + end + end +else + function update_background()end +end + +-- returns nodename if area is generated, else calls generation function +local function generated_or_generate(pos) + local node = minetest.get_node_or_nil(pos) + if node then + return node.name + end + minetest.get_voxel_manip():read_from_map(pos, pos) + node = minetest.get_node_or_nil(pos) + if not node then + minetest.emerge_area(vector.subtract(pos, 80), vector.add(pos, 80)) + return false + end + return node.name +end + +-- where the player appears after dying +local function get_player_died_target(player) + local target = vector.add(player:get_pos(), + {x=math.random(-100,100), y=0, z=math.random(-100,100)}) + target.y = portal_target + math.random(4) + return target +end + +-- used for obsidian portal +local function obsidian_teleport(player, pname, target) + minetest.chat_send_player(pname, "For any reason you arrived here. Type " .. + "/nether_help to find out things like craft recipes.") + players_in_nether[pname] = true + save_nether_players() + update_background(player, true) + if target then + player:set_pos(target) + else + player:set_hp(0) + end +end + +-- teleports players to nether or helps it +local function player_to_nether(player, pos) + local pname = player:get_player_name() + if players_in_nether[pname] then + return + end + players_in_nether[pname] = true + save_nether_players() + update_background(player, true) + if pos then + player:set_pos(pos) + return + end + minetest.chat_send_player(pname, "For any reason you arrived here. " .. + "Type /nether_help to find out things like craft recipes.") + player:set_hp(0) + if not nether_prisons then + player:set_pos(get_player_died_target(player)) + end +end + +local function player_from_nether(player, pos) + local pname = player:get_player_name() + if players_in_nether[pname] then + players_in_nether[pname] = nil + save_nether_players() + end + update_background(player) + player:set_pos(pos) +end + + +local function player_exists(name) + local players = minetest.get_connected_players() + for i = 1,#players do + if players[i]:get_player_name() == name then + return true + end + end + return false +end + +-- Chatcommands (edited) written by sss +minetest.register_chatcommand("to_hell", { + params = "[]", + description = "Send someone to hell", + func = function(name, pname) + if not minetest.check_player_privs(name, {nether=true}) then + return false, + "You need the nether privilege to execute this chatcommand." + end + if not player_exists(pname) then + pname = name + end + local player = minetest.get_player_by_name(pname) + if not player then + return false, "Something went wrong." + end + minetest.chat_send_player(pname, "Go to hell !!!") + player_to_nether(player) + return true, pname.." is now in the nether." + end +}) + +minetest.register_chatcommand("from_hell", { + params = "[]", + description = "Extract from hell", + func = function(name, pname) + if not minetest.check_player_privs(name, {nether=true}) then + return false, + "You need the nether priv to execute this chatcommand." + end + if not player_exists(pname) then + pname = name + end + local player = minetest.get_player_by_name(pname) + if not player then + return false, "Something went wrong." + end + minetest.chat_send_player(pname, "You are free now") + local pos = player:get_pos() + player_from_nether(player, {x=pos.x, y=100, z=pos.z}) + return true, pname.." is now out of the nether." + end +}) + + +if nether_prisons then + -- randomly set player position when he/she dies in nether + minetest.register_on_respawnplayer(function(player) + local pname = player:get_player_name() + if not players_in_nether[pname] then + return + end + local target = get_player_died_target(player) + player:set_pos(target) + minetest.after(0, function(pname, target) + -- fixes respawn bug + local player = minetest.get_player_by_name(pname) + if player then + player:moveto(target) + end + end, pname, target) + return true + end) + + -- override set_pos etc. to disallow player teleportion by e.g. travelnet + local function can_teleport(player, pos) + if not player:is_player() then + -- the same metatable is used for entities + return true + end + local pname = player:get_player_name() + local in_nether = players_in_nether[pname] == true + + -- test if the target is valid + if pos.y < nether.start then + if in_nether then + return true + end + elseif not in_nether then + return true + end + + -- test if the current position is valid + local current_pos = player:get_pos() + local now_in_nether = current_pos.y < nether.start + if now_in_nether ~= in_nether then + if in_nether then + minetest.log("action", "Player \"" .. pname .. + "\" has to be in the nether, teleporting it!") + update_background(player, true) + current_pos.y = portal_target + player:set_pos(current_pos) + else + minetest.log("action", "Player \"" .. pname .. + "\" must not be in the nether, teleporting it!") + update_background(player) + current_pos.y = 20 + player:set_pos(current_pos) + end + return false + end + + minetest.chat_send_player(pname, + "You can not simply teleport to or from the nether!") + minetest.log("action", "Player \"" .. pname .. + "\" attempted to teleport from or to the nether, ignoring.") + return false + end + local methods = {"set_pos", "move_to", "setpos", "moveto"} + local metatable_overridden + minetest.register_on_joinplayer(function(player) + -- set the background when the player joins + if player:get_pos().y < nether.start then + update_background(player, true) + end + + -- overide set_pos etc. if not yet done + if metatable_overridden then + return + end + metatable_overridden = true + local mt = getmetatable(player) + for i = 1,#methods do + local methodname = methods[i] + local origfunc = mt[methodname] + mt[methodname] = function(...) + if can_teleport(...) then + origfunc(...) + end + end + end + end) +else + -- test if player is in nether when he/she joins + minetest.register_on_joinplayer(function(player) + players_in_nether[player:get_player_name()] = + player:get_pos().y < nether.start or nil + end) +end + +-- removes the violet stuff from the obsidian portal +local function remove_portal_essence(pos) + for z = -1,1 do + for y = -2,2 do + for x = -1,1 do + local p = {x=pos.x+x, y=pos.y+y, z=pos.z+z} + if minetest.get_node(p).name == "nether:portal" then + minetest.remove_node(p) + end + end + end + end +end + +-- change parts of the particledefinition instead of recreating it every time +local particledef = { + amount = 32, + time = 4, + minvel = {x=0, y=1, z=0}, + maxvel = {x=0, y=2, z=0}, + minacc = {x=-0.5,y=-3,z=-0.3}, + maxacc = {x=0.5,y=-0.4,z=0.3}, + minexptime = 1, + maxexptime = 1, + minsize = 0.4, + maxsize = 3, + collisiondetection = true, +} + +-- teleports player to neter (obsidian portal) +local function obsi_teleport_player(player, pos, target) + local pname = player:get_player_name() + if players_in_nether[pname] then + return + end + + local objpos = player:get_pos() + objpos.y = objpos.y+0.1 -- Fix some glitches at -8000 + if minetest.get_node(vector.round(objpos)).name ~= "nether:portal" then + return + end + + local has_teleported + if obsidian_portal_kills then + obsidian_teleport(player, pname) + has_teleported = true + elseif not mclike_portal then + local target = vector.round(get_player_died_target(player)) + if generated_or_generate(target) then + obsidian_teleport(player, pname, target) + has_teleported = true + end + end + + if not has_teleported then + -- e.g. ungenerated area + return + end + + remove_portal_essence(pos) + + minetest.sound_play("nether_portal_usual", {to_player=pname, gain=1}) +end + +-- abm for particles of the obsidian portal essence and for teleporting +minetest.register_abm({ + nodenames = {"nether:portal"}, + interval = 1, + chance = 2, + catch_up = false, + action = function(pos, node) + if not abm_allowed then + return + end + particledef.minpos = {x=pos.x-0.25, y=pos.y-0.5, z=pos.z-0.25} + particledef.maxpos = {x=pos.x+0.25, y=pos.y+0.34, z=pos.z+0.25} + particledef.texture = "nether_portal_particle.png^[transform" .. + math.random(0, 7) + minetest.add_particlespawner(particledef) + for _,obj in pairs(minetest.get_objects_inside_radius(pos, 1)) do + if obj:is_player() then + local meta = minetest.get_meta(pos) + local target = minetest.string_to_pos(meta:get_string("target")) + if target then + minetest.after(3, obsi_teleport_player, obj, pos, target) + end + end + end + end, +}) + +local function move_check(p1, max, dir) + local p = {x=p1.x, y=p1.y, z=p1.z} + local d = math.abs(max-p1[dir]) / (max-p1[dir]) + while p[dir] ~= max do + p[dir] = p[dir] + d + if minetest.get_node(p).name ~= "default:obsidian" then + return false + end + end + return true +end + +local function check_portal(p1, p2) + if p1.x ~= p2.x then + if not move_check(p1, p2.x, "x") then + return false + end + if not move_check(p2, p1.x, "x") then + return false + end + elseif p1.z ~= p2.z then + if not move_check(p1, p2.z, "z") then + return false + end + if not move_check(p2, p1.z, "z") then + return false + end + else + return false + end + + if not move_check(p1, p2.y, "y") then + return false + end + if not move_check(p2, p1.y, "y") then + return false + end + + return true +end + +-- tests if it's an obsidian portal +local function is_portal(pos) + for d=-3,3 do + for y=-4,4 do + local px = {x=pos.x+d, y=pos.y+y, z=pos.z} + local pz = {x=pos.x, y=pos.y+y, z=pos.z+d} + if check_portal(px, {x=px.x+3, y=px.y+4, z=px.z}) then + return px, {x=px.x+3, y=px.y+4, z=px.z} + end + if check_portal(pz, {x=pz.x, y=pz.y+4, z=pz.z+3}) then + return pz, {x=pz.x, y=pz.y+4, z=pz.z+3} + end + end + end +end + +-- put here the function for creating a second portal +local create_second_portal +if mclike_portal then + function create_second_portal(target) + -- change target here + end +end + +-- adds the violet portal essence +local function make_portal(pos) + local p1, p2 = is_portal(pos) + if not p1 + or not p2 then + print("[nether] something failed.") + return false + end + + local in_nether = p1.y < nether.start + + if in_nether + and not mclike_portal then + print("[nether] aborted, obsidian portals can't be used to get out") + return + end + + for d=1,2 do + for y=p1.y+1,p2.y-1 do + local p + if p1.z == p2.z then + p = {x=p1.x+d, y=y, z=p1.z} + else + p = {x=p1.x, y=y, z=p1.z+d} + end + if minetest.get_node(p).name ~= "air" then + return false + end + end + end + + local param2 + if p1.z == p2.z then + param2 = 0 + else + param2 = 1 + end + + local target = {x=p1.x, y=p1.y, z=p1.z} + target.x = target.x + 1 + if in_nether then + target.y = 0 + create_second_portal(target) + else + target.y = portal_target + math.random(4) + end + + if not generated_or_generate(target) + and mclike_portal then + return false + end + + for d=0,3 do + for y=p1.y,p2.y do + local p + if param2 == 0 then + p = {x=p1.x+d, y=y, z=p1.z} + else + p = {x=p1.x, y=y, z=p1.z+d} + end + if minetest.get_node(p).name == "air" then + minetest.set_node(p, {name="nether:portal", param2=param2}) + end + local meta = minetest.get_meta(p) + meta:set_string("p1", minetest.pos_to_string(p1)) + meta:set_string("p2", minetest.pos_to_string(p2)) + meta:set_string("target", minetest.pos_to_string(target)) + end + end + print("[nether] construction accepted.") + return true +end + +-- destroy the portal when destroying obsidian +minetest.override_item("default:obsidian", { + on_destruct = function(pos) + local meta = minetest.get_meta(pos) + local p1 = minetest.string_to_pos(meta:get_string("p1")) + local p2 = minetest.string_to_pos(meta:get_string("p2")) + local target = minetest.string_to_pos(meta:get_string("target")) + if not p1 or not p2 then + return + end + for x=p1.x,p2.x do + for y=p1.y,p2.y do + for z=p1.z,p2.z do + local nn = minetest.get_node({x=x,y=y,z=z}).name + if nn == "default:obsidian" or nn == "nether:portal" then + if nn == "nether:portal" then + minetest.remove_node({x=x,y=y,z=z}) + end + local m = minetest.get_meta({x=x,y=y,z=z}) + m:set_string("p1", "") + m:set_string("p2", "") + m:set_string("target", "") + end + end + end + end + meta = minetest.get_meta(target) + if not meta then + return + end + p1 = minetest.string_to_pos(meta:get_string("p1")) + p2 = minetest.string_to_pos(meta:get_string("p2")) + if not p1 or not p2 then + return + end + for x=p1.x,p2.x do + for y=p1.y,p2.y do + for z=p1.z,p2.z do + local nn = minetest.get_node({x=x,y=y,z=z}).name + if nn == "default:obsidian" or nn == "nether:portal" then + if nn == "nether:portal" then + minetest.remove_node({x=x,y=y,z=z}) + end + local m = minetest.get_meta({x=x,y=y,z=z}) + m:set_string("p1", "") + m:set_string("p2", "") + m:set_string("target", "") + end + end + end + end + end +}) + +-- override mese crystal fragment for making an obsidian portal +minetest.after(0.1, function() + minetest.override_item("default:mese_crystal_fragment", { + on_place = function(stack, player, pt) + if pt.under + and minetest.get_node(pt.under).name == "default:obsidian" then + local done = make_portal(pt.under) + if done then + minetest.chat_send_player(player:get_player_name(), + "Warning: If you are in the nether you may not be " .. + "able to find the way out!") + if not minetest.settings:get_bool("creative_mode") then + stack:take_item() + end + end + end + return stack + end + }) +end) + + +-- a not filled square +local function vector_square(r) + local tab, n = {}, 1 + for i = -r+1, r do + for j = -1, 1, 2 do + local a, b = r*j, i*j + tab[n] = {a, b} + tab[n+1] = {b, a} + n=n+2 + end + end + return tab +end + +local function is_netherportal(pos) + local x, y, z = pos.x, pos.y, pos.z + for _,i in pairs({-1, 3}) do + if minetest.get_node({x=x, y=y+i, z=z}).name ~= "nether:white" then + return + end + end + for _,sn in pairs(vector_square(1)) do + if minetest.get_node({x=x+sn[1], y=y-1, z=z+sn[2]}).name ~= "nether:netherrack" + or minetest.get_node({x=x+sn[1], y=y+3, z=z+sn[2]}).name ~= "nether:blood_cooked" then + return + end + end + for _,sn in pairs(vector_square(2)) do + if minetest.get_node({x=x+sn[1], y=y-1, z=z+sn[2]}).name ~= "nether:netherrack_black" + or minetest.get_node({x=x+sn[1], y=y+3, z=z+sn[2]}).name ~= "nether:wood_empty" then + return + end + end + for i = -1,1,2 do + for j = -1,1,2 do + if minetest.get_node({x=x+i, y=y+2, z=z+j}).name ~= "nether:apple" then + return + end + end + end + for i = -2,2,4 do + for j = 0,2 do + for k = -2,2,4 do + if minetest.get_node({x=x+i, y=y+j, z=z+k}).name ~= "nether:netherrack_brick_blue" then + return + end + end + end + end + for i = -1,1 do + for j = -1,1 do + if minetest.get_node({x=x+i, y=y+4, z=z+j}).name ~= "nether:wood_empty" then + return + end + end + end + return true +end + +-- cache known portals +local known_portals_d = {} +local known_portals_u = {} +local function get_portal(t, z,x) + return t[z] and t[z][x] +end +local function set_portal(t, z,x, y) + t[z] = t[z] or {} + t[z][x] = y +end + +-- used when a player eats that fruit in a portal +function nether.teleport_player(player) + if not player then + minetest.log("error", "[nether] Missing player.") + return + end + local pos = vector.round(player:get_pos()) + if not is_netherportal(pos) then + return + end + minetest.sound_play("nether_teleporter", {pos=pos}) + local meta = minetest.get_meta({x=pos.x, y=pos.y-1, z=pos.z}) + if pos.y < nether.start then + set_portal(known_portals_d, pos.z,pos.x, pos.y) + + local my = tonumber(meta:get_string("y")) + local y = get_portal(known_portals_u, pos.z,pos.x) + if y then + if y ~= my then + meta:set_string("y", y) + end + else + y = my or 100 + end + pos.y = y - 0.3 + + player_from_nether(player, pos) + else + set_portal(known_portals_u, pos.z,pos.x, pos.y) + + local my = tonumber(meta:get_string("y")) + local y = get_portal(known_portals_d, pos.z,pos.x) + if y then + if y ~= my then + meta:set_string("y", y) + end + else + y = my or portal_target+math.random(4) + end + pos.y = y - 0.3 + + player_to_nether(player, pos) + end + minetest.sound_play("nether_teleporter", {pos=pos}) + return true +end diff --git a/nether/nether/weird_mapgen_noise.lua b/nether/nether/weird_mapgen_noise.lua new file mode 100644 index 00000000..8fe436db --- /dev/null +++ b/nether/nether/weird_mapgen_noise.lua @@ -0,0 +1,90 @@ +--V2 +local function get_random(a, b, seed) + return PseudoRandom(math.abs(a+b*5)+seed) +end + +local r_chs = {} + +local function nether_weird_noise(minp, fct, s, seed, range, scale) + if not r_chs[s] then + r_chs[s] = math.floor(s/3+0.5) + end + scale = scale or 15 + local r_ch = r_chs[s] + local maxp = vector.add(minp, scale) + + local tab,n = {},1 + local sm = range or (s+r_ch)*2 + for z = -sm, scale+sm do + local pz = z+minp.z + if pz%s == 0 then + for x = -sm, scale+sm do + local px = x+minp.x + if px%s == 0 then + local pr = get_random(px, pz, seed) + tab[n] = {x=px+pr:next(-r_ch, r_ch), y=0, z=pz+pr:next(-r_ch, r_ch)} + n = n+1 + end + end + end + end + + local tab2,n = {},1 + for z = minp.z, maxp.z do + for x = minp.x, maxp.x do + local h = sm + for _,i in ipairs(tab) do + h = math.min(h, fct(x, i.x, z, i.z)) + end + tab2[n] = {x=x, y=maxp.y-h, z=z} + n = n+1 + end + end + return tab2 +end + +--[[ +local function dif(z1, z2) + return math.abs(z1-z2) +end + +local function pymg(x1, x2, z1, z2) + return math.max(dif(x1, x2), dif(z1, z2)) +end + +local function romg(x1, x2, z1, z2) + return math.hypot(dif(x1, x2), dif(z1, z2)) +end + +local function py2mg(x1, x2, z1, z2) + return dif(x1, x2) + dif(z1, z2) +end + +minetest.register_node("ac:wmg", { + description = "wmg", + tiles = {"ac_block.png"}, + groups = {snappy=1,bendy=2,cracky=1}, + sounds = default.node_sound_stone_defaults(), + on_construct = function(pos) + local minp = vector.chunkcorner(pos) + for _,p in ipairs(weird_noise(minp, pymg, 20, 8, 4)) do + local p2 = {x=p.x, y=p.y+1, z=p.z} + if p.y <= minp.y+7 then + local p2 = {x=p.x, y=minp.y+6, z=p.z} + local p3 = {x=p.x, y=p2.y+1, z=p.z} + if minetest.get_node(p2).name ~= "default:desert_stone" then + minetest.set_node(p2, {name="default:desert_stone"}) + end + if minetest.get_node(p3).name ~= "default:desert_sand" then + minetest.set_node(p3, {name="default:desert_sand"}) + end + else + if minetest.get_node(p).name ~= "default:desert_stone" then + minetest.set_node(p, {name="default:desert_stone"}) + end + end + end + end, +})]] + +return nether_weird_noise