diff --git a/basic_machines/autocrafter.lua b/basic_machines/autocrafter.lua index 4f6fd85..5a0e733 100644 --- a/basic_machines/autocrafter.lua +++ b/basic_machines/autocrafter.lua @@ -189,6 +189,17 @@ local function normalize(item_list) return item_list end +local function get_input_from_recipeblock(pos, number, idx) + local own_num = M(pos):get_string("node_number") + local owner = M(pos):get_string("owner") + if techage.check_numbers(number, owner) then + local input = techage.send_single(own_num, number, "input", idx) + if input and type(input) == "string" then + return input + end + end +end + local function on_output_change(pos, inventory, stack) if not stack then inventory:set_list("output", {}) @@ -212,6 +223,47 @@ local function on_output_change(pos, inventory, stack) after_recipe_change(pos, inventory) end +local function determine_recipe_items(pos, input) + if input and type(input) == "string" then + -- Test if "." input + local num, idx = unpack(string.split(input, ".", false, 1)) + if num and idx then + input = get_input_from_recipeblock(pos, num, idx) + end + + if input then + -- ",,..." input + local items = string.split(input, ",", true, 8) + if items and type(items) == "table" and next(items) then + return items + end + end + end +end + +local function on_new_recipe(pos, input) + local items = determine_recipe_items(pos, input) + if items then + input = { + method = "normal", + width = 3, + items = items, + } + local output, _ = minetest.get_craft_result(input) + if output.item:get_name() ~= "" then + local inv = M(pos):get_inventory() + for i = 1, 9 do + inv:set_stack("recipe", i, input.items[i]) + end + after_recipe_change(pos, inv) + end + else + local inv = M(pos):get_inventory() + inv:set_list("recipe", {}) + after_recipe_change(pos, inv) + end +end + local function allow_metadata_inventory_put(pos, listname, index, stack, player) if minetest.is_protected(pos, player:get_player_name()) then @@ -346,6 +398,8 @@ tiles.act = { }, } +local INFO = [[Commands: 'state', 'recipe']] + local tubing = { on_inv_request = function(pos, in_dir, access_type) if access_type == "push" then @@ -378,7 +432,20 @@ local tubing = { end end, on_recv_message = function(pos, src, topic, payload) - return CRD(pos).State:on_receive_message(pos, topic, payload) + if topic == "recipe" and CRD(pos).stage == 4 then + if payload and payload ~= "" then + local inv = M(pos):get_inventory() + on_new_recipe(pos, payload) + return true + else + local inv = M(pos):get_inventory() + return inv:get_stack("output", 1):get_name() + end + elseif topic == "info" and CRD(pos).stage == 4 then + return INFO + else + return CRD(pos).State:on_receive_message(pos, topic, payload) + end end, on_node_load = function(pos) CRD(pos).State:on_node_load(pos) @@ -410,7 +477,7 @@ local node_name_ta2, node_name_ta3, node_name_ta4 = num_items = {0,1,2,4}, power_consumption = {0,4,6,9}, }, - {false, true, true, false}) -- TA2/TA3 + {false, true, true, true}) -- TA2/TA3/TA4 minetest.register_craft({ output = node_name_ta2, @@ -430,9 +497,18 @@ minetest.register_craft({ }, }) +minetest.register_craft({ + output = node_name_ta4, + recipe = { + {"", "default:diamond", ""}, + {"", node_name_ta3, ""}, + {"", "techage:ta4_wlanchip", ""}, + }, +}) + local Cable = techage.ElectricCable local power = networks.power -techage.register_node_for_v1_transition({"techage:ta3_autocrafter_pas"}, function(pos, node) +techage.register_node_for_v1_transition({"techage:ta3_autocrafter_pas", "techage:ta4_autocrafter_pas"}, function(pos, node) power.update_network(pos, nil, Cable) -end) \ No newline at end of file +end) diff --git a/basic_machines/recipeblock.lua b/basic_machines/recipeblock.lua new file mode 100644 index 0000000..3e34cc5 --- /dev/null +++ b/basic_machines/recipeblock.lua @@ -0,0 +1,244 @@ +--[[ + + TechAge + ======= + + Copyright (C) 2019-2021 Joachim Stolberg + + AGPL v3 + See LICENSE.txt for more information + + TA4 Recipe Block for the TA4 Autocrafter +]]-- + +-- 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 S = techage.S + +local MAX_RECIPE = 10 + +local function recipes_formspec(x, y, idx) + return "container[" .. x .. "," .. y .. "]" .. + "background[0,0;8,3.2;techage_form_grey.png]" .. + "list[context;input;0.1,0.1;3,3;]" .. + "image[3,1.1;1,1;techage_form_arrow.png]" .. + "list[context;output;3.9,1.1;1,1;]" .. + "button[5.5,1.1;1,1;priv;<<]" .. + "button[6.5,1.1;1,1;next;>>]" .. + "label[5.5,0.5;"..S("Recipe") .. ": " .. idx .. "/" .. MAX_RECIPE .. "]" .. + "container_end[]" +end + +local function formspec(pos, nvm) + return "size[8,7.4]".. + recipes_formspec(0, 0, nvm.recipe_idx or 1) .. + "list[current_player;main;0,3.6;8,4;]" .. + "listring[current_player;main]".. + "listring[context;src]" .. + "listring[current_player;main]".. + "listring[context;dst]" .. + "listring[current_player;main]" +end + +local function determine_new_input(pos, inv) + local output = inv:get_stack("output", 1):get_name() + if output and output ~= "" then + local recipe = minetest.get_craft_recipe(output) + if recipe.items and recipe.type == "normal" then + for i = 1, 9 do + local name = recipe.items[i] + if name then + if minetest.registered_items[name] then + inv:set_stack("input", i, name) + end + end + end + inv:set_stack("output", 1, recipe.output) + end + else + for i = 1, 9 do + inv:set_stack("input", i, nil) + end + end +end + +local function determine_new_output(pos, inv) + local items = {} + for i = 1, 9 do + items[i] = inv:get_stack("input", i):get_name() + end + local input = { + method = "normal", + width = 3, + items = items, + } + local output, _ = minetest.get_craft_result(input) + inv:set_stack("output", 1, output.item) +end + +local function get_recipe(inv) + local items = {} + local last_idx = 0 + for i = 1, 9 do + local name = inv:get_stack("input", i):get_name() + if name ~= "" then + last_idx = i + end + items[i] = name + end + local input = table.concat(items, ",", 1, last_idx) + local stack = inv:get_stack("output", 1) + return { + input = input, + output = stack:get_name() .. " " .. stack:get_count() + } +end + +local function after_recipe_change(pos, inv, listname) + if listname == "input" then + determine_new_output(pos, inv) + else + determine_new_input(pos, inv) + end + local nvm = techage.get_nvm(pos) + nvm.recipes = nvm.recipes or {} + nvm.recipes[nvm.recipe_idx or 1] = get_recipe(inv) +end + +local function update_inventor(pos, inv, idx) + local nvm = techage.get_nvm(pos) + nvm.recipes = nvm.recipes or {} + local recipe = nvm.recipes[idx] + if recipe then + local items = string.split(recipe.input, ",", true) + for i = 1, 9 do + inv:set_stack("input", i, items[i] or "") + end + inv:set_stack("output", 1, recipe.output) + else + for i = 1, 9 do + inv:set_stack("input", i, nil) + end + inv:set_stack("output", 1, nil) + end +end + +local function allow_metadata_inventory_put(pos, listname, index, stack, player) + if minetest.is_protected(pos, player:get_player_name()) then + return 0 + end + + local inv = M(pos):get_inventory() + local list = inv:get_list(listname) + stack:set_count(1) + inv:set_stack(listname, index, stack) + after_recipe_change(pos, inv, listname) + return 0 +end + +local function allow_metadata_inventory_take(pos, listname, index, stack, player) + if minetest.is_protected(pos, player:get_player_name()) then + return 0 + end + + local inv = M(pos):get_inventory() + inv:set_stack(listname, index, nil) + after_recipe_change(pos, inv, listname) + return 0 +end + +local function allow_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player) + if minetest.is_protected(pos, player:get_player_name()) then + return 0 + end + + local inv = M(pos):get_inventory() + if from_list == to_list then + minetest.after(0.1, after_recipe_change, pos, inv, from_list) + return 1 + end + return 0 +end + +minetest.register_node("techage:ta4_recipeblock", { + description = S("TA4 Recipe Block"), + tiles = { + -- up, down, right, left, back, front + "techage_filling_ta4.png^techage_frame_ta4_top.png", + "techage_filling_ta4.png^techage_frame_ta4_top.png", + "techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_recipeblock.png", + }, + + on_construct = function(pos) + local inv = M(pos):get_inventory() + inv:set_size('input', 9) + inv:set_size('output', 1) + end, + + after_place_node = function(pos, placer, itemstack) + local nvm = techage.get_nvm(pos) + local number = techage.add_node(pos, "techage:ta4_chest") + M(pos):set_string("owner", placer:get_player_name()) + M(pos):set_string("node_number", number) + M(pos):set_string("formspec", formspec(pos, nvm)) + M(pos):set_string("infotext", S("TA4 Recipe Block") .. " " .. number) + end, + + on_receive_fields = function(pos, formname, fields, player) + if minetest.is_protected(pos, player:get_player_name()) then + return + end + + local nvm = techage.get_nvm(pos) + nvm.recipe_idx = nvm.recipe_idx or 1 + if fields.next == ">>" then + nvm.recipe_idx = techage.in_range(nvm.recipe_idx + 1, 1, MAX_RECIPE) + elseif fields.priv == "<<" then + nvm.recipe_idx = techage.in_range(nvm.recipe_idx - 1, 1, MAX_RECIPE) + end + local inv = M(pos):get_inventory() + update_inventor(pos, inv, nvm.recipe_idx or 1) + M(pos):set_string("formspec", formspec(pos, nvm)) + end, + + after_dig_node = function(pos, oldnode, oldmetadata, digger) + techage.remove_node(pos, oldnode, oldmetadata) + techage.del_mem(pos) + end, + + allow_metadata_inventory_put = allow_metadata_inventory_put, + allow_metadata_inventory_take = allow_metadata_inventory_take, + allow_metadata_inventory_move = allow_metadata_inventory_move, + + paramtype2 = "facedir", + groups = {choppy=2, cracky=2, crumbly=2}, + is_ground_content = false, + sounds = default.node_sound_wood_defaults(), +}) + +techage.register_node({"techage:ta4_recipeblock"}, { + on_recv_message = function(pos, src, topic, payload) + local nvm = techage.get_nvm(pos) + if topic == "input" and payload and payload ~= "" then + nvm.recipes = nvm.recipes or {} + local recipe = nvm.recipes[tonumber(payload) or 1] + if recipe then + return recipe.input + end + else + return "unsupported" + end + end, +}) + +minetest.register_craft({ + output = "techage:ta4_recipeblock", + recipe = { + {"techage:ta4_carbon_fiber", "dye:blue", "techage:aluminum"}, + {"", "basic_materials:ic", ""}, + {"default:steel_ingot", "techage:ta4_wlanchip", "default:steel_ingot"}, + }, +}) + diff --git a/basis/command.lua b/basis/command.lua index 28afa00..459b1b7 100644 --- a/basis/command.lua +++ b/basis/command.lua @@ -547,7 +547,7 @@ end minetest.register_chatcommand("ta_send", { description = minetest.formspec_escape( - "Send a techage command to the block with the number given: /ta_send []"), + "Send a techage command to the block with the number given: /ta_send []"), func = function(name, param) local num, cmnd, payload = param:match('^([0-9]+)%s+(%w+)%s*(.*)$') @@ -563,6 +563,43 @@ minetest.register_chatcommand("ta_send", { return false, "Destination block is protected" end end - return false, "Syntax: /ta_send []" + return false, "Syntax: /ta_send []" + end +}) + +minetest.register_chatcommand("expoints", { + privs = { + server = true + }, + func = function(name, param) + local player_name, points = param:match("^(%S+)%s*(%d*)$") + if player_name then + local player = minetest.get_player_by_name(player_name) + if player then + if points and points ~= "" then + if techage.set_expoints(player, tonumber(points)) then + return true, "The player "..player_name.." now has "..points.." experience points." + end + else + points = techage.get_expoints(player) + return true, "The player "..player_name.." has "..points.." experience points." + end + else + return false, "Unknown player "..player_name + end + end + return false, "Syntax error! Syntax: /expoints []" + end +}) + +minetest.register_chatcommand("my_expoints", { + func = function(name, param) + local player = minetest.get_player_by_name(name) + if player then + local points = techage.get_expoints(player) + if points then + return true, "You have "..points.." experience points." + end + end end }) diff --git a/basis/fly_lib.lua b/basis/fly_lib.lua index 13dc527..15784d8 100644 --- a/basis/fly_lib.lua +++ b/basis/fly_lib.lua @@ -20,6 +20,36 @@ local S = techage.S local flylib = {} +local function lvect_add_vec(lvect1, offs) + if not lvect1 or not offs then return end + + local lvect2 = {} + for _, v in ipairs(lvect1) do + lvect2[#lvect2 + 1] = vector.add(v, offs) + end + return lvect2 +end + +local function lvect_add(lvect1, lvect2) + if not lvect1 or not lvect2 then return end + + local lvect3 = {} + for i, v in ipairs(lvect1) do + lvect3[#lvect3 + 1] = vector.add(v, lvect2[i]) + end + return lvect3 +end + +local function lvect_subtract(lvect1, lvect2) + if not lvect1 or not lvect2 then return end + + local lvect3 = {} + for i, v in ipairs(lvect1) do + lvect3[#lvect3 + 1] = vector.subtract(v, lvect2[i]) + end + return lvect3 +end + ------------------------------------------------------------------------------- -- to_path function for the fly/move path ------------------------------------------------------------------------------- @@ -294,7 +324,10 @@ end local function determine_dir(pos1, pos2) local vdist = vector.subtract(pos2, pos1) local ndist = vector.length(vdist) - return vector.divide(vdist, ndist) + if ndist > 0 then + return vector.divide(vdist, ndist) + end + return {x=0, y=0, z=0} end local function move_entity(obj, dest_pos, dir, is_corner) @@ -413,12 +446,14 @@ minetest.register_entity("techage:move_item", { on_step = function(self, dtime, moveresult) local stop_obj = function(obj, self) + local dest_pos = self.dest_pos obj:move_to(self.dest_pos, true) obj:set_acceleration({x=0, y=0, z=0}) obj:set_velocity({x=0, y=0, z=0}) self.dest_pos = nil self.old_dist = nil self.ttl = 2 + return dest_pos end if self.dest_pos then @@ -431,24 +466,21 @@ minetest.register_entity("techage:move_item", { -- Landing if self.lpath and self.lpath[self.path_idx] then if dist < 1 or dist > self.old_dist then - local dest_pos = self.dest_pos - stop_obj(obj, self) + local dest_pos = stop_obj(obj, self) if not moveon_entity(obj, self, dest_pos) then minetest.after(0.5, entity_to_node, dest_pos, obj) end return end elseif self.handover and dist < 0.2 or dist > self.old_dist then - local dest_pos = self.dest_pos - stop_obj(obj, self) + local dest_pos = stop_obj(obj, self) if not handover_to(obj, self, dest_pos) then minetest.after(0.5, entity_to_node, dest_pos, obj) end return else if dist < 0.05 or dist > self.old_dist then - local dest_pos = self.dest_pos - stop_obj(obj, self) + local dest_pos = stop_obj(obj, self) minetest.after(0.5, entity_to_node, dest_pos, obj) return end @@ -513,17 +545,7 @@ local function is_simple_node(pos) return true end -local function table_add(tbl, offs) - if not tbl or not offs then return end - - local tbl2 = {} - for _, v in ipairs(tbl) do - tbl2[#tbl2 + 1] = vector.add(v, offs) - end - return tbl2 -end - -local function move_node(pos, pos1_idx, start_pos, lpath, max_speed, height, move2to1, handover) +local function move_node(pos, pos1_idx, start_pos, lpath, max_speed, height, move2to1, handover, cpos) local pos2 = next_path_pos(start_pos, lpath, 1) --print("move_node", P2S(pos), P2S(start_pos), lpath, max_speed, height, move2to1, P2S(pos2)) if pos2 then @@ -547,7 +569,7 @@ local function move_node(pos, pos1_idx, start_pos, lpath, max_speed, height, mov self.base_pos = pos self.move2to1 = move2to1 self.handover = handover - print("move_node", P2S(start_pos), P2S(pos2), P2S(dir), P2S(pos)) + --print("move_node", P2S(start_pos), P2S(pos2), P2S(dir), P2S(pos)) move_entity(obj, pos2, dir) end end @@ -598,13 +620,14 @@ function flylib.move_to_other_pos(pos, move2to1) local handover height = techage.in_range(height, 0, 1) max_speed = techage.in_range(max_speed, MIN_SPEED, MAX_SPEED) + nvm.lpos1 = nvm.lpos1 or {} local offs = dest_offset(lpath) if move2to1 then lpath = reverse_path(lpath) end - nvm.lpos1 = nvm.lpos1 or {} - nvm.lpos2 = table_add(nvm.lpos1, offs) + -- calc destination positions + nvm.lpos2 = lvect_add_vec(nvm.lpos1, offs) if move2to1 then handover = meta:contains("handoverA") and meta:get_string("handoverA") diff --git a/basis/lib.lua b/basis/lib.lua index ba274b7..e3d2219 100644 --- a/basis/lib.lua +++ b/basis/lib.lua @@ -84,31 +84,33 @@ end ------------------------------------------------------------------------------- -- Rotate nodes around the center ------------------------------------------------------------------------------- -local function center(nodes) +function techage.positions_center(lpos) local c = {x=0, y=0, z=0} - for _,v in ipairs(nodes) do + for _,v in ipairs(lpos) do c = vector.add(c, v) end - c = vector.divide(c, #nodes) + c = vector.divide(c, #lpos) c = vector.round(c) c.y = 0 return c end -local function rotate_around_axis(v, c, rot) +function techage.rotate_around_axis(v, c, turn) local dx, dz = v.x - c.x, v.z - c.z - if rot == "l" then + if turn == "l" then return { x = c.x - dz, y = v.y, z = c.z + dx, } - elseif rot == "r" then + elseif turn == "r" then return { x = c.x + dz, y = v.y, z = c.z - dx, } + elseif turn == "" then + return v else -- turn 180 degree return { x = c.x - dx, @@ -119,13 +121,13 @@ local function rotate_around_axis(v, c, rot) end -- Function returns a list ẃith the new node positions --- rot is one of "l", "r", "2l", "2r" +-- turn is one of "l", "r", "2l", "2r" -- cpos is the center pos (optional) -function techage.rotate_around_center(nodes1, rot, cpos) - cpos = cpos or center(nodes1) +function techage.rotate_around_center(nodes1, turn, cpos) + cpos = cpos or techage.positions_center(nodes1) local nodes2 = {} for _,pos in ipairs(nodes1) do - nodes2[#nodes2 + 1] = rotate_around_axis(pos, cpos, rot) + nodes2[#nodes2 + 1] = techage.rotate_around_axis(pos, cpos, turn) end return nodes2 end @@ -471,6 +473,7 @@ function techage.add_expoint(player) local meta = player:get_meta() if meta then meta:set_int("techage_ex_points", meta:get_int("techage_ex_points") + 1) + return true end end end @@ -480,6 +483,7 @@ function techage.set_expoints(player, ex_points) local meta = player:get_meta() if meta then meta:set_int("techage_ex_points", ex_points) + return true end end end diff --git a/basis/recipe_lib.lua b/basis/recipe_lib.lua index 95ecddc..826410d 100644 --- a/basis/recipe_lib.lua +++ b/basis/recipe_lib.lua @@ -22,6 +22,19 @@ local range = techage.in_range techage.recipes = {} +local GROUP_ITEMS = { + stone = "default:cobble", + wood = "default:wood", + book = "default:book", + sand = "default:sand", + leaves = "default:leaves", + stick = "default:stick", + tree = "default:tree", + vessel = "vessels:glass_bottle", + wool = "wool:white", +} + + local RECIPE = { output = {name = "", num = 0}, waste = {name = "", num = 0}, @@ -137,3 +150,17 @@ function techage.recipes.get_recipe(name) return NormalizedRecipes[name] end + +function techage.recipes.get_default_group_item_name(item_name) + if item_name and item_name:sub(1, 6) == "group:" then + local default_name = GROUP_ITEMS[item_name:sub(7)] + if default_name then + return default_name + end + end + return item_name +end + +function techage.recipes.add_group_item(group, default_item_name) + GROUP_ITEMS[group] = default_item_name +end diff --git a/doc/manual_DE.lua b/doc/manual_DE.lua index 6ca1f0d..f6700e3 100644 --- a/doc/manual_DE.lua +++ b/doc/manual_DE.lua @@ -1729,7 +1729,7 @@ techage.manual_DE.aText = { "\n", "Siehe TA3 Pumpe.\n".. "\n".. - "Die TA4 Pumpe pumpt 8 Einheiten Flüssigkeit alle zwei Sekunden.\n".. + "Die TA4 Pumpe pumpt 8 Einheiten Flüssigkeit alle zwei Sekunden. Zusätzlich unterstützt die Pumpe das Kommando 'flowrate'. Damit kann die Gesamtdurchflussmenge durch die Pumpe abgefragt werden.\n".. "\n".. "\n".. "\n", diff --git a/doc/manual_EN.lua b/doc/manual_EN.lua index 67051d9..d7a444f 100644 --- a/doc/manual_EN.lua +++ b/doc/manual_EN.lua @@ -1725,7 +1725,7 @@ techage.manual_EN.aText = { "\n", "See TA3 pump.\n".. "\n".. - "The TA4 pump pumps 8 units of liquid every two seconds.\n".. + "The TA4 pump pumps 8 units of liquid every two seconds. The pump also supports the 'flowrate' command. This means that the total flow rate through the pump can be queried. \n".. "\n".. "\n".. "\n", diff --git a/init.lua b/init.lua index 4b407d1..231e738 100644 --- a/init.lua +++ b/init.lua @@ -33,8 +33,8 @@ elseif minetest.global_exists("minecart") and minecart.version < 1.08 then elseif minetest.global_exists("lcdlib") and lcdlib.version < 1.01 then minetest.log("error", "[techage] Techage requires lcdlib version 1.01 or newer!") return -elseif minetest.global_exists("safer_lua") and safer_lua.version < 1.0 then - minetest.log("error", "[techage] Techage requires safer_lua version 1.0 or newer!") +elseif minetest.global_exists("safer_lua") and safer_lua.version < 1.01 then + minetest.log("error", "[techage] Techage requires safer_lua version 1.01 or newer!") return elseif minetest.global_exists("networks") and networks.version < 0.10 then minetest.log("error", "[techage] Techage requires networks version 0.10 or newer!") @@ -187,6 +187,7 @@ dofile(MP.."/basic_machines/ta4_injector.lua") dofile(MP.."/basic_machines/itemsource.lua") dofile(MP.."/basic_machines/recycler.lua") dofile(MP.."/basic_machines/concentrator.lua") +dofile(MP.."/basic_machines/recipeblock.lua") -- Liquids II dofile(MP.."/liquids/tank.lua") @@ -274,6 +275,7 @@ dofile(MP.."/logic/lua_logic.lua") -- old dofile(MP.."/logic/logic_block.lua") -- new dofile(MP.."/logic/node_detector.lua") dofile(MP.."/logic/player_detector.lua") +dofile(MP.."/logic/mba_detector.lua") dofile(MP.."/logic/cart_detector.lua") dofile(MP.."/logic/collector.lua") dofile(MP.."/logic/button_2x.lua") diff --git a/liquids/pump.lua b/liquids/pump.lua index 54dc680..258ea53 100644 --- a/liquids/pump.lua +++ b/liquids/pump.lua @@ -25,6 +25,13 @@ local COUNTDOWN_TICKS = 4 local CYCLE_TIME = 2 local CAPA = 4 +local WRENCH_MENU = {{ + type = "output", + name = "flowrate", + label = S("Total flow rate"), + tooltip = S("Total flow rate in liquid units"), +}} + local State3 = techage.NodeStates:new({ node_name_passive = "techage:t3_pump", node_name_active = "techage:t3_pump_on", @@ -52,13 +59,15 @@ local function pumping(pos, nvm, state, capa) liquid.untake(pos, Pipe, Flip[outdir], name, leftover) if leftover == taken then state:blocked(pos, nvm) - return + return 0 end + return taken - leftover end state:keep_running(pos, nvm, COUNTDOWN_TICKS) - return + return taken end state:idle(pos, nvm) + return 0 end local function after_place_node3(pos, placer) @@ -85,7 +94,7 @@ end local function node_timer4(pos, elapsed) local nvm = techage.get_nvm(pos) - pumping(pos, nvm, State4, CAPA * 2) + nvm.flowrate = (nvm.flowrate or 0) + pumping(pos, nvm, State4, CAPA * 2) return State4:is_active(nvm) end @@ -235,6 +244,7 @@ minetest.register_node("techage:t4_pump", { groups = {cracky=2}, is_ground_content = false, sounds = default.node_sound_metal_defaults(), + ta4_formspec = WRENCH_MENU, }) minetest.register_node("techage:t4_pump_on", { @@ -261,7 +271,12 @@ techage.register_node({"techage:t3_pump", "techage:t3_pump_on"}, { techage.register_node({"techage:t4_pump", "techage:t4_pump_on"}, { on_recv_message = function(pos, src, topic, payload) - return State4:on_receive_message(pos, topic, payload) + if topic == "flowrate" then + local nvm = techage.get_nvm(pos) + return nvm.flowrate or 0 + else + return State4:on_receive_message(pos, topic, payload) + end end, }) diff --git a/logic/mba_detector.lua b/logic/mba_detector.lua new file mode 100644 index 0000000..8947676 --- /dev/null +++ b/logic/mba_detector.lua @@ -0,0 +1,100 @@ +--[[ + + TechAge + ======= + + Copyright (C) 2017-2020 Joachim Stolberg + + AGPL v3 + See LICENSE.txt for more information + + TA4 Mapblock Active Detector + +]]-- + +-- for lazy programmers +local M = minetest.get_meta +local S = techage.S + +local logic = techage.logic + +minetest.register_node("techage:ta4_mbadetector", { + description = "TA4 Mapblock Active Detector", + inventory_image = 'techage_smartline_mba_detector_inv.png', + tiles = { + -- up, down, right, left, back, front + "techage_smartline.png", + "techage_smartline.png", + "techage_smartline.png", + "techage_smartline.png", + "techage_smartline.png", + "techage_smartline.png^techage_smartline_mba_detector.png", + }, + + drawtype = "nodebox", + node_box = { + type = "fixed", + fixed = { + { -6/32, -6/32, 14/32, 6/32, 6/32, 16/32}, + }, + }, + + after_place_node = function(pos, placer) + local meta = M(pos) + logic.after_place_node(pos, placer, "techage:ta4_mbadetector", S("TA4 Mapblock Active Detector")) + logic.infotext(meta, S("TA4 Mapblock Active Detector")) + minetest.get_node_timer(pos):start(1) + end, + + on_timer = function(pos, elapsed) + local mem = techage.get_mem(pos) + mem.gametime = minetest.get_gametime() + return true + end, + + after_dig_node = function(pos, oldnode, oldmetadata, digger) + techage.remove_node(pos, oldnode, oldmetadata) + techage.del_mem(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(), +}) + +minetest.register_craft({ + output = "techage:ta4_mbadetector", + recipe = { + {"", "group:wood", "default:mese_crystal"}, + {"", "techage:vacuum_tube", "default:copper_ingot"}, + {"", "group:wood", ""}, + }, +}) + +techage.register_node({"techage:ta4_mbadetector"}, { + on_recv_message = function(pos, src, topic, payload) + if topic == "state" then + if minetest.compare_block_status then + if minetest.compare_block_status(pos, "active") then + return "on" + else + return "off" + end + else + local mem = techage.get_mem(pos) + local res = mem.gametime and mem.gametime > (minetest.get_gametime() - 2) + return res and "on" or "off" + end + else + return "unsupported" + end + end, + on_node_load = function(pos) + minetest.get_node_timer(pos):start(1) + end, + } +) + diff --git a/manuals/manual_ta4_DE.md b/manuals/manual_ta4_DE.md index 77acb01..1bdf928 100644 --- a/manuals/manual_ta4_DE.md +++ b/manuals/manual_ta4_DE.md @@ -689,7 +689,7 @@ In einen TA4 Tank passen 2000 Einheiten oder 200 Fässer einer Flüssigkeit. Siehe TA3 Pumpe. -Die TA4 Pumpe pumpt 8 Einheiten Flüssigkeit alle zwei Sekunden. +Die TA4 Pumpe pumpt 8 Einheiten Flüssigkeit alle zwei Sekunden. Zusätzlich unterstützt die Pumpe das Kommando `flowrate`. Damit kann die Gesamtdurchflussmenge durch die Pumpe abgefragt werden. [ta4_pump|image] diff --git a/manuals/manual_ta4_EN.md b/manuals/manual_ta4_EN.md index 7b851c0..b4cb554 100644 --- a/manuals/manual_ta4_EN.md +++ b/manuals/manual_ta4_EN.md @@ -681,7 +681,7 @@ A TA4 tank can hold 2000 units or 200 barrels of liquid. See TA3 pump. -The TA4 pump pumps 8 units of liquid every two seconds. +The TA4 pump pumps 8 units of liquid every two seconds. The pump also supports the `flowrate` command. This means that the total flow rate through the pump can be queried. [ta4_pump|image] diff --git a/manuals/ta4_lua_controller_EN.md b/manuals/ta4_lua_controller_EN.md index b50b953..7a43200 100644 --- a/manuals/ta4_lua_controller_EN.md +++ b/manuals/ta4_lua_controller_EN.md @@ -134,7 +134,8 @@ SaferLua directly supports the following standard functions: - string.rep - string.sub - string.upper -- string.split +- string.split (result is an Array) +- string.split2 (result are multiple returns like the Lua function unpack) - string.trim For own function definitions, the menu tab 'func' can be used. Here you write your functions like: @@ -366,12 +367,14 @@ Please note, that this is not a technical distinction, only a logical. | "depth" | number | Read the current depth value of a quarry block (1..80) | | "load" | number | Read the load value in percent (0..100) of a tank, silo, accu, or battery block, or from the Signs Bot Box. Silo and tank return two values: The percentage value and the absolute value in units.
Example: percent, absolute = $send_cmnd("223", "load") | | "delivered" | number | Read the current delivered power value of a generator block. A power consuming block (accu) provides a negative value | +| "flowrate" | Total flow rate in liquid units | Only for TA4 Pumps | | "action" | player-name, action-string | Only for Sensor Chests | | "stacks" | Array with up to 4 Stores with the inventory content (see example) | Only for Sensor Chests | | "count" | number | Read the item counter of the TA4 Item Detector block | | "count" | number of items | Read the total amount of TA4 chest items. An optional number as `add_data` is used to address only one inventory slot (1..8, from left to right). | | "itemstring" | item string of the given slot | Specific command for the TA4 8x2000 Chest to read the item type (technical name) of one chest slot, specified via `add_data` (1..8).
Example: s = $send_cmnd("223", "itemstring", 1) | | "output" | recipe output string,
e.g.: "default:glass" | Only for the Industrial Furnace. If no recipe is active, the command returns "unknown" | +| "input" | `` | Read a recipe from the TA4 Recipe Block. `` is the number of the recipe. The block return a list of recipe items. | @@ -385,18 +388,23 @@ Please note, that this is not a technical distinction, only a logical. | -------------------------------- | ------------ | ------------------------------------------------------------ | | "on", "off" | nil | turn a node on/off (machine, lamp,...) | | "red, "amber", "green", "off" | nil | set Signal Tower color | +| "red, "amber", "green", "off" | lamp number (1..4) | Set the signal lamp color. Valid for "TA4 2x Signal Lamp" and "TA4 4x Signal Lamp" | | "port" | `=on/off` | Enable/disable a Distributor filter slot..
Example: `yellow=on`
colors: "red", "green", "blue", "yellow" | | "text" | text string | Text to be used for the Sensor Chest menu | | "reset" | nil | Reset the item counter of the TA4 Item Detector block | | "pull" | item string | Start the TA4 pusher to pull/push items.
Example: `default:dirt 8` | | "config" | item string | Configure the TA4 pusher.
Example: `wool:blue` | | "exchange" | inventory slot number | place/remove/exchange an block by means of the TA3 Door Controller II (techage:ta3_doorcontroller2) | - - - -* `$display(num, row, text)` Send a text string to the display with number _num_. _row_ is the display row, a value from 1 to 5, or 0 to add the text string at the bottom (scroll screen mode). _text_ is the string to be displayed. If the first char of the string is a blank, the text will be horizontally centered. -* `$clear_screen(num)` Clear the screen of the display with number _num_. -* `$position(num)` Returns the position as string "'(x,y,z)" of the device with the given _num_. +| "a2b" | nil | TA4 Move Controller command to move the block(s) from position A to B | +| "b2a" | nil | TA4 Move Controller command to move the block(s) from position B to A | +| "move" | nil | TA4 Move Controller command to move the block(s) to the opposite position | +| "left" | nil | TA4 Turn Controller command to turn the block(s) to the left | +| "right" | nil | TA4 Turn Controller command to turn the block(s) to the right | +| "uturn" | nil | TA4 Turn Controller command to turn the block(s) 180 degrees | +| "recipe" | `,,...` | Set the TA4 Autocrafter recipe.
Example for the torch recipe: `default:coal_lump,,,default:stick`
Hint: Empty fields may only be left out at the end of the item list! | +| "recipe" | `.` | Set the TA4 Autocrafter recipe with a recipe from a TA4 Recipe Block.
`` is the TA4 Recipe Block number
`` is the number of the recipe in the TA4 Recipe Block | +| "goto" | `` | Start command for the TA4 Sequencer. `` is the time slot like `[1]` where the execution starts. | +| "stop" | nil | Stop command for the TA4 Sequencer. | ### Server and Terminal Functions @@ -414,25 +422,27 @@ In contrast the Controller can send text strings to the terminal. - `$get_term()` - Read a text command received from the Terminal - `$put_term(num, text)` - Send a text string to the Terminal. _num_ is the number of the Terminal. - -### Further Functions +### Communication between Lua Controllers Messages are used to transport data between Controllers. Messages can contain arbitrary data. Incoming messages are stored in order (up to 10) and can be read one after the other. + * `$get_msg([raw])` - Read a received message. The function returns the sender number and the message. (see example "Emails"). If the _raw_ parameter is not set or false, the message is guaranteed to be a string. * `$send_msg(num, msg)` - Send a message to another Controller. _num_ is the destination number. (see example "Emails") -* `$chat(text)` - Send yourself a chat message. _text_ is a text string. +### Further Functions +* `$chat(text)` - Send yourself a chat message. _text_ is a text string. * `$door(pos, text)` - Open/Close a door at position "pos". Example: `$door("123,7,-1200", "close")`. Hint: Use the Techage Info Tool to determine the door position. - * `$item_description("default:apple")` Get the description (item name) for a specified itemstring, e. g. determined via the TA4 8x2000 Chest command `itemstring`: `str = $send_cmnd("223", "itemstring", 1)` `descr = $item_description(str)` - +* `$display(num, row, text)` Send a text string to the display with number _num_. _row_ is the display row, a value from 1 to 5, or 0 to add the text string at the bottom (scroll screen mode). _text_ is the string to be displayed. If the first char of the string is a blank, the text will be horizontally centered. +* `$clear_screen(num)` Clear the screen of the display with number _num_. +* `$position(num)` Returns the position as string "'(x,y,z)" of the device with the given _num_. ## Example Scripts @@ -662,7 +672,7 @@ loop() code: -- read from Terminal and send the message s = $get_term() if s then - name,text = unpack(string.split(s, ":", false, 1)) + name,text = string.split2(s, ":", false, 1) num = $server_read(SERVER, name) if num then $send_msg(num, text) diff --git a/manuals/ta4_lua_controller_EN.pdf b/manuals/ta4_lua_controller_EN.pdf index 73fca67..5d97537 100644 Binary files a/manuals/ta4_lua_controller_EN.pdf and b/manuals/ta4_lua_controller_EN.pdf differ diff --git a/move_controller/turncontroller.lua b/move_controller/turncontroller.lua index 781d630..d4bbc42 100644 --- a/move_controller/turncontroller.lua +++ b/move_controller/turncontroller.lua @@ -97,7 +97,6 @@ minetest.register_node("techage:ta4_turncontroller", { nvm.lpos = new_posses local name = player:get_player_name() mark.stop(name) - print("new_posses", #new_posses) end meta:set_string("formspec", formspec(nvm, meta)) elseif fields.right then @@ -107,7 +106,6 @@ minetest.register_node("techage:ta4_turncontroller", { nvm.lpos = new_posses local name = player:get_player_name() mark.stop(name) - print("new_posses", #new_posses) end meta:set_string("formspec", formspec(nvm, meta)) end diff --git a/textures/techage_appl_recipeblock.png b/textures/techage_appl_recipeblock.png new file mode 100644 index 0000000..ae14cc9 Binary files /dev/null and b/textures/techage_appl_recipeblock.png differ diff --git a/textures/techage_smartline_mba_detector.png b/textures/techage_smartline_mba_detector.png new file mode 100644 index 0000000..660fe10 Binary files /dev/null and b/textures/techage_smartline_mba_detector.png differ diff --git a/textures/techage_smartline_mba_detector_inv.png b/textures/techage_smartline_mba_detector_inv.png new file mode 100644 index 0000000..dc681b6 Binary files /dev/null and b/textures/techage_smartline_mba_detector_inv.png differ diff --git a/tools/repairkit.lua b/tools/repairkit.lua index 7b09757..b60a2cd 100644 --- a/tools/repairkit.lua +++ b/tools/repairkit.lua @@ -109,6 +109,11 @@ local function read_state(itemstack, user, pointed_thing) consumption = dump(consumption) minetest.chat_send_player(user:get_player_name(), ndef.description.." "..number..": consumption = "..consumption.." kud ") end + local flowrate = techage.send_single("0", number, "flowrate", nil) + if flowrate and flowrate ~= "" and flowrate ~= "unsupported" then + flowrate = dump(flowrate) + minetest.chat_send_player(user:get_player_name(), ndef.description.." "..number..": flowrate = "..flowrate.." ") + end local owner = M(pos):get_string("owner") or "" if owner ~= "" then minetest.chat_send_player(user:get_player_name(), S("Node owner")..": "..owner.." ")