diff --git a/basic_machines/distributor.lua b/basic_machines/distributor.lua index 9940a92..6dba8da 100644 --- a/basic_machines/distributor.lua +++ b/basic_machines/distributor.lua @@ -26,6 +26,9 @@ local COUNTDOWN_TICKS = 10 local STANDBY_TICKS = 10 local CYCLE_TIME = 4 +local INFO = [[- Turn port on/off: command = "port", payload = "red/green/blue/yellow=on/off" +- Clear counter: command = "clear_counter"]] + local function formspec(self, pos, mem) local filter = minetest.deserialize(M(pos):get_string("filter")) or {false,false,false,false} return "size[10.5,8.5]".. @@ -206,7 +209,7 @@ local function distributing(pos, inv, crd, mem) if num_pushed == 0 then crd.State:blocked(pos, mem) else - crd.State:keep_running(pos, mem, COUNTDOWN_TICKS, 1) + crd.State:keep_running(pos, mem, COUNTDOWN_TICKS, sum_num_pushed) end end @@ -324,15 +327,12 @@ local tubing = { return techage.put_items(inv, "src", stack) end, on_recv_message = function(pos, topic, payload) - if topic == "filter" then - return change_filter_settings(pos, payload.slot, payload.val) - elseif topic == "counter" then - local meta = minetest.get_meta(pos) - return minetest.deserialize(meta:get_string("item_counter")) or - {red=0, green=0, blue=0, yellow=0} - elseif topic == "clear_counter" then - local meta = minetest.get_meta(pos) - meta:set_string("item_counter", minetest.serialize({red=0, green=0, blue=0, yellow=0})) + if topic == "info" then + return INFO + elseif topic == "port" then + -- "red"/"green"/"blue"/"yellow" = "on"/"off" + local slot, val = techage.ident_value(payload) + return change_filter_settings(pos, slot, val) else local resp = CRD(pos).State:on_receive_message(pos, topic, payload) if resp then diff --git a/basis/command.lua b/basis/command.lua index add2eb0..e0180bb 100644 --- a/basis/command.lua +++ b/basis/command.lua @@ -204,6 +204,12 @@ function techage.get_new_number(pos, name) return number end +-- extract ident and value from strings like "ident=value" +function techage.ident_value(s) + local ident, value = unpack(string.split(s, "=", true, 1)) + return (ident or ""):trim(), (value or ""):trim() +end + ------------------------------------------------------------------- -- Node construction/destruction functions ------------------------------------------------------------------- @@ -281,14 +287,22 @@ end -- Send message functions ------------------------------------------------------------------- -function techage.send_multi(numbers, placer_name, clicker_name, topic, payload) +function techage.not_protected(number, placer_name, clicker_name) + if Number2Pos[number] and Number2Pos[number].name then + local data = Number2Pos[number] + if data.pos then + return not_protected(data.pos, placer_name, clicker_name) + end + end + return false +end + +function techage.send_multi(numbers, topic, payload) for _,num in ipairs(string_split(numbers, " ")) do if Number2Pos[num] and Number2Pos[num].name then local data = Number2Pos[num] - if data.pos and not_protected(data.pos, placer_name, clicker_name) then - if NodeDef[data.name] and NodeDef[data.name].on_recv_message then - NodeDef[data.name].on_recv_message(data.pos, topic, payload) - end + if data.pos and NodeDef[data.name] and NodeDef[data.name].on_recv_message then + NodeDef[data.name].on_recv_message(data.pos, topic, payload) end end end diff --git a/coal_power_station/generator.lua b/coal_power_station/generator.lua index 9551855..be93515 100644 --- a/coal_power_station/generator.lua +++ b/coal_power_station/generator.lua @@ -87,7 +87,7 @@ local function node_timer(pos, elapsed) if mem.power_available <= 0 or mem.triggered <= 0 then power_switched(pos) State:stop(pos, mem) - mem.generating = 0 + mem.generating = false mem.provided = 0 end else diff --git a/doc/ta3_doc.lua b/doc/ta3_doc.lua index 7c77aea..e80df4e 100644 --- a/doc/ta3_doc.lua +++ b/doc/ta3_doc.lua @@ -103,3 +103,10 @@ techage.register_category_page("ta3m", "techage:ta3_autocrafter_pas", {"pusher", "distributor", "chest", "grinder", "gravelsieve", "autocrafter", "electronic_fab"} ) + +techage.register_category_page("ta3l", + S("TA3: Logic"), + S("Collection of TA3 logic blocks to control your machines."), + "techage:terminal2", + {"terminal"} +) diff --git a/init.lua b/init.lua index 62ff9db..d5d3a80 100644 --- a/init.lua +++ b/init.lua @@ -135,6 +135,9 @@ else dofile(MP.."/nodes/basalt.lua") end + -- Logic + --dofile(MP.."/logic/terminal.lua") + -- Test dofile(MP.."/recipe_checker.lua") dofile(MP.."/.test/sink.lua") diff --git a/logic/terminal.lua b/logic/terminal.lua new file mode 100644 index 0000000..f7ea4da --- /dev/null +++ b/logic/terminal.lua @@ -0,0 +1,342 @@ +--[[ + + Terminal + ======== + + Copyright (C) 2018-2019 Joachim Stolberg + + LGPLv2.1+ + See LICENSE.txt for more information + + terminal.lua: + +]]-- + +local S = techage.S + +local HELP_TA3 = S("#### TA3 Terminal ####@n".. +"@n".. +"Send commands to your machines@n".. +"and output text messages from your@n".. +"machines to the Terminal.@n".. +"@n".. +"Commands can have up to 80 characters.@n".. +"Local commands:@n".. +"- clear = clear screen@n".. +"- help = this message@n".. +"- pub = switch to public use@n".. +"- priv = switch to private use@n".. +"To program a button with a command:@n".. +"- set @n".. +"Global commands:@n".. +"- cmd [] = send a command@n".. +"- turn on/off = send a simple turn on/off command@n") + +local CMNDS_TA3 = S("Command syntax:@n".. +"- cmd [] = send a command@n".. +"- turn on/off = send a simple turn on/off command") + +local function formspec1() + return "size[6,4]".. + default.gui_bg.. + default.gui_bg_img.. + default.gui_slots.. + "field[0.5,1;5,1;number;Techage Controller number:;]" .. + "button_exit[1.5,2.5;2,1;exit;Save]" +end + +local function get_string(meta, num, default) + local s = meta:get_string("bttn_text"..num) + if not s or s == "" then + return default + end + return s +end + +local function formspec2(meta) + local output = meta:get_string("output") + local command = meta:get_string("command") + output = minetest.formspec_escape(output) + output = output:gsub("\n", ",") + local bttn_text1 = get_string(meta, 1, "User1") + local bttn_text2 = get_string(meta, 2, "User2") + local bttn_text3 = get_string(meta, 3, "User3") + local bttn_text4 = get_string(meta, 4, "User4") + local bttn_text5 = get_string(meta, 5, "User5") + local bttn_text6 = get_string(meta, 6, "User6") + local bttn_text7 = get_string(meta, 7, "User7") + local bttn_text8 = get_string(meta, 8, "User8") + local bttn_text9 = get_string(meta, 9, "User9") + return "size[10,8]".. + default.gui_bg.. + default.gui_bg_img.. + default.gui_slots.. + "button[0,0;3.3,1;bttn1;"..bttn_text1.."]button[3.3,0;3.3,1;bttn2;"..bttn_text2.."]button[6.6,0;3.3,1;bttn3;"..bttn_text3.."]".. + "button[0,0.8;3.3,1;bttn4;"..bttn_text4.."]button[3.3,0.8;3.3,1;bttn5;"..bttn_text5.."]button[6.6,0.8;3.3,1;bttn6;"..bttn_text6.."]".. + "button[0,1.6;3.3,1;bttn7;"..bttn_text7.."]button[3.3,1.6;3.3,1;bttn8;"..bttn_text8.."]button[6.6,1.6;3.3,1;bttn9;"..bttn_text9.."]".. + "table[0,2.5;9.8,4.7;output;"..output..";200]".. + "field[0.4,7.7;7.6,1;cmnd;;"..command.."]" .. + "field_close_on_enter[cmnd;false]".. + "button[7.9,7.4;2,1;ok;"..S("Enter").."]" +end + +local function output(pos, text) + local meta = minetest.get_meta(pos) + text = meta:get_string("output") .. "\n" .. (text or "") + text = text:sub(-500,-1) + meta:set_string("output", text) + meta:set_string("formspec", formspec2(meta)) +end + +local function get_line_text(pos, num) + local meta = minetest.get_meta(pos) + local text = meta:get_string("output") or "" + local lines = string.split(text, "\n", true) + local line = lines[num] or "" + return line:gsub("^[%s$]*(.-)%s*$", "%1") +end + + +local function command(pos, command, player) + local meta = minetest.get_meta(pos) + local owner = meta:get_string("owner") or "" + if command then + command = command:sub(1,80) + command = string.trim(command) + + if command == "clear" then + meta:set_string("output", "") + meta:set_string("formspec", formspec2(meta)) + elseif command == "help" then + local meta = minetest.get_meta(pos) + meta:set_string("output", HELP_TA3) + meta:set_string("formspec", formspec2(meta)) + elseif command == "pub" and owner == player then + meta:set_int("public", 1) + output(pos, player..":$ "..command) + output(pos, S("Switched to public use!")) + elseif command == "priv" and owner == player then + meta:set_int("public", 0) + output(pos, player..":$ "..command) + output(pos, S("Switched to private use!")) + elseif meta:get_int("public") == 1 or owner == player then + output(pos, "$ "..command) + local num, cmnd, payload = command:match('^cmd%s+([0-9]+)%s+(%w+)%s*(.*)$') + if num and cmnd then + local own_number = meta:get_string("own_number") + if techage.not_protected(num, owner, owner) then + local resp = techage.send_single(num, cmnd, payload) + if type(resp) == "string" then + output(pos, resp) + else + output(pos, dump(resp)) + end + end + return + end + num, cmnd = command:match('^turn%s+([0-9]+)%s+([onf]+)$') + if num and (cmnd == "on" or cmnd == "off") then + if techage.not_protected(num, owner, owner) then + local resp = techage.send_single(num, cmnd) + output(pos, dump(resp)) + end + return + end + local bttn_num, label, cmnd = command:match('^set%s+([1-9])%s+(%w+)%s+(.+)$') + 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)) + return + end + if command ~= "" then + output(pos, CMNDS_TA3) + end + end + end +end + +local function send_cmnd(pos, meta, num) + local cmnd = meta:get_string("bttn_cmnd"..num) + local owner = meta:get_string("owner") or "" + command(pos, cmnd, owner) +end + +local function register_terminal(num, tiles, node_box, selection_box) + minetest.register_node("techage:terminal"..num, { + description = S("TA3 Terminal"), + tiles = tiles, + drawtype = "nodebox", + node_box = node_box, + selection_box = selection_box, + + after_place_node = function(pos, placer) + local number = techage.add_node(pos, minetest.get_node(pos).name) + local meta = minetest.get_meta(pos) + meta:set_string("own_number", number) + meta:set_string("command", S("commands like: help")) + meta:set_string("formspec", formspec2(meta)) + meta:set_string("owner", placer:get_player_name()) + end, + + on_receive_fields = function(pos, formname, fields, player) + local meta = minetest.get_meta(pos) + local evt = minetest.explode_table_event(fields.output) + if evt.type == "DCL" then + local s = get_line_text(pos, evt.row) + meta:set_string("command", s) + meta:set_string("formspec", formspec2(meta)) + elseif (fields.key_enter == "true" or fields.ok) and fields.cmnd ~= "" then + command(pos, fields.cmnd, player:get_player_name()) + meta:set_string("command", "") + meta:set_string("formspec", formspec2(meta)) + elseif fields.bttn1 then send_cmnd(pos, meta, 1) + elseif fields.bttn2 then send_cmnd(pos, meta, 2) + elseif fields.bttn3 then send_cmnd(pos, meta, 3) + elseif fields.bttn4 then send_cmnd(pos, meta, 4) + elseif fields.bttn5 then send_cmnd(pos, meta, 5) + elseif fields.bttn6 then send_cmnd(pos, meta, 6) + elseif fields.bttn7 then send_cmnd(pos, meta, 7) + elseif fields.bttn8 then send_cmnd(pos, meta, 8) + elseif fields.bttn9 then send_cmnd(pos, meta, 9) + end + end, + + after_dig_node = function(pos) + techage.remove_node(pos) + end, + + paramtype = "light", + sunlight_propagates = true, + paramtype2 = "facedir", + groups = {choppy=2, cracky=2, crumbly=2}, + is_ground_content = false, + sounds = default.node_sound_metal_defaults(), + }) +end + +register_terminal("1", { + -- up, down, right, left, back, front + 'techage_terminal1_top.png', + 'techage_terminal1_bottom.png', + 'techage_terminal1_side.png', + 'techage_terminal1_side.png', + 'techage_terminal1_bottom.png', + "techage_terminal1_front.png", + }, + { + type = "fixed", + fixed = { + {-12/32, -16/32, -8/32, 12/32, -14/32, 12/32}, + {-12/32, -14/32, 12/32, 12/32, 6/32, 14/32}, + }, + }) + +--minetest.register_craft({ +-- output = "techage:terminal", +-- recipe = { +-- {"", "smartline:display", ""}, +-- {"", "", ""}, +-- {"dye:black", "tubelib:wlanchip", "default:copper_ingot"}, +-- }, +--}) + +register_terminal("2", { + -- up, down, right, left, back, front + 'techage_terminal2_top.png', + 'techage_terminal2_side.png', + 'techage_terminal2_side.png^[transformFX', + 'techage_terminal2_side.png', + 'techage_terminal2_back.png', + "techage_terminal2_front.png", + }, + { + type = "fixed", + fixed = { + {-12/32, -16/32, -16/32, 12/32, -14/32, 16/32}, + {-12/32, -14/32, -3/32, 12/32, 6/32, 16/32}, + {-10/32, -12/32, 14/32, 10/32, 4/32, 18/32}, + {-12/32, 4/32, -4/32, 12/32, 6/32, 16/32}, + {-12/32, -16/32, -4/32, -10/32, 6/32, 16/32}, + { 10/32, -16/32, -4/32, 12/32, 6/32, 16/32}, + {-12/32, -14/32, -4/32, 12/32, -12/32, 16/32}, + }, + }, + { + type = "fixed", + fixed = { + {-12/32, -16/32, -4/32, 12/32, 6/32, 16/32}, + }, + }) + +minetest.register_craft({ + output = "techage:terminal2", + recipe = { + {"", "", ""}, + {"techage:basalt_glass_thin", "techage:vacuum_tube", "default:copper_ingot"}, + {"dye:grey", "default:steel_ingot", "techage:usmium_nuggets"}, + }, +}) + +techage.register_node({"techage:terminal1", "techage:terminal2"}, { + on_recv_message = function(pos, topic, payload) + if topic == "term" then + output(pos, payload) + return true + elseif topic == "msg" then + output(pos, payload.src..": "..payload.text) + return true + end + end, +}) + +--sl_controller.register_function("get_term", { +-- cmnd = function(self) +-- return sl_controller.get_command(self.meta.number) +-- end, +-- help = ' $get_term() --> text string or nil\n'.. +-- ' Read an entered string (command) from the Terminal.\n'.. +-- ' example: s = $get_term()\n'.. +-- " The Terminal has to be connected to the controller." +--}) + +--sl_controller.register_action("put_term", { +-- cmnd = function(self, num, text) +-- text = tostring(text or "") +-- tubelib.send_message(num, self.meta.owner, nil, "term", text) +-- end, +-- help = " $put_term(num, text)\n".. +-- ' Send a text line to the terminal with number "num".\n'.. +-- ' example: $put_term("0123", "Hello "..name)' +--}) + +--sl_controller.register_function("get_msg", { +-- cmnd = function(self) +-- local msg = sl_controller.get_msg(self.meta.number) +-- if msg then +-- return msg.src, msg.text +-- end +-- end, +-- help = ' $get_msg() --> number and text string or nil\n'.. +-- ' Read a received messages. Number is the node\n'.. +-- ' number of the sender.\n'.. +-- ' example: num,msg = $get_msg().' +--}) + +--sl_controller.register_action("send_msg", { +-- cmnd = function(self, num, text) +-- local msg = {src = self.meta.number, text = tostring(text or "")} +-- tubelib.send_message(num, self.meta.owner, nil, "msg", msg) +-- end, +-- help = " $send_msg(num, text)\n".. +-- ' Send a message to the controller with number "num".\n'.. +-- ' example: $send_msg("0123", "test")' +--}) + +techage.register_entry_page("ta3l", "terminal", + S("TA3 Terminal"), + S("The Terminal is used to send commands to machines and output their responses.@n".. + "In order to not always have to enter commands, commands can be assigned to buttons@n".. + "and with a double-click on a text line, the command is copied into the input field, again.@n".. + "The terminal has a help command with further information to the supported commands."), + "techage:terminal2") diff --git a/power/junctionbox.lua b/power/junctionbox.lua index a00de20..523a59a 100644 --- a/power/junctionbox.lua +++ b/power/junctionbox.lua @@ -43,11 +43,7 @@ techage.register_junction("techage:electric_junction", 2/8, Boxes, Cable, { power_switched(pos) end, is_power_available = function(pos) - if power_available(pos) then - return "on" - else - return "off" - end + return techage.power.power_accounting(pos) end, }) diff --git a/power/power.lua b/power/power.lua index 6733847..77f1c51 100644 --- a/power/power.lua +++ b/power/power.lua @@ -121,11 +121,6 @@ local function accounting(mem) mem.reserve = (mem.available1 + mem.available2) > mem.needed1 --print("needed = "..mem.needed1.."/"..mem.needed2..", available = "..mem.available1.."/"..mem.available2) --print("supply = "..mem.supply1.."/"..mem.supply2..", demand = "..mem.demand1.."/"..mem.demand2..", reserve = "..dump(mem.reserve)) - -- reset values for nect cycle - mem.needed1 = 0 - mem.needed2 = 0 - mem.available1 = 0 - mem.available2 = 0 end local function connection_walk(pos, clbk) @@ -199,6 +194,11 @@ local function on_power_switch(pos) local mem = tubelib2.get_mem(mpos) mem.is_master = true -- trigger all nodes so that we get a stable state again + -- reset values for nect cycle + mem.needed1 = 0 + mem.needed2 = 0 + mem.available1 = 0 + mem.available2 = 0 trigger_nodes(mpos) accounting(tubelib2.get_mem(mpos)) --t = minetest.get_us_time() - t @@ -327,6 +327,11 @@ function techage.power.power_distribution(pos) -- timer is running, which is needed to be master mem.could_be_master = true if mem.is_master then + -- reset values for nect cycle + mem.needed1 = 0 + mem.needed2 = 0 + mem.available1 = 0 + mem.available2 = 0 trigger_nodes(pos, mem) accounting(mem) end @@ -414,6 +419,15 @@ function techage.power.power_available(pos, needed) return false end +function techage.power.power_accounting(pos) + local mem = tubelib2.get_mem(pos) + if mem.master_pos then + mem = tubelib2.get_mem(mem.master_pos) + return "\nGenerators = "..mem.available1.."\nAkkus = "..mem.available2.."\nMachines = "..mem.needed1.."\n" + end + return "no power" +end + function techage.power.percent(max_val, curr_val) return math.min(math.ceil(((curr_val or 0) * 100.0) / (max_val or 1.0)), 100) end diff --git a/power/powerswitch.lua b/power/powerswitch.lua index a1d586a..7ab39f4 100644 --- a/power/powerswitch.lua +++ b/power/powerswitch.lua @@ -32,7 +32,7 @@ local Param2ToDir = { } local function switch_on(pos, node, clicker) - if minetest.is_protected(pos, clicker:get_player_name()) then + if clicker and minetest.is_protected(pos, clicker:get_player_name()) then return end node.name = "techage:powerswitch_on" @@ -47,7 +47,7 @@ local function switch_on(pos, node, clicker) end local function switch_off(pos, node, clicker) - if minetest.is_protected(pos, clicker:get_player_name()) then + if clicker and minetest.is_protected(pos, clicker:get_player_name()) then return end node.name = "techage:powerswitch" @@ -79,6 +79,14 @@ minetest.register_node("techage:powerswitch", { }, }, + after_place_node = function(pos, placer) + local meta = minetest.get_meta(pos) + local number = techage.add_node(pos, "techage:powerswitch") + meta:set_string("number", number) + meta:set_string("owner", placer:get_player_name()) + meta:set_string("infotext", S("TA Power Switch").." "..number) + end, + on_rightclick = function(pos, node, clicker) switch_on(pos, node, clicker) end, @@ -185,6 +193,27 @@ techage.power.register_node({"techage:powerswitch_box"}, { conn_sides = get_conn_dirs, }) +techage.register_node({"techage:powerswitch", "techage:powerswitch_on"}, { + on_recv_message = function(pos, topic, payload) + local mem = tubelib2.get_mem(pos) + local node = minetest.get_node(pos) + if topic == "on" and node.name == "techage:powerswitch" then + switch_on(pos, node) + return true + elseif topic == "off" and node.name == "techage:powerswitch_on" then + switch_off(pos, node) + return true + elseif topic == "state" then + if node.name == "techage:powerswitch_on" then + return "on" + end + return "off" + else + return "unsupported" + end + end, +}) + minetest.register_craft({ output = "techage:powerswitch 2", recipe = { diff --git a/steam_engine/flywheel.lua b/steam_engine/flywheel.lua index 194bd3f..a626da9 100644 --- a/steam_engine/flywheel.lua +++ b/steam_engine/flywheel.lua @@ -96,7 +96,7 @@ local function node_timer(pos, elapsed) if mem.firebox_trigger <= 0 then power_switched(pos) State:nopower(pos, mem) - mem.generating = 0 + mem.generating = false mem.provided = 0 techage.transfer(pos, "L", "stop", nil, nil, {"techage:cylinder_on"}) else diff --git a/textures/techage_terminal1_bottom.png b/textures/techage_terminal1_bottom.png new file mode 100644 index 0000000..773331d Binary files /dev/null and b/textures/techage_terminal1_bottom.png differ diff --git a/textures/techage_terminal1_front.png b/textures/techage_terminal1_front.png new file mode 100644 index 0000000..038a6ae Binary files /dev/null and b/textures/techage_terminal1_front.png differ diff --git a/textures/techage_terminal1_side.png b/textures/techage_terminal1_side.png new file mode 100644 index 0000000..23e791b Binary files /dev/null and b/textures/techage_terminal1_side.png differ diff --git a/textures/techage_terminal1_top.png b/textures/techage_terminal1_top.png new file mode 100644 index 0000000..72e797d Binary files /dev/null and b/textures/techage_terminal1_top.png differ diff --git a/textures/techage_terminal2_back.png b/textures/techage_terminal2_back.png new file mode 100644 index 0000000..c9632fa Binary files /dev/null and b/textures/techage_terminal2_back.png differ diff --git a/textures/techage_terminal2_front.png b/textures/techage_terminal2_front.png new file mode 100644 index 0000000..7ae0723 Binary files /dev/null and b/textures/techage_terminal2_front.png differ diff --git a/textures/techage_terminal2_side.png b/textures/techage_terminal2_side.png new file mode 100644 index 0000000..813fcfb Binary files /dev/null and b/textures/techage_terminal2_side.png differ diff --git a/textures/techage_terminal2_top.png b/textures/techage_terminal2_top.png new file mode 100644 index 0000000..760ce77 Binary files /dev/null and b/textures/techage_terminal2_top.png differ diff --git a/tools/repairkit.lua b/tools/repairkit.lua index 97bba5c..a7b5ab8 100644 --- a/tools/repairkit.lua +++ b/tools/repairkit.lua @@ -44,6 +44,10 @@ local function read_state(itemstack, user, pointed_thing) local ndef = minetest.registered_nodes[minetest.get_node(pos).name] if number then if ndef and ndef.description then + local info = techage.send_single(number, "info", nil) + if info and info ~= "" and info ~= "unsupported" then + minetest.chat_send_player(user:get_player_name(), ndef.description.." "..number..": Supported Commands:\n"..info.." ") + end local state = techage.send_single(number, "state", nil) if state and state ~= "" and state ~= "unsupported" then minetest.chat_send_player(user:get_player_name(), ndef.description.." "..number..": state = "..state.." ")