Add TA4 water remover device

This commit is contained in:
Joachim Stolberg 2025-01-05 20:41:28 +01:00
parent 46bb406cae
commit 5e3e7344fa
16 changed files with 592 additions and 38 deletions

View File

@ -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", ""},
},
})

View File

@ -571,6 +571,20 @@ local function is_simple_node(pos)
end end
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' -- Move node from 'pos1' to the destination, calculated by means of 'lmove'
-- * pos and meta are controller block related -- * pos and meta are controller block related
-- * lmove is the movement as a list of `moves` -- * 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 is_simple_node(pos1) and is_valid_dest(pos2) then
if move_node(pos, meta, pos1, lmove, max_speed, height) == false 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")) 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 end
else else
if not is_simple_node(pos1) then 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")) meta:set_string("status", S("No valid destination position"))
minetest.chat_send_player(owner, " [techage] " .. S("No valid destination position") .. " at " .. P2S(pos2)) minetest.chat_send_player(owner, " [techage] " .. S("No valid destination position") .. " at " .. P2S(pos2))
end end
return false
end end
else else
if minetest.is_protected(pos1, owner) then 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")) meta:set_string("status", S("Destination position is protected"))
minetest.chat_send_player(owner, " [techage] " .. S("Destination position is protected") .. " at " .. P2S(pos2)) minetest.chat_send_player(owner, " [techage] " .. S("Destination position is protected") .. " at " .. P2S(pos2))
end end
return false
end end
running = true running = true
end end

View File

@ -3,7 +3,7 @@
TechAge TechAge
======= =======
Copyright (C) 2019-2022 Joachim Stolberg Copyright (C) 2019-2025 Joachim Stolberg
AGPL v3 AGPL v3
See LICENSE.txt for more information See LICENSE.txt for more information
@ -38,9 +38,15 @@ end
-- generate the formspec string to be placed into a container frame -- 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 tbl = {}
local player_inv_needed = false 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 if meta and form_def then
local nvm = techage.get_nvm(pos) 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) val = meta:get_int(elem.name)
end end
if nvm.running or techage.is_running(nvm) then 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 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 end
elseif elem.type == "numbers" then elseif elem.type == "numbers" then
local val = elem.default 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) val = meta:get_string(elem.name)
end end
if nvm.running or techage.is_running(nvm) then 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 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 end
elseif elem.type == "float" then elseif elem.type == "float" then
local val = elem.default 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 val = tonumber(meta:get_string(elem.name)) or 0
end end
if nvm.running or techage.is_running(nvm) then 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 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 end
elseif elem.type == "ascii" then elseif elem.type == "ascii" then
local val = elem.default 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) val = meta:get_string(elem.name)
end end
if nvm.running or techage.is_running(nvm) then 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 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 end
elseif elem.type == "const" then 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 elseif elem.type == "output" then
local val = nvm[elem.name] or meta:get_string(elem.name) or "" local val = nvm[elem.name] or meta:get_string(elem.name) or ""
if tonumber(val) then if tonumber(val) then
val = techage.round(val) val = techage.round(val)
end end
tbl[#tbl+1] = "label[4.75," .. offs .. ";" .. val .. "]" tbl[#tbl+1] = "label[" .. xpos1 .. "," .. offs .. ";" .. val .. "]"
elseif elem.type == "dropdown" then elseif elem.type == "dropdown" then
if nvm.running or techage.is_running(nvm) then if nvm.running or techage.is_running(nvm) then
local val = elem.default or "" local val = elem.default or ""
if meta:contains(elem.name) then if meta:contains(elem.name) then
val = meta:get_string(elem.name) or "" 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 .. "]" end
tbl[#tbl+1] = "label[" .. xpos1 .. "," .. offs .. ";" .. val .. "]"
elseif elem.on_dropdown then -- block provides a specific list of choice elements elseif elem.on_dropdown then -- block provides a specific list of choice elements
local val = elem.default local val = elem.default
if meta:contains(elem.name) then 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 choices = elem.on_dropdown(pos)
local l = choices:split(",") local l = choices:split(",")
local idx = index(l, val) or 1 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 else
local val = elem.default local val = elem.default
if meta:contains(elem.name) then 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(",") local l = elem.choices:split(",")
idx = index(l, val) or 1 idx = index(l, val) or 1
end 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 end
elseif elem.type == "items" then -- inventory elseif elem.type == "items" then -- inventory
if elem.size then 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 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 end
player_inv_needed = true player_inv_needed = true
end end
end end
if nvm.running or techage.is_running(nvm) then if not no_note and (nvm.running or techage.is_running(nvm)) then
local offs = #form_def * 0.9 - 0.2 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!") .. "]" tbl[#tbl+1] = "label[0," .. offs .. ";" .. S("Note: You can't change any values while the block is running!") .. "]"
end end
end end
@ -304,6 +315,45 @@ function techage.menu.generate_formspec(pos, ndef, form_def, player_name)
return "" return ""
end 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) function techage.menu.eval_input(pos, form_def, fields, player_name)
if fields.save or fields.key_enter_field then if fields.save or fields.key_enter_field then
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)

View File

@ -210,6 +210,7 @@ local items = {
ta4_chargedetector = "techage:ta4_chargedetector_off", ta4_chargedetector = "techage:ta4_chargedetector_off",
ta4_gaze_sensor = "techage:ta4_gaze_sensor_off", ta4_gaze_sensor = "techage:ta4_gaze_sensor_off",
ta4_nodedetector = "techage:ta4_nodedetector_off", ta4_nodedetector = "techage:ta4_nodedetector_off",
ta4_waterremover = "techage:ta4_waterremover_pas",
---------------------------- ----------------------------
techage_ta5 = "techage:ta5_fr_nucleus", techage_ta5 = "techage:ta5_fr_nucleus",
ta5_flycontroller = "techage:ta5_flycontroller", ta5_flycontroller = "techage:ta5_flycontroller",

View File

@ -89,6 +89,7 @@ return {
"3,TA4 Kiessieb / Gravel Sieve", "3,TA4 Kiessieb / Gravel Sieve",
"3,TA4 Mühle / Grinder", "3,TA4 Mühle / Grinder",
"3,TA4 Steinbrecher / Quarry", "3,TA4 Steinbrecher / Quarry",
"3,TA4 Wasserentferner / Water Remover",
"3,TA4 Elektronikfabrik / Electronic Fab", "3,TA4 Elektronikfabrik / Electronic Fab",
"3,TA4 Injektor / Injector", "3,TA4 Injektor / Injector",
"3,TA4 Recycler", "3,TA4 Recycler",
@ -837,6 +838,20 @@ return {
"\n".. "\n"..
"\n".. "\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 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".. "Die Verarbeitungsleistung beträgt ein Chip alle 6 s. Der Block benötigt hierfür 12 ku Strom.\n"..
"\n".. "\n"..
@ -951,6 +966,7 @@ return {
"ta4_gravelsieve", "ta4_gravelsieve",
"ta4_grinder", "ta4_grinder",
"ta4_quarry", "ta4_quarry",
"ta4_waterremover",
"ta4_electronicfab", "ta4_electronicfab",
"ta4_injector", "ta4_injector",
"ta4_recycler", "ta4_recycler",
@ -1048,5 +1064,6 @@ return {
"", "",
"", "",
"", "",
"",
} }
} }

View File

@ -89,6 +89,7 @@ return {
"3,TA4 Gravel Sieve", "3,TA4 Gravel Sieve",
"3,TA4 Grinder", "3,TA4 Grinder",
"3,TA4 Quarry", "3,TA4 Quarry",
"3,TA4 Water Remover",
"3,TA4 Electronic Fab", "3,TA4 Electronic Fab",
"3,TA4 Injector", "3,TA4 Injector",
"3,TA4 Recycler", "3,TA4 Recycler",
@ -838,6 +839,19 @@ return {
"\n".. "\n"..
"\n".. "\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 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".. "The processing power is one chip every 6 s. The block requires 12 ku of electricity for this.\n"..
"\n".. "\n"..
@ -953,6 +967,7 @@ return {
"ta4_gravelsieve", "ta4_gravelsieve",
"ta4_grinder", "ta4_grinder",
"ta4_quarry", "ta4_quarry",
"ta4_waterremover",
"ta4_electronicfab", "ta4_electronicfab",
"ta4_injector", "ta4_injector",
"ta4_recycler", "ta4_recycler",
@ -1050,5 +1065,6 @@ return {
"", "",
"", "",
"", "",
"",
} }
} }

View File

@ -199,6 +199,7 @@ dofile(MP.."/basic_machines/recycler.lua")
dofile(MP.."/basic_machines/concentrator.lua") dofile(MP.."/basic_machines/concentrator.lua")
dofile(MP.."/basic_machines/recipeblock.lua") dofile(MP.."/basic_machines/recipeblock.lua")
dofile(MP.."/basic_machines/ta5_chest.lua") dofile(MP.."/basic_machines/ta5_chest.lua")
dofile(MP.."/basic_machines/waterremover.lua")
-- Liquids II -- Liquids II
dofile(MP.."/liquids/tank.lua") dofile(MP.."/liquids/tank.lua")

View File

@ -1172,9 +1172,13 @@ Hole size=Lochgröße
Quarry=Steinbrecher Quarry=Steinbrecher
Start level=Startebene Start level=Startebene
Start level @= 0@nmeans the same level@nas the quarry is placed=Startebene @= 0@nbedeutet gleiche Ebene@nwie der Steinbrecher 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 area is protected=Bereich ist geschützt
finished=fertig finished=fertig
inventory full=Inventar ist voll
### reboiler.lua ### ### reboiler.lua ###
@ -1582,6 +1586,17 @@ TA1 Watermill=TA1 Wasssermühle
TA4 Water Pump=Wasserpumpe TA4 Water Pump=Wasserpumpe
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 ### ### windturbine_lib.lua ###
Here is not enough water (41x41 m)!=Hier ist nicht genug Wasser (41x41 m)! Here is not enough water (41x41 m)!=Hier ist nicht genug Wasser (41x41 m)!

View File

@ -1172,9 +1172,13 @@ Hole size=
Quarry= Quarry=
Start level= Start level=
Start level @= 0@nmeans the same level@nas the quarry is placed= Start level @= 0@nmeans the same level@nas the quarry is placed=
inventory full=
### quarry.lua ###
### waterremover.lua ###
area is protected= area is protected=
finished= finished=
inventory full=
### reboiler.lua ### ### reboiler.lua ###
@ -1582,6 +1586,17 @@ TA1 Watermill=
TA4 Water Pump=TA4 Pompe à eau TA4 Water Pump=TA4 Pompe à eau
Water Pump=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 ### ### windturbine_lib.lua ###
Here is not enough water (41x41 m)!=Ici, il n'y a pas assez d'eau (41x41 m)! Here is not enough water (41x41 m)!=Ici, il n'y a pas assez d'eau (41x41 m)!

View File

@ -1172,9 +1172,13 @@ Hole size=Глубина ямы
Quarry=Карьер Quarry=Карьер
Start level=Начальный высота Start level=Начальный высота
Start level @= 0@nmeans the same level@nas the quarry is placed=Начальная высота @= 0@nозначает ту же высоту, что имеется у карьера Start level @= 0@nmeans the same level@nas the quarry is placed=Начальная высота @= 0@nозначает ту же высоту, что имеется у карьера
inventory full=инвентарь заполнен
### quarry.lua ###
### waterremover.lua ###
area is protected=зона защищена area is protected=зона защищена
finished=готово finished=готово
inventory full=инвентарь заполнен
### reboiler.lua ### ### reboiler.lua ###
@ -1582,6 +1586,17 @@ TA1 Watermill=TA1 Водяное колесо
TA4 Water Pump=TA4 Водяной насос TA4 Water Pump=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 ### ### windturbine_lib.lua ###
Here is not enough water (41x41 m)!=Здесь недостаточно воды (41x41 м)! Here is not enough water (41x41 m)!=Здесь недостаточно воды (41x41 м)!

View File

@ -1172,9 +1172,13 @@ Hole size=
Quarry= Quarry=
Start level= Start level=
Start level @= 0@nmeans the same level@nas the quarry is placed= Start level @= 0@nmeans the same level@nas the quarry is placed=
inventory full=
### quarry.lua ###
### waterremover.lua ###
area is protected= area is protected=
finished= finished=
inventory full=
### reboiler.lua ### ### reboiler.lua ###
@ -1582,6 +1586,17 @@ TA1 Watermill=
TA4 Water Pump= TA4 Water Pump=
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 ### ### windturbine_lib.lua ###
Here is not enough water (41x41 m)!= Here is not enough water (41x41 m)!=

View File

@ -49,6 +49,7 @@ are possible.]]
local SYNTAX_ERR = S("Syntax error, try help") local SYNTAX_ERR = S("Syntax error, try help")
local WRENCH_MENU = { local WRENCH_MENU = {
[0] = {"techage:terminal2"}, --valid_nodes
{ {
type = "dropdown", type = "dropdown",
choices = "all players,me", choices = "all players,me",
@ -76,7 +77,7 @@ local function get_string(meta, num, default)
return s return s
end end
local function formspec2(meta) local function formspec2(pos, meta)
local output = meta:get_string("output") local output = meta:get_string("output")
local command = meta:get_string("command") local command = meta:get_string("command")
output = minetest.formspec_escape(output) output = minetest.formspec_escape(output)
@ -90,9 +91,13 @@ local function formspec2(meta)
local bttn_text7 = get_string(meta, 7, "User7") local bttn_text7 = get_string(meta, 7, "User7")
local bttn_text8 = get_string(meta, 8, "User8") local bttn_text8 = get_string(meta, 8, "User8")
local bttn_text9 = get_string(meta, 9, "User9") 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]".. return "size[10,8.5]"..
--"style_type[table,field;font=mono]".. --"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.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,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.."]".. "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 = meta:get_string("output") .. "\n" .. (text or "")
text = text:sub(-1000,-1) text = text:sub(-1000,-1)
meta:set_string("output", text) meta:set_string("output", text)
meta:set_string("formspec", formspec2(meta)) meta:set_string("formspec", formspec2(pos, meta))
end end
local function append(pos, text) local function append(pos, text)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
text = meta:get_string("output") .. (text or "") text = meta:get_string("output") .. (text or "")
meta:set_string("output", text) meta:set_string("output", text)
meta:set_string("formspec", formspec2(meta)) meta:set_string("formspec", formspec2(pos, meta))
end end
local function get_line_text(pos, num) local function get_line_text(pos, num)
@ -188,7 +193,7 @@ local function command(pos, command, player, is_ta4)
if cmnd == "clear" then if cmnd == "clear" then
meta:set_string("output", "") meta:set_string("output", "")
meta:set_string("formspec", formspec2(meta)) meta:set_string("formspec", formspec2(pos, meta))
elseif cmnd == "" then elseif cmnd == "" then
output(pos, "$") output(pos, "$")
elseif cmnd == "help" then elseif cmnd == "help" then
@ -255,7 +260,7 @@ local function command(pos, command, player, is_ta4)
if bttn_num and label and cmnd then if bttn_num and label and cmnd then
meta:set_string("bttn_text"..bttn_num, label) meta:set_string("bttn_text"..bttn_num, label)
meta:set_string("bttn_cmnd"..bttn_num, cmnd) meta:set_string("bttn_cmnd"..bttn_num, cmnd)
meta:set_string("formspec", formspec2(meta)) meta:set_string("formspec", formspec2(pos, meta))
return return
end end
@ -303,7 +308,7 @@ local function register_terminal(name, description, tiles, node_box, selection_b
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
meta:set_string("node_number", number) meta:set_string("node_number", number)
meta:set_string("command", S("commands like: help")) meta:set_string("command", S("commands like: help"))
meta:set_string("formspec", formspec2(meta)) meta:set_string("formspec", formspec2(pos, meta))
if placer then if placer then
meta:set_string("owner", placer:get_player_name()) meta:set_string("owner", placer:get_player_name())
end end
@ -320,22 +325,22 @@ local function register_terminal(name, description, tiles, node_box, selection_b
if evt.type == "DCL" then if evt.type == "DCL" then
local s = get_line_text(pos, evt.row) local s = get_line_text(pos, evt.row)
meta:set_string("command", s) meta:set_string("command", s)
meta:set_string("formspec", formspec2(meta)) meta:set_string("formspec", formspec2(pos, meta))
return return
elseif (fields.ok or fields.key_enter_field) and fields.cmnd then elseif (fields.ok or fields.key_enter_field) and fields.cmnd then
local is_ta4 = string.find(description, "TA4") local is_ta4 = string.find(description, "TA4")
command(pos, fields.cmnd, player:get_player_name(), is_ta4) command(pos, fields.cmnd, player:get_player_name(), is_ta4)
techage.historybuffer_add(pos, fields.cmnd) techage.historybuffer_add(pos, fields.cmnd)
meta:set_string("command", "") meta:set_string("command", "")
meta:set_string("formspec", formspec2(meta)) meta:set_string("formspec", formspec2(pos, meta))
return return
elseif fields.key_up then elseif fields.key_up then
meta:set_string("command", techage.historybuffer_priv(pos)) meta:set_string("command", techage.historybuffer_priv(pos))
meta:set_string("formspec", formspec2(meta)) meta:set_string("formspec", formspec2(pos, meta))
return return
elseif fields.key_down then elseif fields.key_down then
meta:set_string("command", techage.historybuffer_next(pos)) meta:set_string("command", techage.historybuffer_next(pos))
meta:set_string("formspec", formspec2(meta)) meta:set_string("formspec", formspec2(pos, meta))
return return
end end
end end
@ -354,7 +359,7 @@ local function register_terminal(name, description, tiles, node_box, selection_b
end, end,
ta_after_formspec = function(pos, fields, playername) 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 M(pos):get_string("opmode") == "basic" then
if minetest.global_exists("nanobasic") then if minetest.global_exists("nanobasic") then
local node = techage.get_node_lvm(pos) local node = techage.get_node_lvm(pos)

View File

@ -994,6 +994,22 @@ Die maximale Tiefe beträgt 80 Meter. Der Steinbrecher benötigt 14 ku Strom.
[ta4_quarry|image] [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 ### TA4 Elektronikfabrik / Electronic Fab
Die Funktion entspricht der von TA2, nur werden hier verschiedene Chips produziert. Die Funktion entspricht der von TA2, nur werden hier verschiedene Chips produziert.

View File

@ -986,6 +986,21 @@ The maximum depth is 80 meters. The quarry requires 14 ku of electricity.
[ta4_quarry|image] [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 ### TA4 Electronic Fab
The function corresponds to that of TA2, only different chips are produced here. The function corresponds to that of TA2, only different chips are produced here.

View File

@ -1055,6 +1055,7 @@ SLEEP(seconds)
``` ```
The SLEEP function is used to pause program execution for a specified number of 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 ### 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 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 | | 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)<br>`num` is the button number (1..4), `state`: 0 = "off", 1 = "on" | | Multi Button State | 152 | num | state | Read the button state (TA4 2x Button, TA4 4x Button)<br>`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 ### CMD$ Commands with Response as String Value

Binary file not shown.