--[[ TechAge ======= Copyright (C) 2019-2020 Joachim Stolberg AGPL v3 See LICENSE.txt for more information TA3 Oil Explorer ]]-- -- for lazy programmers local M = minetest.get_meta local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end local S = techage.S local PROBABILITY = 100 local OIL_MIN = 4096 local OIL_MAX = 20000 local DEPTH_MIN = 16 local DEPTH_MAX = 25*16 local DEPTH_STEP = 16 local YPOS_MAX = -6*16 -- oil can't found below this level local OIL_BUBBLE_SIZE = 4096 local seed = tonumber(minetest.settings:get("techage_oil_exploration_seed")) or 1234 -- confidental! local InvalidGroundNodes = { ["air"] = true, } local ValidGroundNodes = { ["default:cobble"] = true, ["default:mossycobble"] = true, ["default:desert_cobble"] = true, } local function oil_amount(pos) if pos.y > YPOS_MAX then return 0 end local block_key = seed + math.floor((pos.z + 32768) / 16) * 4096 * 4096 + math.floor((pos.y + 32768) / 16) * 4096 + math.floor((pos.x + 32768) / 16) math.randomseed(block_key) math.random(); math.random(); math.random() local has_oil = math.random(1,PROBABILITY) == 1 if has_oil then local amount = math.random(OIL_MIN, OIL_MAX) return amount end -- Generate new randomseed after use math.randomseed(os.time()) return 0 end local function center(coord) return (math.floor(coord/16) * 16) + 8 end local function basis(coord) return (math.floor(coord/16) * 16) end -- determine the mapblock coordinates local function mapblock_coordinates(pos) local pos1 = {x = basis(pos.x), y = basis(pos.y), z = basis(pos.z)} local pos2 = {x = pos1.x + 15, y = pos1.y + 15, z = pos1.z + 15} return pos1, pos2 end local function calc_depth(pos, explore_pos) return pos.y - explore_pos.y + 1 end -- posC is the center position of the oil bubble -- idx is the vmdata index -- function returns the real position {x,y,z} local function calc_vmdata_pos(posC, idx) local rest, xoffs, yoffs, zoffs rest = idx - 1 xoffs = rest % 16 rest = math.floor(rest / 16) zoffs = rest % 16 rest = math.floor(rest / 16) yoffs = rest % 16 return {x = basis(posC.x) + xoffs, y = basis(posC.y) + yoffs, z = basis(posC.z) + zoffs} end local function calc_vmdata_index(xoffs, yoffs, zoffs) return (xoffs + (yoffs * 16) + (zoffs * 16 * 16)) + 1 end -- from/to are x/z-offsets (0..15) for one layer of oil within one mapblock local function gen_oil_slice(yoffs, from, to, vmdata, id) for xoffs = from, to do for zoffs = from, to do vmdata[calc_vmdata_index(xoffs, yoffs, zoffs)] = id end end end local function gen_oil_bubble(vmdata) local id = minetest.get_content_id("techage:oil_source") gen_oil_slice(1, 3, 12, vmdata, id) gen_oil_slice(2, 2, 13, vmdata, id) for offs = 3, 12 do gen_oil_slice(offs, 1, 14, vmdata, id) end gen_oil_slice(13, 2, 13, vmdata, id) gen_oil_slice(14, 3, 12, vmdata, id) end local function useable_stone_block(data) local valid = {} for _,id in ipairs(data) do if not valid[id] then local itemname = minetest.get_name_from_content_id(id) if not ValidGroundNodes[itemname] then local ndef = minetest.registered_nodes[itemname] if InvalidGroundNodes[itemname] or not ndef or ndef.is_ground_content == false then return false end end valid[id] = true end end return true end local function get_next_explore_pos(pos) local meta = M(pos) local ypos = meta:get_int("exploration_ypos") if ypos == 0 then ypos = math.min(YPOS_MAX, center(pos.y)) end local d = calc_depth(pos, {y = ypos}) if d + DEPTH_STEP < DEPTH_MAX then ypos = ypos - DEPTH_STEP local posC = {x = center(pos.x), y = center(ypos), z = center(pos.z)} local node = techage.get_node_lvm(posC) if node.name ~= "ignore" then meta:set_int("exploration_ypos", ypos) else -- load world and pause for one step minetest.emerge_area(posC, posC) end end return {x = center(pos.x), y = center(ypos), z = center(pos.z)} end local function get_oil_amount(pos) return M(pos):get_int("oil_amount") end local function set_oil_amount(pos, amount) minetest.set_node(pos, {name = "techage:oilstorage"}) M(pos):set_int("oil_amount", amount) M(pos):set_int("initial_oil_amount", amount) end local function status(pos, player_name, explore_pos, amount) local depth = calc_depth(pos, explore_pos) minetest.chat_send_player(player_name, "[TA Oil] "..P2S(explore_pos).." "..S("depth")..": "..depth..", "..S("Oil")..": "..amount.." ") end local function marker(player_name, pos) local posC = {x = center(pos.x), y = pos.y, z = center(pos.z)} local pos1 = {x = posC.x - 2, y = posC.y - 2, z = posC.z - 2} local pos2 = {x = posC.x + 2, y = posC.y + 7, z = posC.z + 2} techage.switch_region(player_name, pos1, pos2) end -- check if oil can be placed and if so, do it and return true local function generate_oil_bubble(posC, amount) local pos1, pos2 = mapblock_coordinates(posC) local vm = minetest.get_voxel_manip(pos1, pos2) local data = vm:get_data() if useable_stone_block(data) then gen_oil_bubble(data) vm:set_data(data) vm:write_to_map() vm:update_map() set_oil_amount(posC, amount) return true end return false end local function explore_area(pos, node, player_name) if M(pos):get_int("oil_amount") == 0 then -- nothing found so far? local posC, amount node.name = "techage:oilexplorer_on" minetest.swap_node(pos, node) minetest.get_node_timer(pos):start(2.2) minetest.sound_play("techage_explore", { pos = pos, max_hear_distance = 8}) for i = 1,4 do posC = get_next_explore_pos(pos) amount = oil_amount(posC) if amount > 0 then break end end if amount > 0 then if get_oil_amount(posC) == 0 then -- not explored so far? if generate_oil_bubble(posC, amount) then marker(player_name, pos) else amount = 0 end end M(pos):set_int("oil_amount", amount) end minetest.after(2, status, pos, player_name, posC, amount) else local explore_pos = {x = center(pos.x), y = M(pos):get_int("exploration_ypos"), z = center(pos.z)} status(pos, player_name, explore_pos, M(pos):get_int("oil_amount")) marker(player_name, pos) end end -- Used as storage for already explored blocks minetest.register_node("techage:oilstorage", { description = S("TA3 Oil Storage"), tiles = {"default_stone.png"}, groups = {not_in_creative_inventory=1}, diggable = false, drop = "", is_ground_content = false, }) minetest.register_node("techage:oilexplorer", { description = S("TA3 Oil Explorer"), tiles = { "techage_filling_ta3.png^techage_appl_oilexplorer_top.png^techage_frame_ta3_top.png", "techage_filling_ta3.png^techage_frame_ta3.png", "techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_oilexplorer.png", }, on_rightclick = function(pos, node, clicker, itemstack, pointed_thing) explore_area(pos, node, clicker:get_player_name()) end, after_dig_node = function(pos, oldnode, oldmetadata, digger) techage.unmark_region(digger:get_player_name()) local xpos = (math.floor(pos.x / 16) * 16) local ypos = (math.floor(pos.y / 16) * 16) local zpos = (math.floor(pos.z / 16) * 16) local pos1 = {x=xpos, y=ypos, z=zpos} local pos2 = {x=xpos+15, y=ypos+15, z=zpos+15} techage.mark_region(digger:get_player_name(), pos1, pos2) end, is_ground_content = false, groups = {snappy=2,cracky=2,oddly_breakable_by_hand=2}, sounds = default.node_sound_wood_defaults(), }) minetest.register_node("techage:oilexplorer_on", { description = S("TA3 Oil Explorer"), tiles = { { name = "techage_filling4_ta3.png^techage_appl_oilexplorer_top4.png^techage_frame4_ta3_top.png", backface_culling = false, animation = { type = "vertical_frames", aspect_w = 32, aspect_h = 32, length = 1.2, }, }, "techage_filling_ta3.png^techage_frame_ta3.png", "techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_oilexplorer.png", }, on_timer = function(pos,elapsed) local node = minetest.get_node(pos) node.name = "techage:oilexplorer" minetest.swap_node(pos, node) end, diggable = false, is_ground_content = false, paramtype = "light", light_source = 8, groups = {not_in_creative_inventory=1}, sounds = default.node_sound_wood_defaults(), }) minetest.register_craft({ output = "techage:oilexplorer", recipe = { {"group:wood", "default:diamond", "group:wood"}, {"techage:baborium_ingot", "basic_materials:gear_steel", "techage:usmium_nuggets"}, {"group:wood", "techage:vacuum_tube", "group:wood"}, }, }) techage.explore = {} function techage.explore.get_oil_info(pos) local amount = 0 local depth = DEPTH_MIN local posC = {x = center(pos.x), y = center(pos.y) - DEPTH_MIN, z = center(pos.z)} while amount == 0 and depth < DEPTH_MAX do amount = get_oil_amount(posC) depth = calc_depth(pos, posC) posC.y = posC.y - DEPTH_STEP end posC.y = posC.y + DEPTH_STEP return {depth = depth, amount = amount, storage_pos = posC} end function techage.explore.get_oil_amount(posC) local meta = M(posC) if meta:get_int("initial_oil_amount") == 0 then meta:set_int("initial_oil_amount", meta:get_int("oil_amount")) end return meta:get_int("oil_amount"), meta:get_int("initial_oil_amount") end function techage.explore.dec_oil_amount(posC) local oil_amount, oil_initial = techage.explore.get_oil_amount(posC) oil_amount = oil_amount - 1 M(posC):set_int("oil_amount", oil_amount) local idx = math.floor(oil_amount * OIL_BUBBLE_SIZE / oil_initial) idx = idx + 256 -- last level is stone, so add one level if idx <= (OIL_BUBBLE_SIZE - 256) then -- first level is stone, too local pos = calc_vmdata_pos(posC, idx) local node = techage.get_node_lvm(pos) if node.name == "techage:oil_source" then minetest.remove_node(pos) end end return oil_amount end