diff --git a/basic_machines/waterremover.lua b/basic_machines/waterremover.lua new file mode 100644 index 0000000..84be53e --- /dev/null +++ b/basic_machines/waterremover.lua @@ -0,0 +1,351 @@ +--[[ + + TechAge + ======= + + Copyright (C) 2019-2025 Joachim Stolberg + + AGPL v3 + See LICENSE.txt for more information + + Water Remover + + The Water Remover removes water from an area of ​​up to 21 x 21 x 80 m. + It is mainly used to drain caves. The water remover is placed at the highest + point of the cave and removes the water from the cave to the lowest point. + It digs one water block every two seconds. + +]]-- + +-- for lazy programmers +local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end +local S2P = minetest.string_to_pos +local M = minetest.get_meta +local NDEF = function(pos) return minetest.registered_nodes[techage.get_node_lvm(pos).name] or {} end +-- Consumer Related Data +local CRD = function(pos) return (minetest.registered_nodes[techage.get_node_lvm(pos).name] or {}).consumer end + +local S = techage.S +local Pipe = techage.LiquidPipe +local liquid = networks.liquid +local menu = techage.menu + +local TITLE = S("Water Remover") +local CYCLE_TIME = 2 +local STANDBY_TICKS = 4 +local COUNTDOWN_TICKS = 4 +local Side2Facedir = {F=0, R=1, B=2, L=3, D=4, U=5} + +local MENU = { + { + type = "dropdown", + choices = "9x9,11x11,13x13,15x15,17x17,19x19,21x21", + name = "area_size", + label = S("Area size"), + tooltip = S("Area where the water is to be removed"), + default = "9", + values = {9,11,13,15,17,19,21}, + }, + { + type = "numbers", + name = "area_depth", + label = S("Area depth"), + tooltip = S("Depth of the area where the water is to be removed (1-80)"), + default = "10", + check = function(value, player_name) return tonumber(value) >= 1 and tonumber(value) <= 80 end, + }, + { + type = "output", + name = "curr_depth", + label = S("Current depth"), + tooltip = S("Current working depth of the water remover"), + }, +} + +local WaterNodes = { + "default:water_source", + "default:river_water_source", + -- Add more water nodes here +} + +core.register_node("techage:air", { + description = "Techage Air", + inventory_image = "air.png", + wield_image = "air.png", + drawtype = "airlike", + paramtype = "light", + sunlight_propagates = true, + walkable = false, + pointable = false, + diggable = false, + buildable_to = true, + floodable = false, -- This is important! + air_equivalent = true, + drop = "", + groups = {not_in_creative_inventory=1}, +}) + +local function formspec(self, pos, nvm) + return "size[8,4.4]" .. + "box[0,-0.1;7.8,0.5;#c6e8ff]" .. + "label[3.0,-0.1;" .. minetest.colorize( "#000000", TITLE) .. "]" .. + "image[6.4,0.8;1,1;" .. techage.get_power_image(pos, nvm) .. "]" .. + "image_button[6.4,2.2;1,1;".. self:get_state_button_image(nvm) .. ";state_button;]" .. + "tooltip[6.4,2.2;1,1;" .. self:get_state_tooltip(nvm) .. "]" .. + menu.generate_formspec_container(pos, NDEF(pos), MENU, 0.0, 5.8) +end + +local function play_sound(pos) + minetest.sound_play("techage_scoopwater", { + pos = pos, + gain = 1.5, + max_hear_distance = 15}) +end + +local function on_node_state_change(pos, old_state, new_state) + local mem = techage.get_mem(pos) + local owner = M(pos):get_string("owner") + mem.co = nil + techage.unmark_position(owner) +end + +local function get_pos(pos, facedir, side, steps) + facedir = (facedir + Side2Facedir[side]) % 4 + local dir = vector.multiply(minetest.facedir_to_dir(facedir), steps or 1) + return vector.add(pos, dir) +end + +local function get_dig_pos(pos, xoffs, zoffs) + return {x = pos.x + xoffs - 1, y = pos.y, z = pos.z + zoffs - 1} +end + +-- pos is the quarry pos +local function get_corner_positions(pos, facedir, hole_diameter) + local _pos = get_pos(pos, facedir, "L") + local pos1 = get_pos(_pos, facedir, "F", math.floor((hole_diameter - 1) / 2)) + local pos2 = get_pos(_pos, facedir, "B", math.floor((hole_diameter - 1) / 2)) + pos2 = get_pos(pos2, facedir, "L", hole_diameter - 1) + if pos1.x > pos2.x then pos1.x, pos2.x = pos2.x, pos1.x end + if pos1.y > pos2.y then pos1.y, pos2.y = pos2.y, pos1.y end + if pos1.z > pos2.z then pos1.z, pos2.z = pos2.z, pos1.z end + return pos1, pos2 +end + +local function is_water(pos1, pos2) + return #minetest.find_nodes_in_area(pos1, pos2, WaterNodes) > 0 +end + +local function mark_area(pos1, pos2, owner) + pos1.y = pos1.y + 0.2 + techage.mark_cube(owner, pos1, pos2, TITLE, "#FF0000", 40) + pos1.y = pos1.y - 0.2 +end + +local function dig_water_node(mypos, dig_pos) + local outdir = M(mypos):get_int("outdir") + local node = techage.get_node_lvm(dig_pos) + if node.name == "default:water_source" then + minetest.swap_node(dig_pos, {name = "techage:air", param2 = 0}) + local leftover = liquid.put(mypos, Pipe, outdir, "techage:water", 1) + if leftover and leftover > 0 then + return "tank full" + end + return "ok" + end + return "no_water" +end + +local function drain_task(pos, crd, nvm) + nvm.area_depth = M(pos):get_int("area_depth") + nvm.area_size = M(pos):get_int("area_size") + local y_first = pos.y + local y_last = y_first - nvm.area_depth + 1 + local facedir = minetest.get_node(pos).param2 + local owner = M(pos):get_string("owner") + local cnt = 0 + + local pos1, pos2 = get_corner_positions(pos, facedir, nvm.area_size) + nvm.level = 1 + --print("drain_task", nvm.area_depth, nvm.area_size, y_first, y_last, M(pos):get_int("area_depth")) + for y_curr = y_first, y_last, -1 do + pos1.y = y_curr + pos2.y = y_curr + + -- Restarting the server can detach the coroutine data. + -- Therefore, read nvm again. + nvm = techage.get_nvm(pos) + nvm.level = y_first - y_curr + 1 + + if minetest.is_area_protected(pos1, pos2, owner, 5) then + crd.State:fault(pos, nvm, S("area is protected")) + return + end + + if is_water(pos1, pos2) then + mark_area(pos1, pos2, owner) + M(pos):set_string("curr_depth", nvm.level) + coroutine.yield() + + for zoffs = 1, nvm.area_size do + for xoffs = 1, nvm.area_size do + local qpos = get_dig_pos(pos1, xoffs, zoffs) + while true do + local res = dig_water_node(pos, qpos) + if res == "tank full" then + crd.State:blocked(pos, nvm, S("tank full")) + techage.unmark_position(owner) + coroutine.yield() + elseif res == "no_water" then + break + else + crd.State:keep_running(pos, nvm, COUNTDOWN_TICKS) + if cnt % 4 == 0 then + play_sound(pos) + end + cnt = cnt + 1 + coroutine.yield() + break + end + end + end + coroutine.yield() + end + techage.unmark_position(owner) + end + end + M(pos):set_string("curr_depth", nvm.level) + crd.State:stop(pos, nvm, S("finished")) +end + +local function keep_running(pos, elapsed) + local mem = techage.get_mem(pos) + if not mem.co then + mem.co = coroutine.create(drain_task) + end + + local nvm = techage.get_nvm(pos) + local crd = CRD(pos) + local _, err = coroutine.resume(mem.co, pos, crd, nvm) + if err then + minetest.log("error", "[" .. TITLE .. "] at pos " .. minetest.pos_to_string(pos) .. " " .. err) + end +end + +local function on_rightclick(pos, node, clicker) + local nvm = techage.get_nvm(pos) + techage.set_activeformspec(pos, clicker) + M(pos):set_string("formspec", formspec(CRD(pos).State, pos, nvm)) +end + +local function on_receive_fields(pos, formname, fields, player) + if minetest.is_protected(pos, player:get_player_name()) then + return + end + + local nvm = techage.get_nvm(pos) + if menu.eval_input(pos, MENU, fields) then + M(pos):set_string("formspec", formspec(CRD(pos).State, pos, nvm)) + else + CRD(pos).State:state_button_event(pos, nvm, fields) + end +end + +local function after_dig_node(pos, oldnode, oldmetadata, digger) + Pipe:after_dig_node(pos) + techage.remove_node(pos, oldnode, oldmetadata) + techage.del_mem(pos) +end + +local tiles = {} +-- '#' will be replaced by the stage number +tiles.pas = { + -- up, down, right, left, back, front + "techage_filling_ta#.png^techage_frame_ta#_top.png", + "techage_filling_ta#.png^techage_frame_ta#.png", + "techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_hole_pipe.png", + "techage_filling_ta#.png^techage_frame_ta#.png^techage_quarry_left.png", + "techage_filling_ta#.png^techage_appl_liquidsampler.png^techage_frame_ta#.png", + "techage_filling_ta#.png^techage_appl_liquidsampler.png^techage_frame_ta#.png", +} +tiles.act = { + -- up, down, right, left, back, front + "techage_filling_ta#.png^techage_frame_ta#_top.png", + "techage_filling_ta#.png^techage_frame_ta#.png", + "techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_hole_pipe.png", + { + name = "techage_frame14_ta#.png^techage_quarry_left14.png", + backface_culling = false, + animation = { + type = "vertical_frames", + aspect_w = 32, + aspect_h = 32, + length = 2.0, + }, + }, + "techage_filling_ta#.png^techage_appl_liquidsampler.png^techage_frame_ta#.png", + "techage_filling_ta#.png^techage_appl_liquidsampler.png^techage_frame_ta#.png", +} + +local tubing = { + on_recv_message = function(pos, src, topic, payload) + if topic == "depth" then + local nvm = techage.get_nvm(pos) + return nvm.level or 0 + else + return CRD(pos).State:on_receive_message(pos, topic, payload) + end + end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + return CRD(pos).State:on_beduino_receive_cmnd(pos, topic, payload) + end, + on_beduino_request_data = function(pos, src, topic, payload) + if topic == 153 then -- Current Depth + local nvm = techage.get_nvm(pos) + return 0, {nvm.level or 0} + else + return CRD(pos).State:on_beduino_request_data(pos, topic, payload) + end + end, + on_node_load = function(pos) + CRD(pos).State:on_node_load(pos) + end, +} + +local _, _, node_name_ta4 = + techage.register_consumer("waterremover", TITLE, tiles, { + drawtype = "normal", + cycle_time = CYCLE_TIME, + standby_ticks = STANDBY_TICKS, + formspec = formspec, + tubing = tubing, + on_state_change = on_node_state_change, + after_place_node = function(pos, placer) + M(pos):set_string("owner", placer:get_player_name()) + M(pos):set_int("outdir", networks.side_to_outdir(pos, "R")) + M(pos):set_int("area_depth", 10) + M(pos):set_int("area_size", 9) + Pipe:after_place_node(pos) + end, + node_timer = keep_running, + on_receive_fields = on_receive_fields, + on_rightclick = on_rightclick, + after_dig_node = after_dig_node, + groups = {choppy=2, cracky=2, crumbly=2}, + sounds = default.node_sound_wood_defaults(), + num_items = {0,0,0,1}, + power_consumption = {0,0,0,10}, + } +) + +liquid.register_nodes({ + "techage:ta4_waterremover_pas", "techage:ta4_waterremover_act", +}, Pipe, "pump", {"R"}, {}) + +minetest.register_craft({ + output = node_name_ta4, + recipe = { + {"", "default:mese_crystal", ""}, + {"", "techage:ta3_liquidsampler_pas", ""}, + {"", "techage:ta4_wlanchip", ""}, + }, +}) diff --git a/basis/fly_lib.lua b/basis/fly_lib.lua index ed1840b..e24dfc1 100644 --- a/basis/fly_lib.lua +++ b/basis/fly_lib.lua @@ -571,6 +571,20 @@ local function is_simple_node(pos) end end +local function is_air(pos) + local node = techage.get_node_lvm(pos) + return node.name == "air" +end + +local function hidden_node(pos) + local meta = M(pos) + if meta:contains("ta_move_block") then + local node = minetest.deserialize(meta:get_string("ta_move_block")) + meta:set_string("ta_move_block", "") + return node + end +end + -- Move node from 'pos1' to the destination, calculated by means of 'lmove' -- * pos and meta are controller block related -- * lmove is the movement as a list of `moves` @@ -640,7 +654,15 @@ local function multi_move_nodes(pos, meta, nvm, lmove, max_speed, height, move2t if is_simple_node(pos1) and is_valid_dest(pos2) then if move_node(pos, meta, pos1, lmove, max_speed, height) == false then meta:set_string("status", S("No valid node at the start position")) - return false + else + running = true + end + elseif is_air(pos1) then + -- Try to recover the node + local node = hidden_node(pos2) + if node then + minetest.set_node(pos1, node) + running = move_node(pos, meta, pos1, lmove, max_speed, height) end else if not is_simple_node(pos1) then @@ -650,7 +672,6 @@ local function multi_move_nodes(pos, meta, nvm, lmove, max_speed, height, move2t meta:set_string("status", S("No valid destination position")) minetest.chat_send_player(owner, " [techage] " .. S("No valid destination position") .. " at " .. P2S(pos2)) end - return false end else if minetest.is_protected(pos1, owner) then @@ -660,7 +681,6 @@ local function multi_move_nodes(pos, meta, nvm, lmove, max_speed, height, move2t meta:set_string("status", S("Destination position is protected")) minetest.chat_send_player(owner, " [techage] " .. S("Destination position is protected") .. " at " .. P2S(pos2)) end - return false end running = true end diff --git a/basis/submenu.lua b/basis/submenu.lua index 46ce5da..8b30afc 100644 --- a/basis/submenu.lua +++ b/basis/submenu.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019-2022 Joachim Stolberg + Copyright (C) 2019-2025 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -38,9 +38,15 @@ end -- generate the formspec string to be placed into a container frame -local function generate_formspec_substring(pos, meta, form_def, player_name) +local function generate_formspec_substring(pos, meta, form_def, player_name, width, no_note) local tbl = {} local player_inv_needed = false + width = width or "10" + local xpos1 = tostring(tonumber(width) / 2 - 0.25) + local xpos2 = tostring(tonumber(width) / 2) + local xpos3 = tostring(tonumber(width) / 2 + 0.3) + local xpos4 = tostring(tonumber(width) / 2 + 0.5) + local xsize = tostring(tonumber(width) / 2) if meta and form_def then local nvm = techage.get_nvm(pos) @@ -56,9 +62,9 @@ local function generate_formspec_substring(pos, meta, form_def, player_name) val = meta:get_int(elem.name) end if nvm.running or techage.is_running(nvm) then - tbl[#tbl+1] = "label[4.75," .. offs .. ";" .. val .. "]" + tbl[#tbl+1] = "label[" .. xpos1 .. "," .. offs .. ";" .. val .. "]" else - tbl[#tbl+1] = "field[5," .. (offs+0.2) .. ";5.3,1;" .. elem.name .. ";;" .. val .. "]" + tbl[#tbl+1] = "field[" .. xpos2 .. "," .. (offs+0.2) .. ";" .. xpos3 .. ",1;" .. elem.name .. ";;" .. val .. "]" end elseif elem.type == "numbers" then local val = elem.default @@ -66,9 +72,9 @@ local function generate_formspec_substring(pos, meta, form_def, player_name) val = meta:get_string(elem.name) end if nvm.running or techage.is_running(nvm) then - tbl[#tbl+1] = "label[4.75," .. offs .. ";" .. val .. "]" + tbl[#tbl+1] = "label[" .. xpos1 .. "," .. offs .. ";" .. val .. "]" else - tbl[#tbl+1] = "field[5," .. (offs+0.2) .. ";5.3,1;" .. elem.name .. ";;" .. val .. "]" + tbl[#tbl+1] = "field[" .. xpos2 .. "," .. (offs+0.2) .. ";" .. xpos3 .. ",1;" .. elem.name .. ";;" .. val .. "]" end elseif elem.type == "float" then local val = elem.default @@ -76,9 +82,9 @@ local function generate_formspec_substring(pos, meta, form_def, player_name) val = tonumber(meta:get_string(elem.name)) or 0 end if nvm.running or techage.is_running(nvm) then - tbl[#tbl+1] = "label[4.75," .. offs .. ";" .. val .. "]" + tbl[#tbl+1] = "label[" .. xpos1 .. "," .. offs .. ";" .. val .. "]" else - tbl[#tbl+1] = "field[5," .. (offs+0.2) .. ";5.3,1;" .. elem.name .. ";;" .. val .. "]" + tbl[#tbl+1] = "field[" .. xpos2 .. "," .. (offs+0.2) .. ";" .. xpos3 .. ",1;" .. elem.name .. ";;" .. val .. "]" end elseif elem.type == "ascii" then local val = elem.default @@ -86,25 +92,30 @@ local function generate_formspec_substring(pos, meta, form_def, player_name) val = meta:get_string(elem.name) end if nvm.running or techage.is_running(nvm) then - tbl[#tbl+1] = "label[4.75," .. offs .. ";" .. minetest.formspec_escape(val) .. "]" + tbl[#tbl+1] = "label[" .. xpos1 .. "," .. offs .. ";" .. minetest.formspec_escape(val) .. "]" else - tbl[#tbl+1] = "field[5," .. (offs+0.2) .. ";5.3,1;" .. elem.name .. ";;" .. minetest.formspec_escape(val) .. "]" + tbl[#tbl+1] = "field[" .. xpos2 .. "," .. (offs+0.2) .. ";" .. xpos3 .. ",1;" .. elem.name .. ";;" .. minetest.formspec_escape(val) .. "]" end elseif elem.type == "const" then - tbl[#tbl+1] = "label[4.75," .. offs .. ";" .. elem.value .. "]" + tbl[#tbl+1] = "label[" .. xpos1 .. "," .. offs .. ";" .. elem.value .. "]" elseif elem.type == "output" then local val = nvm[elem.name] or meta:get_string(elem.name) or "" if tonumber(val) then val = techage.round(val) end - tbl[#tbl+1] = "label[4.75," .. offs .. ";" .. val .. "]" + tbl[#tbl+1] = "label[" .. xpos1 .. "," .. offs .. ";" .. val .. "]" elseif elem.type == "dropdown" then if nvm.running or techage.is_running(nvm) then local val = elem.default or "" if meta:contains(elem.name) then val = meta:get_string(elem.name) or "" + if elem.values then + local idx = index(elem.values, val) or 1 + local l = elem.choices:split(",") + val = l[idx] + end end - tbl[#tbl+1] = "label[4.75," .. offs .. ";" .. val .. "]" + tbl[#tbl+1] = "label[" .. xpos1 .. "," .. offs .. ";" .. val .. "]" elseif elem.on_dropdown then -- block provides a specific list of choice elements local val = elem.default if meta:contains(elem.name) then @@ -113,7 +124,7 @@ local function generate_formspec_substring(pos, meta, form_def, player_name) local choices = elem.on_dropdown(pos) local l = choices:split(",") local idx = index(l, val) or 1 - tbl[#tbl+1] = "dropdown[4.72," .. (offs) .. ";5.5,1.4;" .. elem.name .. ";" .. choices .. ";" .. idx .. "]" + tbl[#tbl+1] = "dropdown[" .. xpos1 .. "," .. (offs) .. ";" .. xpos4 .. ",1.4;" .. elem.name .. ";" .. choices .. ";" .. idx .. "]" else local val = elem.default if meta:contains(elem.name) then @@ -126,19 +137,19 @@ local function generate_formspec_substring(pos, meta, form_def, player_name) local l = elem.choices:split(",") idx = index(l, val) or 1 end - tbl[#tbl+1] = "dropdown[4.72," .. (offs) .. ";5.5,1.4;" .. elem.name .. ";" .. elem.choices .. ";" .. idx .. "]" + tbl[#tbl+1] = "dropdown[" .. xpos1 .. "," .. (offs) .. ";" .. xpos4 .. ",1.4;" .. elem.name .. ";" .. elem.choices .. ";" .. idx .. "]" end elseif elem.type == "items" then -- inventory if elem.size then - tbl[#tbl+1] = "list[detached:" .. minetest.formspec_escape(player_name) .. "_techage_wrench_menu;cfg;4.75," .. offs .. ";" .. elem.size .. ",1;]" + tbl[#tbl+1] = "list[detached:" .. minetest.formspec_escape(player_name) .. "_techage_wrench_menu;cfg;" .. xpos1 .. "," .. offs .. ";" .. elem.size .. ",1;]" else - tbl[#tbl+1] = "list[detached:" .. minetest.formspec_escape(player_name) .. "_techage_wrench_menu;cfg;4.75," .. offs .. ";" .. elem.width .. "," .. elem.height .. ";]" + tbl[#tbl+1] = "list[detached:" .. minetest.formspec_escape(player_name) .. "_techage_wrench_menu;cfg;" .. xpos1 .. "," .. offs .. ";" .. elem.width .. "," .. elem.height .. ";]" end player_inv_needed = true end end - if nvm.running or techage.is_running(nvm) then - local offs = #form_def * 0.9 - 0.2 + if not no_note and (nvm.running or techage.is_running(nvm)) then + local offs = #form_def * 0.9 - 0.3 tbl[#tbl+1] = "label[0," .. offs .. ";" .. S("Note: You can't change any values while the block is running!") .. "]" end end @@ -304,6 +315,45 @@ function techage.menu.generate_formspec(pos, ndef, form_def, player_name) return "" end +function techage.menu.generate_formspec_container(pos, ndef, form_def, ypos, width) + local meta = minetest.get_meta(pos) + local number = techage.get_node_number(pos) or "-" + local mem = techage.get_mem(pos) + mem.star = ((mem.star or 0) + 1) % 2 + local star = mem.star == 1 and " *" or " " + local bttn_width = (width - 0.3) / 3 + if meta and number and ndef and form_def then + local _, text = generate_formspec_substring(pos, meta, form_def, "", width, true) + local yoffs = math.min(#form_def, 8) * 0.9 + 0.7 + local buttons = "button[0.1," .. yoffs .. ";" .. bttn_width .. ",1;refresh;" .. S("Refresh") .. star .. "]" .. + "button_exit[" .. (bttn_width + 0.2) .. "," .. yoffs .. ";" .. bttn_width .. ",1;cancel;" .. S("Cancel") .. "]" .. + "button[" .. (2 * bttn_width + 0.3) .. "," .. yoffs .. ";" .. bttn_width .. ",1;save;" .. S("Save") .. "]" + + + if #form_def > 8 then + local size = (#form_def * 10) - 60 + return "container[0," .. ypos .. "]" .. + "box[0,0;" .. width .. "," .. (yoffs + 0.8) .. ";#395c74]".. + "scrollbaroptions[max=" .. size .. "]" .. + "scrollbar[9.4,0.6;0.4,7.7;vertical;wrenchmenu;]" .. + "scroll_container[0,1;12,9;wrenchmenu;vertical;]" .. + text .. + "scroll_container_end[]" .. + buttons .. + "container_end[]" + else + return "container[0," .. ypos .. "]" .. + "container[0,1]" .. + "box[-0.1,-0.3;" .. (width + 0.2) .. "," .. (yoffs + 0.3) .. ";#395c74]".. + text .. + "container_end[]" .. + buttons .. + "container_end[]" + end + end + return "" +end + function techage.menu.eval_input(pos, form_def, fields, player_name) if fields.save or fields.key_enter_field then local meta = minetest.get_meta(pos) diff --git a/doc/items.lua b/doc/items.lua index b63bf99..a315474 100644 --- a/doc/items.lua +++ b/doc/items.lua @@ -210,6 +210,7 @@ local items = { ta4_chargedetector = "techage:ta4_chargedetector_off", ta4_gaze_sensor = "techage:ta4_gaze_sensor_off", ta4_nodedetector = "techage:ta4_nodedetector_off", + ta4_waterremover = "techage:ta4_waterremover_pas", ---------------------------- techage_ta5 = "techage:ta5_fr_nucleus", ta5_flycontroller = "techage:ta5_flycontroller", diff --git a/doc/manual_ta4_DE.lua b/doc/manual_ta4_DE.lua index 91f58d5..e87f00c 100644 --- a/doc/manual_ta4_DE.lua +++ b/doc/manual_ta4_DE.lua @@ -89,6 +89,7 @@ return { "3,TA4 Kiessieb / Gravel Sieve", "3,TA4 Mühle / Grinder", "3,TA4 Steinbrecher / Quarry", + "3,TA4 Wasserentferner / Water Remover", "3,TA4 Elektronikfabrik / Electronic Fab", "3,TA4 Injektor / Injector", "3,TA4 Recycler", @@ -837,6 +838,20 @@ return { "\n".. "\n".. "\n", + "Der Wasserentferner entfernt Wasser aus einer Fläche von bis zu 21 x 21 x 80 m.\n".. + "Der Hauptzweck ist die Entwässerung von Höhlen. Er kann aber auch verwendet werden\\, um ein Loch ins Meer zu „bohren“.\n".. + "\n".. + "Der Wasserentferner benötigt Strom und eine Rohrverbindung zu einem Flüssigkeitstank.\n".. + "\n".. + "Der Wasserentferner wird am höchsten Punkt der Höhle platziert und entfernt das Wasser\n".. + "aus der Höhle zum tiefsten Punkt. Der Wasserentferner gräbt alle zwei Sekunden einen Wasserblock. \n".. + "Das Gerät benötigt 10 Ku Strom.\n".. + "\n".. + "Technisch gesehen ersetzt der Wasserentferner die Wasserblöcke durch einen speziellen Luftblock\\,\n".. + "der nicht sichtbar und nicht begehbar ist\\, aber verhindert\\, dass das Wasser zurückfließt.\n".. + "\n".. + "\n".. + "\n", "Die Funktion entspricht der von TA2\\, nur werden hier verschiedene Chips produziert.\n".. "Die Verarbeitungsleistung beträgt ein Chip alle 6 s. Der Block benötigt hierfür 12 ku Strom.\n".. "\n".. @@ -951,6 +966,7 @@ return { "ta4_gravelsieve", "ta4_grinder", "ta4_quarry", + "ta4_waterremover", "ta4_electronicfab", "ta4_injector", "ta4_recycler", @@ -1048,5 +1064,6 @@ return { "", "", "", + "", } } \ No newline at end of file diff --git a/doc/manual_ta4_EN.lua b/doc/manual_ta4_EN.lua index ea1c55e..fb58c28 100644 --- a/doc/manual_ta4_EN.lua +++ b/doc/manual_ta4_EN.lua @@ -89,6 +89,7 @@ return { "3,TA4 Gravel Sieve", "3,TA4 Grinder", "3,TA4 Quarry", + "3,TA4 Water Remover", "3,TA4 Electronic Fab", "3,TA4 Injector", "3,TA4 Recycler", @@ -838,6 +839,19 @@ return { "\n".. "\n".. "\n", + "The Water Remover removes water from an area of up to 21 x 21 x 80 m. The main\n".. + "purpose is to drain caves. But it can also be used to \"drill\" a hole into the sea.\n".. + "\n".. + "The Water Remover needs electricity and a pipe connection to a liquid tank. The\n".. + "Water Remover is placed at the highest point of the cave and removes the water\n".. + "from the cave to the lowest point. The Water Remover digs one water block every\n".. + "two seconds. The device requires 10 ku of electricity.\n".. + "\n".. + "Technically\\, the Water Remover replaces the water blocks with a special air block\n".. + "that is not visible and not walkable but prevents the water from flowing back.\n".. + "\n".. + "\n".. + "\n", "The function corresponds to that of TA2\\, only different chips are produced here.\n".. "The processing power is one chip every 6 s. The block requires 12 ku of electricity for this.\n".. "\n".. @@ -953,6 +967,7 @@ return { "ta4_gravelsieve", "ta4_grinder", "ta4_quarry", + "ta4_waterremover", "ta4_electronicfab", "ta4_injector", "ta4_recycler", @@ -1050,5 +1065,6 @@ return { "", "", "", + "", } } \ No newline at end of file diff --git a/init.lua b/init.lua index c2a766e..bb59229 100644 --- a/init.lua +++ b/init.lua @@ -199,6 +199,7 @@ dofile(MP.."/basic_machines/recycler.lua") dofile(MP.."/basic_machines/concentrator.lua") dofile(MP.."/basic_machines/recipeblock.lua") dofile(MP.."/basic_machines/ta5_chest.lua") +dofile(MP.."/basic_machines/waterremover.lua") -- Liquids II dofile(MP.."/liquids/tank.lua") diff --git a/locale/techage.de.tr b/locale/techage.de.tr index 269c379..28e6c18 100644 --- a/locale/techage.de.tr +++ b/locale/techage.de.tr @@ -1172,9 +1172,13 @@ Hole size=Lochgröße Quarry=Steinbrecher Start level=Startebene Start level @= 0@nmeans the same level@nas the quarry is placed=Startebene @= 0@nbedeutet gleiche Ebene@nwie der Steinbrecher +inventory full=Inventar ist voll + +### quarry.lua ### +### waterremover.lua ### + area is protected=Bereich ist geschützt finished=fertig -inventory full=Inventar ist voll ### reboiler.lua ### @@ -1582,6 +1586,17 @@ TA1 Watermill=TA1 Wasssermühle TA4 Water Pump=Wasserpumpe Water Pump=Wasserpumpe +### waterremover.lua ### + +Area depth=Flächentiefe +Area size=Flächengröße +Area where the water is to be removed=Fläche, aus der das Wasser entfernt werden soll +Current depth=Aktuelle Tiefe +Current working depth of the water remover=Aktuelle Arbeitstiefe des Wasserentferners +Depth of the area where the water is to be removed (1-80)=Tiefe der Fläche, aus der das Wasser entfernt werden soll (1-80) +Water Remover=Wasserentferner +tank full=Tank voll + ### windturbine_lib.lua ### Here is not enough water (41x41 m)!=Hier ist nicht genug Wasser (41x41 m)! diff --git a/locale/techage.fr.tr b/locale/techage.fr.tr index b30985e..a4a4883 100644 --- a/locale/techage.fr.tr +++ b/locale/techage.fr.tr @@ -1172,9 +1172,13 @@ Hole size= Quarry= Start level= Start level @= 0@nmeans the same level@nas the quarry is placed= +inventory full= + +### quarry.lua ### +### waterremover.lua ### + area is protected= finished= -inventory full= ### reboiler.lua ### @@ -1582,6 +1586,17 @@ TA1 Watermill= TA4 Water Pump=TA4 Pompe à eau Water Pump=Pompe à eau +### waterremover.lua ### + +Area depth= +Area size= +Area where the water is to be removed= +Current depth= +Current working depth of the water remover= +Depth of the area where the water is to be removed (1-80)= +Water Remover= +tank full= + ### windturbine_lib.lua ### Here is not enough water (41x41 m)!=Ici, il n'y a pas assez d'eau (41x41 m)! diff --git a/locale/techage.ru.tr b/locale/techage.ru.tr index 0cfb05a..5eae3d5 100644 --- a/locale/techage.ru.tr +++ b/locale/techage.ru.tr @@ -1172,9 +1172,13 @@ Hole size=Глубина ямы Quarry=Карьер Start level=Начальный высота Start level @= 0@nmeans the same level@nas the quarry is placed=Начальная высота @= 0@nозначает ту же высоту, что имеется у карьера +inventory full=инвентарь заполнен + +### quarry.lua ### +### waterremover.lua ### + area is protected=зона защищена finished=готово -inventory full=инвентарь заполнен ### reboiler.lua ### @@ -1582,6 +1586,17 @@ TA1 Watermill=TA1 Водяное колесо TA4 Water Pump=TA4 Водяной насос Water Pump=Водяной насос +### waterremover.lua ### + +Area depth= +Area size= +Area where the water is to be removed= +Current depth= +Current working depth of the water remover= +Depth of the area where the water is to be removed (1-80)= +Water Remover= +tank full= + ### windturbine_lib.lua ### Here is not enough water (41x41 m)!=Здесь недостаточно воды (41x41 м)! diff --git a/locale/template.txt b/locale/template.txt index 4ee8999..3847e97 100644 --- a/locale/template.txt +++ b/locale/template.txt @@ -1172,9 +1172,13 @@ Hole size= Quarry= Start level= Start level @= 0@nmeans the same level@nas the quarry is placed= +inventory full= + +### quarry.lua ### +### waterremover.lua ### + area is protected= finished= -inventory full= ### reboiler.lua ### @@ -1582,6 +1586,17 @@ TA1 Watermill= TA4 Water Pump= Water Pump= +### waterremover.lua ### + +Area depth= +Area size= +Area where the water is to be removed= +Current depth= +Current working depth of the water remover= +Depth of the area where the water is to be removed (1-80)= +Water Remover= +tank full= + ### windturbine_lib.lua ### Here is not enough water (41x41 m)!= diff --git a/logic/terminal.lua b/logic/terminal.lua index 1f7ed88..fd69683 100644 --- a/logic/terminal.lua +++ b/logic/terminal.lua @@ -49,6 +49,7 @@ are possible.]] local SYNTAX_ERR = S("Syntax error, try help") local WRENCH_MENU = { + [0] = {"techage:terminal2"}, --valid_nodes { type = "dropdown", choices = "all players,me", @@ -76,7 +77,7 @@ local function get_string(meta, num, default) return s end -local function formspec2(meta) +local function formspec2(pos, meta) local output = meta:get_string("output") local command = meta:get_string("command") output = minetest.formspec_escape(output) @@ -90,9 +91,13 @@ local function formspec2(meta) local bttn_text7 = get_string(meta, 7, "User7") local bttn_text8 = get_string(meta, 8, "User8") local bttn_text9 = get_string(meta, 9, "User9") + local wrench_image = "" + if minetest.get_node(pos).name == "techage:terminal2" then + wrench_image = techage.wrench_image(9.6, -0.2) + end return "size[10,8.5]".. --"style_type[table,field;font=mono]".. - techage.wrench_image(9.6, -0.2) .. + wrench_image .. "button[0,-0.2;3.3,1;bttn1;"..bttn_text1.."]button[3.3,-0.2;3.3,1;bttn2;"..bttn_text2.."]button[6.6,-0.2;3.2,1;bttn3;"..bttn_text3.."]".. "button[0,0.6;3.3,1;bttn4;"..bttn_text4.."]button[3.3,0.6;3.3,1;bttn5;"..bttn_text5.."]button[6.6,0.6;3.4,1;bttn6;"..bttn_text6.."]".. "button[0,1.4;3.3,1;bttn7;"..bttn_text7.."]button[3.3,1.4;3.3,1;bttn8;"..bttn_text8.."]button[6.6,1.4;3.4,1;bttn9;"..bttn_text9.."]".. @@ -107,14 +112,14 @@ local function output(pos, text) text = meta:get_string("output") .. "\n" .. (text or "") text = text:sub(-1000,-1) meta:set_string("output", text) - meta:set_string("formspec", formspec2(meta)) + meta:set_string("formspec", formspec2(pos, meta)) end local function append(pos, text) local meta = minetest.get_meta(pos) text = meta:get_string("output") .. (text or "") meta:set_string("output", text) - meta:set_string("formspec", formspec2(meta)) + meta:set_string("formspec", formspec2(pos, meta)) end local function get_line_text(pos, num) @@ -188,7 +193,7 @@ local function command(pos, command, player, is_ta4) if cmnd == "clear" then meta:set_string("output", "") - meta:set_string("formspec", formspec2(meta)) + meta:set_string("formspec", formspec2(pos, meta)) elseif cmnd == "" then output(pos, "$") elseif cmnd == "help" then @@ -255,7 +260,7 @@ local function command(pos, command, player, is_ta4) if bttn_num and label and cmnd then meta:set_string("bttn_text"..bttn_num, label) meta:set_string("bttn_cmnd"..bttn_num, cmnd) - meta:set_string("formspec", formspec2(meta)) + meta:set_string("formspec", formspec2(pos, meta)) return end @@ -303,7 +308,7 @@ local function register_terminal(name, description, tiles, node_box, selection_b local meta = minetest.get_meta(pos) meta:set_string("node_number", number) meta:set_string("command", S("commands like: help")) - meta:set_string("formspec", formspec2(meta)) + meta:set_string("formspec", formspec2(pos, meta)) if placer then meta:set_string("owner", placer:get_player_name()) end @@ -320,22 +325,22 @@ local function register_terminal(name, description, tiles, node_box, selection_b if evt.type == "DCL" then local s = get_line_text(pos, evt.row) meta:set_string("command", s) - meta:set_string("formspec", formspec2(meta)) + meta:set_string("formspec", formspec2(pos, meta)) return elseif (fields.ok or fields.key_enter_field) and fields.cmnd then local is_ta4 = string.find(description, "TA4") command(pos, fields.cmnd, player:get_player_name(), is_ta4) techage.historybuffer_add(pos, fields.cmnd) meta:set_string("command", "") - meta:set_string("formspec", formspec2(meta)) + meta:set_string("formspec", formspec2(pos, meta)) return elseif fields.key_up then meta:set_string("command", techage.historybuffer_priv(pos)) - meta:set_string("formspec", formspec2(meta)) + meta:set_string("formspec", formspec2(pos, meta)) return elseif fields.key_down then meta:set_string("command", techage.historybuffer_next(pos)) - meta:set_string("formspec", formspec2(meta)) + meta:set_string("formspec", formspec2(pos, meta)) return end end @@ -354,7 +359,7 @@ local function register_terminal(name, description, tiles, node_box, selection_b end, ta_after_formspec = function(pos, fields, playername) - if fields.save then + if fields.save and minetest.get_node(pos).name == "techage:terminal2" then if M(pos):get_string("opmode") == "basic" then if minetest.global_exists("nanobasic") then local node = techage.get_node_lvm(pos) diff --git a/manuals/manual_ta4_DE.md b/manuals/manual_ta4_DE.md index 6212744..a06cde0 100644 --- a/manuals/manual_ta4_DE.md +++ b/manuals/manual_ta4_DE.md @@ -994,6 +994,22 @@ Die maximale Tiefe beträgt 80 Meter. Der Steinbrecher benötigt 14 ku Strom. [ta4_quarry|image] +### TA4 Wasserentferner / Water Remover + +Der Wasserentferner entfernt Wasser aus einer Fläche von bis zu 21 x 21 x 80 m. +Der Hauptzweck ist die Entwässerung von Höhlen. Er kann aber auch verwendet werden, um ein Loch ins Meer zu „bohren“. + +Der Wasserentferner benötigt Strom und eine Rohrverbindung zu einem Flüssigkeitstank. + +Der Wasserentferner wird am höchsten Punkt der Höhle platziert und entfernt das Wasser +aus der Höhle zum tiefsten Punkt. Der Wasserentferner gräbt alle zwei Sekunden einen Wasserblock. +Das Gerät benötigt 10 Ku Strom. + +Technisch gesehen ersetzt der Wasserentferner die Wasserblöcke durch einen speziellen Luftblock, +der nicht sichtbar und nicht begehbar ist, aber verhindert, dass das Wasser zurückfließt. + +[ta4_waterremover|image] + ### TA4 Elektronikfabrik / Electronic Fab Die Funktion entspricht der von TA2, nur werden hier verschiedene Chips produziert. diff --git a/manuals/manual_ta4_EN.md b/manuals/manual_ta4_EN.md index 5791b73..cfee4c2 100644 --- a/manuals/manual_ta4_EN.md +++ b/manuals/manual_ta4_EN.md @@ -986,6 +986,21 @@ The maximum depth is 80 meters. The quarry requires 14 ku of electricity. [ta4_quarry|image] +### TA4 Water Remover + +The Water Remover removes water from an area of up to 21 x 21 x 80 m. The main +purpose is to drain caves. But it can also be used to "drill" a hole into the sea. + +The Water Remover needs electricity and a pipe connection to a liquid tank. The +Water Remover is placed at the highest point of the cave and removes the water +from the cave to the lowest point. The Water Remover digs one water block every +two seconds. The device requires 10 ku of electricity. + +Technically, the Water Remover replaces the water blocks with a special air block +that is not visible and not walkable but prevents the water from flowing back. + +[ta4_waterremover|image] + ### TA4 Electronic Fab The function corresponds to that of TA2, only different chips are produced here. diff --git a/manuals/nanobasic.md b/manuals/nanobasic.md index 58770e1..544d281 100644 --- a/manuals/nanobasic.md +++ b/manuals/nanobasic.md @@ -1055,6 +1055,7 @@ SLEEP(seconds) ``` The SLEEP function is used to pause program execution for a specified number of seconds. +If the number of seconds is 0, the program pauses one time slice (0.2 seconds). ### SPC @@ -1528,6 +1529,7 @@ corresponds to the error from previous chapter. | TA4 Pusher Counter | 150 | - | number | Read the number of pushed items for a TA4 Pusher in "flow limiter" mode | | TA4 Pump Counter | 151 | - | number | Read the number of pumped liquid units for a TA4 Pump in "flow limiter" mode | | Multi Button State | 152 | num | state | Read the button state (TA4 2x Button, TA4 4x Button)
`num` is the button number (1..4), `state`: 0 = "off", 1 = "on" | +| Water Remover Depth | 153 | - | depth | Current depth value of a remover (1..80) | ### CMD$ Commands with Response as String Value diff --git a/sounds/techage_scoopwater.ogg b/sounds/techage_scoopwater.ogg new file mode 100644 index 0000000..43113d9 Binary files /dev/null and b/sounds/techage_scoopwater.ogg differ