diff --git a/README.md b/README.md index 000e45d..f7d5006 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ This modpack covers all necessary and useful mods to be able to use techage. All mods have the own README.txt. For further information please consult these files. -This modpack includes: +This modpack contains: - techage: The main mod - ta4_jetpack: A Jetpack for techage with hydrogen as fuel and TA4 recipe - ta4_paraglider: A Paraglider for techage with TA4 recipe @@ -47,6 +47,12 @@ ta4_jetpack requires the modpack 3d_armor. 3d_armor is itself a modpack and can' ### History +#### 2022-07-11 + +Updated Mods: +- techage (fusion reactor added) + + #### 2022-01-28 Updated Mods: diff --git a/hyperloop/tubecrowbar.lua b/hyperloop/tubecrowbar.lua index a359e9e..2e616de 100644 --- a/hyperloop/tubecrowbar.lua +++ b/hyperloop/tubecrowbar.lua @@ -109,7 +109,7 @@ minetest.register_node("hyperloop:tube_crowbar", { description = S("Hyperloop Tube Crowbar"), inventory_image = "hyperloop_tubecrowbar.png", wield_image = "hyperloop_tubecrowbar.png", - use_texture_alpha = true, + use_texture_alpha = hyperloop.CLIP, groups = {cracky=1, book=1}, on_use = remove_tube, on_place = repair_tubes, diff --git a/lcdlib/README.md b/lcdlib/README.md index 3f620e3..4a658a1 100644 --- a/lcdlib/README.md +++ b/lcdlib/README.md @@ -2,7 +2,7 @@ This LCD Lib is based on Display Lib and Font Lib from Pierre-Yves Rollo -**Dependancies**: default +**Dependancies**: none **License**: LGPL diff --git a/lcdlib/depends.txt b/lcdlib/depends.txt deleted file mode 100644 index e69de29..0000000 diff --git a/lcdlib/mod.conf b/lcdlib/mod.conf new file mode 100644 index 0000000..4e0f72f --- /dev/null +++ b/lcdlib/mod.conf @@ -0,0 +1 @@ +name = lcdlib \ No newline at end of file diff --git a/minecart/baselib.lua b/minecart/baselib.lua index 53bd7ad..09fea93 100644 --- a/minecart/baselib.lua +++ b/minecart/baselib.lua @@ -144,7 +144,7 @@ minetest.register_entity("minecart:marker", { initial_properties = { visual = "upright_sprite", textures = {"minecart_marker_cube.png"}, - use_texture_alpha = true, + use_texture_alpha = minecart.CLIP, physical = false, glow = 12, static_save = false, @@ -196,23 +196,27 @@ function minecart.is_owner(player, owner) end function minecart.get_buffer_pos(pos, player_name) - local pos1 = minecart.find_node_near_lvm(pos, 1, {"minecart:buffer"}) - if pos1 then - local meta = minetest.get_meta(pos1) - if player_name == nil or player_name == meta:get_string("owner") then - return pos1 + if pos then + local pos1 = minecart.find_node_near_lvm(pos, 1, {"minecart:buffer"}) + if pos1 then + local meta = minetest.get_meta(pos1) + if player_name == nil or player_name == meta:get_string("owner") then + return pos1 + end end end end function minecart.get_buffer_name(pos) - local pos1 = minecart.find_node_near_lvm(pos, 1, {"minecart:buffer"}) - if pos1 then - local name = M(pos1):get_string("name") - if name ~= "" then - return name + if pos then + local pos1 = minecart.find_node_near_lvm(pos, 1, {"minecart:buffer"}) + if pos1 then + local name = M(pos1):get_string("name") + if name ~= "" then + return name + end + return P2S(pos1) end - return P2S(pos1) end end diff --git a/minecart/tool.lua b/minecart/tool.lua index 593d3de..55868a7 100644 --- a/minecart/tool.lua +++ b/minecart/tool.lua @@ -102,7 +102,7 @@ minetest.register_node("minecart:tool", { inventory_image = "minecart_tool.png", wield_image = "minecart_tool.png", liquids_pointable = true, - use_texture_alpha = true, + use_texture_alpha = minecart.CLIP, groups = {cracky=1, book=1}, on_use = click_left, on_place = click_right, diff --git a/networks/liquid.lua b/networks/liquid.lua index 59f2f8e..1082cc9 100644 --- a/networks/liquid.lua +++ b/networks/liquid.lua @@ -181,16 +181,16 @@ end function networks.liquid.srv_peek(nvm) nvm.liquid = nvm.liquid or {} - return nvm.liquid.name + nvm.liquid.amount = math.floor((nvm.liquid.amount or 0) + 0.5) + return nvm.liquid.amount > 0 and nvm.liquid.name end function networks.liquid.srv_put(nvm, name, amount, capa) assert(name) - assert(amount and amount >= 0) assert(capa and capa > 0) - + amount = math.floor((amount or 0) + 0.5) nvm.liquid = nvm.liquid or {} - amount = amount or 0 + if not nvm.liquid.name then nvm.liquid.name = name nvm.liquid.amount = amount @@ -210,10 +210,9 @@ function networks.liquid.srv_put(nvm, name, amount, capa) end function networks.liquid.srv_take(nvm, name, amount) - assert(amount and amount >= 0) - + amount = math.floor((amount or 0) + 0.5) nvm.liquid = nvm.liquid or {} - amount = amount or 0 + if not name or nvm.liquid.name == name then name = nvm.liquid.name nvm.liquid.amount = nvm.liquid.amount or 0 diff --git a/signs_bot/README.md b/signs_bot/README.md index 05f711e..377bfd1 100644 --- a/signs_bot/README.md +++ b/signs_bot/README.md @@ -184,4 +184,6 @@ optional: farming redo, node_io, doc, techage, minecart, xdecor, compost - 2021-05-04 v1.08 * Add print command, improve error msg - 2021-08-22 v1.09 * Add soup commands and signs, add aspen sign - 2021-09-18 v1.10 * Add techage command 'set ' to the Bot Control Unit +- 2022-03-19 V1.11 * Extend farming (and add ethereal) support (Thanks to nixnoxus) + diff --git a/signs_bot/basis.lua b/signs_bot/basis.lua index ef5e1c3..aacd1dc 100644 --- a/signs_bot/basis.lua +++ b/signs_bot/basis.lua @@ -417,6 +417,10 @@ minetest.register_node("signs_bot:box", { end, after_place_node = function(pos, placer, itemstack) + if not placer or not placer:is_player() then + minetest.remove_node(pos) + minetest.add_item(pos, itemstack) + end local mem = tubelib2.init_mem(pos) mem.running = false mem.error = false diff --git a/signs_bot/cmd_farming.lua b/signs_bot/cmd_farming.lua index 905be0e..83519f6 100644 --- a/signs_bot/cmd_farming.lua +++ b/signs_bot/cmd_farming.lua @@ -19,9 +19,9 @@ local lib = signs_bot.lib local bot_inv_put_item = signs_bot.bot_inv_put_item local bot_inv_take_item = signs_bot.bot_inv_take_item -local function soil_availabe(pos) +local function soil_availabe(pos, trellis) local node = minetest.get_node_or_nil(pos) - if node.name == "air" then + if node.name == (trellis or "air") then node = minetest.get_node_or_nil({x=pos.x, y=pos.y-1, z=pos.z}) if node and minetest.get_item_group(node.name, "soil") >= 1 then return true @@ -33,13 +33,13 @@ end local function planting(base_pos, mem, slot) local pos = mem.pos_tbl and mem.pos_tbl[mem.steps] mem.steps = (mem.steps or 1) + 1 - if pos and lib.not_protected(base_pos, pos) and soil_availabe(pos) then + if pos and lib.not_protected(base_pos, pos) then local stack = bot_inv_take_item(base_pos, slot, 1) if stack and stack ~= "" then local plant = stack:get_name() if plant then local item = signs_bot.FarmingSeed[plant] - if item then + if item and soil_availabe(pos, signs_bot.FarmingNeedTrellis[item]) then if minetest.registered_nodes[item] then local p2 = minetest.registered_nodes[item].place_param2 or 1 minetest.set_node(pos, {name = item, param2 = p2}) @@ -87,13 +87,20 @@ local function harvesting(base_pos, mem) if pos and lib.not_protected(base_pos, pos) then local node = minetest.get_node_or_nil(pos) if signs_bot.FarmingCrop[node.name] then - minetest.remove_node(pos) + local trellis = signs_bot.FarmingKeepTrellis[node.name] + if trellis then + minetest.set_node(pos, {name = trellis}) + elseif not trellis then + minetest.remove_node(pos) + end -- Do not cache the result of get_node_drops; it is a probabilistic function! local drops = minetest.get_node_drops(node.name) for _,itemstring in ipairs(drops) do - local leftover = bot_inv_put_item(base_pos, 0, ItemStack(itemstring)) - if leftover and leftover:get_count() > 0 then - signs_bot.lib.drop_items(mem.robot_pos, leftover) + if not trellis or trellis ~= itemstring then + local leftover = bot_inv_put_item(base_pos, 0, ItemStack(itemstring)) + if leftover and leftover:get_count() > 0 then + signs_bot.lib.drop_items(mem.robot_pos, leftover) + end end end end diff --git a/signs_bot/mod.conf b/signs_bot/mod.conf index 7e84aab..d649484 100644 --- a/signs_bot/mod.conf +++ b/signs_bot/mod.conf @@ -1,4 +1,4 @@ name=signs_bot depends = default,farming,basic_materials,tubelib2 -optional_depends = node_io,techage,doc,minecart,bucket,fire,xdecor +optional_depends = node_io,techage,doc,minecart,bucket,fire,xdecor,ethereal description = A robot controlled by signs diff --git a/signs_bot/nodes.lua b/signs_bot/nodes.lua index e46837d..46cd452 100644 --- a/signs_bot/nodes.lua +++ b/signs_bot/nodes.lua @@ -14,14 +14,20 @@ signs_bot.FarmingSeed = {} signs_bot.FarmingCrop = {} +signs_bot.FarmingNeedTrellis = {} +signs_bot.FarmingKeepTrellis = {} signs_bot.TreeSaplings = {} -- inv_seed is the seed inventory name -- plantlet is what has to be placed on the ground (stage 1) -- crop is the farming crop in the final stage -function signs_bot.register_farming_plant(inv_seed, plantlet, crop) +function signs_bot.register_farming_plant(inv_seed, plantlet, crop, trellis) signs_bot.FarmingCrop[crop] = true signs_bot.FarmingSeed[inv_seed] = plantlet + if trellis then + signs_bot.FarmingNeedTrellis[plantlet] = trellis + signs_bot.FarmingKeepTrellis[crop] = trellis + end end -- inv_sapling is the sapling inventory name @@ -44,42 +50,27 @@ end -- Farming Redo ------------------------------------------------------------------------------- if farming.mod == "redo" then - fp("farming:seed_wheat", "farming:wheat_1", "farming:wheat_8") - fp("farming:seed_cotton", "farming:cotton_1", "farming:cotton_8") - fp("farming:carrot", "farming:carrot_1", "farming:carrot_8") - fp("farming:potato", "farming:potato_1", "farming:potato_4") - fp("farming:tomato", "farming:tomato_1", "farming:tomato_8") - fp("farming:cucumber", "farming:cucumber_1", "farming:cucumber_4") - fp("farming:corn", "farming:corn_1", "farming:corn_8") - fp("farming:coffee_beans", "farming:coffee_1", "farming:coffee_5") - fp("farming:melon_slice", "farming:melon_1", "farming:melon_8") - fp("farming:pumpkin_slice", "farming:pumpkin_1", "farming:pumpkin_8") - fp("farming:raspberries", "farming:raspberry_1", "farming:raspberry_4") - fp("farming:blueberries", "farming:blueberry_1", "farming:blueberry_4") - fp("farming:rhubarb", "farming:rhubarb_1", "farming:rhubarb_3") - fp("farming:beans", "farming:beanpole_1", "farming:beanpole_5") - fp("farming:grapes", "farming:grapes_1", "farming:grapes_8") - fp("farming:seed_barley", "farming:barley_1", "farming:barley_7") - fp("farming:chili_pepper", "farming:chili_1", "farming:chili_8") - fp("farming:seed_hemp", "farming:hemp_1", "farming:hemp_8") - fp("farming:seed_oat", "farming:oat_1", "farming:oat_8") - fp("farming:seed_rye", "farming:rye_1", "farming:rye_8") - fp("farming:seed_rice", "farming:rice_1", "farming:rice_8") - fp("farming:beetroot", "farming:beetroot_1", "farming:beetroot_5") - fp("farming:cocoa_beans", "farming:cocoa_1", "farming:cocoa_4") - fp("farming:garlic_clove", "farming:garlic_1", "farming:garlic_5") - fp("farming:onion", "farming:onion_1", "farming:onion_5") - fp("farming:pea_pod", "farming:pea_1", "farming:pea_5") - fp("farming:peppercorn", "farming:pepper_1", "farming:pepper_5") - fp("farming:pineapple_top", "farming:pineapple_1", "farming:pineapple_8") + local fp_grows = function(def, step) + local crop = def.crop .. "_" .. step + local node = minetest.registered_nodes[crop] + if node then + fp(def.seed, def.crop .. "_1", crop, def.trellis) + return node.groups and node.groups.growing + end + end + + for name, def in pairs(farming.registered_plants) do + -- everything except cocoa (these can only be placed on jungletree) + if name ~= "farming:cocoa_beans" then + local step = def.steps + while fp_grows(def, step) do step = step + 1 end + end + end end ------------------------------------------------------------------------------- -- Ethereal Farming ------------------------------------------------------------------------------- ---fn("ethereal:strawberry_8", "ethereal:strawberry 2", "ethereal:strawberry 1") ---fn("ethereal:onion_5", "ethereal:wild_onion_plant 2", "ethereal:onion_1") - --fn("ethereal:willow_trunk", "ethereal:willow_trunk", "ethereal:willow_sapling") --fn("ethereal:redwood_trunk", "ethereal:redwood_trunk", "ethereal:redwood_sapling") diff --git a/signs_bot/robot.lua b/signs_bot/robot.lua index b305606..55e501a 100644 --- a/signs_bot/robot.lua +++ b/signs_bot/robot.lua @@ -121,3 +121,22 @@ minetest.register_node("signs_bot:robot_foot", { }, sounds = default.node_sound_metal_defaults(), }) + +minetest.register_lbm({ + label = "[signs_bot] Remove lost robots", + name = "signs_bot:lost_robot_remove", + nodenames = {"signs_bot:robot"}, + run_at_every_load = true, + action = function(pos, node) + local found = false + tubelib2.walk_over_all(function(npos, node, mem) + if node.name == "signs_bot:box" and mem.robot_pos and + vector.equals(pos, mem.robot_pos) then + found = true + end + end, "robot_pos") + if not found then + signs_bot.remove_robot({robot_pos = pos}) + end + end +}) diff --git a/ta4_jetpack/init.lua b/ta4_jetpack/init.lua index 53eb16b..ca977dc 100644 --- a/ta4_jetpack/init.lua +++ b/ta4_jetpack/init.lua @@ -14,6 +14,7 @@ local S = minetest.get_translator("ta4_jetpack") local liquid = networks.liquid +local LQD = function(pos) return (minetest.registered_nodes[tubelib2.get_node_lvm(pos).name] or {}).liquid end local ta4_jetpack = {} @@ -333,12 +334,12 @@ local function load_fuel(itemstack, user, pointed_thing) local value = get_fuel_value(name) local newvalue - if user:get_player_control().sneak then -- back to tank? - local amount = math.min(value, FUEL_UNIT) - local rest = liquid.srv_put(nvm, "techage:hydrogen", amount, MAX_FUEL) - newvalue = value - amount + rest + if user:get_player_control().sneak then -- back to tank? + local amount = math.max(math.min(value, FUEL_UNIT), 0) + local rest = liquid.srv_put(nvm, "techage:hydrogen", amount, LQD(pos).capa) + newvalue = value - (amount - rest) else - local amount = math.min(FUEL_UNIT, MAX_FUEL - value) + local amount = math.max(math.min(FUEL_UNIT, MAX_FUEL - value), 0) local taken = liquid.srv_take(nvm, "techage:hydrogen", amount) newvalue = value + taken end @@ -552,4 +553,4 @@ ta4_jetpack.register_forbidden_item("techage:cylinder_large_hydrogen") ta4_jetpack.register_forbidden_item("techage:cylinder_small_hydrogen") ta4_jetpack.register_forbidden_item("techage:hydrogen") ta4_jetpack.register_forbidden_item("digtron:loaded_crate") -ta4_jetpack.register_forbidden_item("digtron:loaded_locked_crate") \ No newline at end of file +ta4_jetpack.register_forbidden_item("digtron:loaded_locked_crate") diff --git a/techage/README.md b/techage/README.md index 42ee4f0..8fbab06 100644 --- a/techage/README.md +++ b/techage/README.md @@ -2,12 +2,9 @@ Tech Age, a mod to go through 5 tech ages in search of wealth and power. -**Tech Age (techage) is the successor to TechPack V2, at first glance similar and yet completely different!** - ![screenshot](https://github.com/joe7575/techage/blob/master/screenshot.png) - Important facts: - techage is not backwards compatible and cannot be installed on a server together with TechPack - techage is significantly more extensive, since additional mods are integrated @@ -22,6 +19,10 @@ Important facts: In contrast to TechPack, the resources are more limited and it is much more difficult to pass all levels. (no endless ore generation by means of cobble generators) +**Techage blocks store information outside of the block. This is for performance reasons. +If you move, place, or remove blocks with any tool, at best, only the information is lost. +In the worst case, the server crashes.** + [Manuals](https://github.com/joe7575/techage/wiki) @@ -75,11 +76,14 @@ For the installation of 'luarocks' (if not already available), see [luarocks](ht Available worlds will be converted to 'lsqlite3', but there is no way back, so: -** Never disable 'lsqlite3' for a world that has already been used!** +**Never disable 'lsqlite3' for a world that has already been used!** ### History +**2022-06-06 V1.08** +- Native support for the mod Beduino added + **2022-01-22 V1.07** - TA5 fusion reactor added diff --git a/techage/basic_machines/chest.lua b/techage/basic_machines/chest.lua index b07f824..ed7b58d 100644 --- a/techage/basic_machines/chest.lua +++ b/techage/basic_machines/chest.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -180,6 +180,15 @@ techage.register_node({"techage:chest_ta2", "techage:chest_ta3"}, { return "unsupported" end end, + on_beduino_request_data = function(pos, src, topic, payload) + if topic == 131 then + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + return 0, {techage.get_inv_state_num(inv, "main")} + else + return 2, "" + end + end, }) @@ -412,6 +421,15 @@ techage.register_node({"techage:chest_ta4"}, { return "unsupported" end end, + on_beduino_request_data = function(pos, src, topic, payload) + if topic == 131 then + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + return 0, {techage.get_inv_state_num(inv, "main")} + else + return 2, "" + end + end, }) minetest.register_craft({ diff --git a/techage/basic_machines/concentrator.lua b/techage/basic_machines/concentrator.lua index cba0f58..b2a4d67 100644 --- a/techage/basic_machines/concentrator.lua +++ b/techage/basic_machines/concentrator.lua @@ -65,6 +65,10 @@ local names = networks.register_junction("techage:concentrator", 2/8, Boxes, Tub end, }, 27) +for _, name in ipairs(names) do + Tube:set_valid_sides(name, {"B", "R", "F", "L", "D", "U"}) +end + techage.register_node(names, { on_push_item = function(pos, in_dir, stack) local push_dir = M(pos):get_int("push_dir") @@ -110,6 +114,10 @@ names = networks.register_junction("techage:ta4_concentrator", 2/8, Boxes, Tube, end, }, 27) +for _, name in ipairs(names) do + Tube:set_valid_sides(name, {"B", "R", "F", "L", "D", "U"}) +end + techage.register_node(names, { on_push_item = function(pos, in_dir, stack) local push_dir = M(pos):get_int("push_dir") diff --git a/techage/basic_machines/distributor.lua b/techage/basic_machines/distributor.lua index 6df2639..66dd51c 100644 --- a/techage/basic_machines/distributor.lua +++ b/techage/basic_machines/distributor.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -34,6 +34,7 @@ local INFO = [[Turn port on/off or read its state: command = 'port', payload = r --local Side2Color = {B="red", L="green", F="blue", R="yellow"} local SlotColors = {"red", "green", "blue", "yellow"} +local SlotNumbers = {red = 1, green = 2, blue = 3, yellow = 4} local Num2Ascii = {"B", "L", "F", "R"} local FilterCache = {} -- local cache for filter settings @@ -383,16 +384,16 @@ end -- techage command to turn on/off filter channels local function change_filter_settings(pos, slot, val) - local slots = {["red"] = 1, ["green"] = 2, ["blue"] = 3, ["yellow"] = 4} local meta = M(pos) local filter = minetest.deserialize(meta:get_string("filter")) or {false,false,false,false} - local num = slots[slot] or 1 + local num = SlotNumbers[slot] or 1 if num >= 1 and num <= 4 then filter[num] = val == "on" end meta:set_string("filter", minetest.serialize(filter)) - filter_settings(pos) + local hash = minetest.hash_node_position(pos) + FilterCache[hash] = nil local nvm = techage.get_nvm(pos) meta:set_string("formspec", formspec(CRD(pos).State, pos, nvm)) @@ -401,9 +402,45 @@ end -- techage command to read filter channel status (on/off) local function read_filter_settings(pos, slot) - local slots = {["red"] = 1, ["green"] = 2, ["blue"] = 3, ["yellow"] = 4} local filter = minetest.deserialize(M(pos):get_string("filter")) or {false,false,false,false} - return filter[slots[slot]] and "on" or "off" + return filter[SlotNumbers[slot]] and "on" or "off" +end + +local function get_payload_values(payload) + local color + local idx = 0 + local items = {ItemStack(""), ItemStack(""), ItemStack(""), ItemStack(""), ItemStack(""), ItemStack("")} + for s in payload:gmatch("[^%s]+") do --- white spaces + if not color then + if SlotNumbers[s] then + color = s + else + return "red", {} + end + else + idx = idx + 1 + if idx <= 6 then + items[idx] = ItemStack(s) + end + end + end + return color, items +end + +local function str_of_inv_items(pos, color) + color = SlotColors[color] or color + if SlotNumbers[color] then + local inv = M(pos):get_inventory() + local t = {} + for idx = 1, 6 do + local item = inv:get_stack(color, idx) + if item:get_count() > 0 then + t[#t + 1] = item:get_name() + end + end + return table.concat(t, " ") + end + return "" end local function can_dig(pos, player) @@ -474,10 +511,47 @@ local tubing = { else return change_filter_settings(pos, slot, val) end + elseif topic == "config" then + local color, items = get_payload_values(payload) + local inv = M(pos):get_inventory() + for idx,item in ipairs(items) do + inv:set_stack(color, idx, item) + end + local hash = minetest.hash_node_position(pos) + FilterCache[hash] = nil + return true + elseif topic == "get" then + return str_of_inv_items(pos, payload) else return CRD(pos).State:on_receive_message(pos, topic, payload) end end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + if topic == 4 then + local slot = SlotColors[payload[1]] + local state = payload[2] == 1 and "on" or "off" + change_filter_settings(pos, slot, state) + return 0 + elseif topic == 67 then + local color, items = get_payload_values(payload) + local inv = M(pos):get_inventory() + for idx,item in ipairs(items) do + inv:set_stack(color, idx, item) + end + local hash = minetest.hash_node_position(pos) + FilterCache[hash] = nil + return 0 + else + return CRD(pos).State:on_beduino_receive_cmnd(pos, topic, payload) + end + end, + on_beduino_request_data = function(pos, src, topic, payload) + if topic == 148 then + return 0, str_of_inv_items(pos, payload[1]) + 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, diff --git a/techage/basic_machines/electronic_fab.lua b/techage/basic_machines/electronic_fab.lua index 6487412..e6a2640 100644 --- a/techage/basic_machines/electronic_fab.lua +++ b/techage/basic_machines/electronic_fab.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019-2020 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -74,8 +74,9 @@ local function allow_metadata_inventory_take(pos, listname, index, stack, player end local function making(pos, crd, nvm, inv) + local owner = M(pos):get_string("owner") local rtype = RecipeType[crd.stage] - local recipe = recipes.get(nvm, rtype) + local recipe = recipes.get(nvm, rtype, owner) local output = ItemStack(recipe.output.name.." "..recipe.output.num) if inv:room_for_item("dst", output) then for _,item in ipairs(recipe.input) do @@ -202,6 +203,12 @@ local tubing = { on_recv_message = function(pos, src, topic, payload) return CRD(pos).State:on_receive_message(pos, topic, payload) 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) + return CRD(pos).State:on_beduino_request_data(pos, topic, payload) + end, on_node_load = function(pos) CRD(pos).State:on_node_load(pos) end, diff --git a/techage/basic_machines/forceload.lua b/techage/basic_machines/forceload.lua index 121d8ab..adecd64 100644 --- a/techage/basic_machines/forceload.lua +++ b/techage/basic_machines/forceload.lua @@ -91,13 +91,13 @@ local function set_pos_list(player, lPos) meta:set_string("techage_forceload_blocks", minetest.serialize(lPos)) end -local function shoe_flbs(pos, name, range) +local function show_flbs(pos, name, range) local pos1 = {x=pos.x-range, y=pos.y-range, z=pos.z-range} local pos2 = {x=pos.x+range, y=pos.y+range, z=pos.z+range} for _,npos in ipairs(minetest.find_nodes_in_area(pos1, pos2, {"techage:forceload", "techage:forceloadtile"})) do local _pos1, _pos2 = calc_area(npos) local owner = M(npos):get_string("owner") - techage.mark_region(name, _pos1, _pos2, owner) + techage.mark_region(name, _pos1, _pos2, owner .. " " .. P2S(npos)) end end @@ -204,6 +204,7 @@ minetest.register_node("techage:forceload", { paramtype = "light", sunlight_propagates = true, + use_texture_alpha = techage.CLIP, groups = {choppy=2, cracky=2, crumbly=2, digtron_protected = 1, not_in_creative_inventory = techage.max_num_forceload_blocks == 0 and 1 or 0}, @@ -292,15 +293,11 @@ minetest.register_chatcommand("forceload", { params = "", description = S("Show all forceload blocks in a 64x64x64 range"), func = function(name, param) - if minetest.check_player_privs(name, "superminer") then - local player = minetest.get_player_by_name(name) - if player then - local pos = player:get_pos() - pos = vector.round(pos) - shoe_flbs(pos, name, 64) - end - else - return false, S("Priv missing") + local player = minetest.get_player_by_name(name) + if player then + local pos = player:get_pos() + pos = vector.round(pos) + show_flbs(pos, name, 64) end end, }) diff --git a/techage/basic_machines/gravelrinser.lua b/techage/basic_machines/gravelrinser.lua index cff4611..43ef7b9 100644 --- a/techage/basic_machines/gravelrinser.lua +++ b/techage/basic_machines/gravelrinser.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -249,6 +249,12 @@ local tubing = { on_recv_message = function(pos, src, topic, payload) return CRD(pos).State:on_receive_message(pos, topic, payload) 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) + return CRD(pos).State:on_beduino_request_data(pos, topic, payload) + end, on_node_load = function(pos) remove_objects({x=pos.x, y=pos.y+1, z=pos.z}) CRD(pos).State:on_node_load(pos) diff --git a/techage/basic_machines/gravelsieve.lua b/techage/basic_machines/gravelsieve.lua index 0d61593..f12c581 100644 --- a/techage/basic_machines/gravelsieve.lua +++ b/techage/basic_machines/gravelsieve.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019-2021 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -174,6 +174,12 @@ local tubing = { on_recv_message = function(pos, src, topic, payload) return CRD(pos).State:on_receive_message(pos, topic, payload) 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) + return CRD(pos).State:on_beduino_request_data(pos, topic, payload) + end, on_node_load = function(pos) CRD(pos).State:on_node_load(pos) end, diff --git a/techage/basic_machines/grinder.lua b/techage/basic_machines/grinder.lua index 48a9efc..97a8340 100644 --- a/techage/basic_machines/grinder.lua +++ b/techage/basic_machines/grinder.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019-2021 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -56,7 +56,10 @@ local function allow_metadata_inventory_put(pos, listname, index, stack, player) return 0 end if listname == "src" then - CRD(pos).State:start_if_standby(pos) + local state = CRD(pos).State + if state then + state:start_if_standby(pos) + end end return stack:get_count() end @@ -206,6 +209,12 @@ local tubing = { on_recv_message = function(pos, src, topic, payload) return CRD(pos).State:on_receive_message(pos, topic, payload) 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) + return CRD(pos).State:on_beduino_request_data(pos, topic, payload) + end, on_node_load = function(pos) CRD(pos).State:on_node_load(pos) end, diff --git a/techage/basic_machines/liquidsampler.lua b/techage/basic_machines/liquidsampler.lua index 0a4ca84..4467a18 100644 --- a/techage/basic_machines/liquidsampler.lua +++ b/techage/basic_machines/liquidsampler.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019-2020 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -173,6 +173,12 @@ local tubing = { on_recv_message = function(pos, src, topic, payload) return CRD(pos).State:on_receive_message(pos, topic, payload) 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) + return CRD(pos).State:on_beduino_request_data(pos, topic, payload) + end, } local node_name_ta2, node_name_ta3, _ = diff --git a/techage/basic_machines/pusher.lua b/techage/basic_machines/pusher.lua index fd03895..f9ff656 100644 --- a/techage/basic_machines/pusher.lua +++ b/techage/basic_machines/pusher.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -181,13 +181,21 @@ local function can_start(pos, nvm, state) end local function config_item(pos, payload) - local name, count = unpack(payload:split(" ")) - if name and (minetest.registered_nodes[name] or minetest.registered_items[name] - or minetest.registered_craftitems[name]) then - count = tonumber(count) or 1 - local inv = M(pos):get_inventory() - inv:set_stack("main", 1, {name = name, count = 1}) - return count + if type(payload) == "string" then + if payload == "" then + local inv = M(pos):get_inventory() + inv:set_stack("main", 1, nil) + return 0 + else + local name, count = unpack(payload:split(" ")) + if name and (minetest.registered_nodes[name] or minetest.registered_items[name] + or minetest.registered_craftitems[name]) then + count = tonumber(count) or 1 + local inv = M(pos):get_inventory() + inv:set_stack("main", 1, {name = name, count = 1}) + return count + end + end end return 0 end @@ -256,6 +264,24 @@ local tubing = { return CRD(pos).State:on_receive_message(pos, topic, payload) end end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + if topic == 64 then -- Start pusher + local nvm = techage.get_nvm(pos) + CRD(pos).State:stop(pos, nvm) + nvm.item_count = math.min(config_item(pos, payload), 12) + nvm.rmt_num = src + CRD(pos).State:start(pos, nvm) + return 0 + elseif topic == 65 then -- Config Pusher + local nvm = techage.get_nvm(pos) + CRD(pos).State:stop(pos, nvm) + config_item(pos, payload) + CRD(pos).State:start(pos, nvm) + return 0 + else + return CRD(pos).State:on_beduino_receive_cmnd(pos, topic, payload) + end + end, } local node_name_ta2, node_name_ta3, node_name_ta4 = diff --git a/techage/basic_machines/quarry.lua b/techage/basic_machines/quarry.lua index 90aaf87..33be5ec 100644 --- a/techage/basic_machines/quarry.lua +++ b/techage/basic_machines/quarry.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019-2020 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -368,6 +368,17 @@ local tubing = { 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 == 133 then -- Quarry 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, diff --git a/techage/basic_machines/recycler.lua b/techage/basic_machines/recycler.lua index e2442a2..5e82e49 100644 --- a/techage/basic_machines/recycler.lua +++ b/techage/basic_machines/recycler.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019-2021 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -45,7 +45,7 @@ local SpecialItems = { ["dye:black"] = "", ["techage:basalt_glass_thin"] = "", ["group:stone"] = "techage:sieved_gravel", - ["basic_materials:plastic_sheet"] = "", + --["basic_materials:plastic_sheet"] = "", ["group:wood"] = "default:stick 5", ["techage:basalt_glass"] = "", ["default:junglewood"] = "default:stick 5", @@ -235,6 +235,12 @@ local tubing = { on_recv_message = function(pos, src, topic, payload) return CRD(pos).State:on_receive_message(pos, topic, payload) 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) + return CRD(pos).State:on_beduino_request_data(pos, topic, payload) + end, on_node_load = function(pos) CRD(pos).State:on_node_load(pos) end, diff --git a/techage/basic_machines/ta4_chest.lua b/techage/basic_machines/ta4_chest.lua index 096eaef..49bdb83 100644 --- a/techage/basic_machines/ta4_chest.lua +++ b/techage/basic_machines/ta4_chest.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2020 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -92,6 +92,18 @@ local function inv_state(nvm) return "loaded" end +local function inv_state_num(nvm) + local num = 0 + for _,item in ipairs(nvm.inventory or {}) do + if item.count and item.count > 0 then + num = num + 1 + end + end + if num == 0 then return 0 end + if num == 8 then return 2 end + return 1 +end + local function max_stacksize(item_name) -- It is sufficient to use minetest.registered_items as all registration -- functions (node, craftitems, tools) add the definitions there. @@ -324,12 +336,17 @@ local function count_number_of_chests(pos) local node = techage.get_node_lvm(pos) local dir = techage.side_to_outdir("B", node.param2) local pos1 = tubelib2.get_pos(pos, dir) + local param2 = node.param2 local cnt = 1 while cnt < 50 do node = techage.get_node_lvm(pos1) if node.name ~= "techage:ta4_chest_dummy" then break end + local meta = M(pos1) + if meta:contains("param2") and meta:get_int("param2") ~= param2 then + break + end pos1 = tubelib2.get_pos(pos1, dir) cnt = cnt + 1 end @@ -339,12 +356,17 @@ end local function search_chest_in_front(pos, node) local dir = techage.side_to_outdir("F", node.param2) local pos1 = tubelib2.get_pos(pos, dir) + local param2 = node.param2 local cnt = 1 while cnt < 50 do node = techage.get_node_lvm(pos1) if node.name ~= "techage:ta4_chest_dummy" then break end + local meta = M(pos1) + if meta:contains("param2") and meta:get_int("param2") ~= param2 then + break + end pos1 = tubelib2.get_pos(pos1, dir) cnt = cnt + 1 end @@ -517,6 +539,7 @@ minetest.register_node("techage:ta4_chest", { if search_chest_in_front(pos, node) then node.name = "techage:ta4_chest_dummy" minetest.swap_node(pos, node) + M(pos):set_int("param2", node.param2) else local nvm = techage.get_nvm(pos) gen_inv(nvm) @@ -597,10 +620,10 @@ techage.register_node({"techage:ta4_chest"}, { on_recv_message = function(pos, src, topic, payload) if topic == "count" then local nvm = techage.get_nvm(pos) - return get_count(nvm, tonumber(payload) or 0) + return get_count(nvm, tonumber(payload or 1) or 1) elseif topic == "itemstring" then local nvm = techage.get_nvm(pos) - return get_itemstring(nvm, tonumber(payload) or 0) + return get_itemstring(nvm, tonumber(payload or 1) or 1) elseif topic == "state" then local nvm = techage.get_nvm(pos) return inv_state(nvm) @@ -608,6 +631,20 @@ techage.register_node({"techage:ta4_chest"}, { return "unsupported" end end, + on_beduino_request_data = function(pos, src, topic, payload) + if topic == 140 and payload[1] == 1 then -- Inventory Item Count + local nvm = techage.get_nvm(pos) + return 0, {get_count(nvm, tonumber(payload[2] or 1) or 1)} + elseif topic == 140 and payload[1] == 2 then -- Inventory Item Name + local nvm = techage.get_nvm(pos) + return 0, get_itemstring(nvm, tonumber(payload[2] or 1) or 1) + elseif topic == 131 then -- Chest State + local nvm = techage.get_nvm(pos) + return 0, {inv_state_num(nvm)} + else + return 2, "" + end + end, }) techage.register_node({"techage:ta4_chest_dummy"}, { diff --git a/techage/basic_machines/ta4_injector.lua b/techage/basic_machines/ta4_injector.lua index 4332e17..e08bfd0 100644 --- a/techage/basic_machines/ta4_injector.lua +++ b/techage/basic_machines/ta4_injector.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2020 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -242,6 +242,12 @@ local tubing = { on_recv_message = function(pos, src, topic, payload) return CRD(pos).State:on_receive_message(pos, topic, payload) 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) + return CRD(pos).State:on_beduino_request_data(pos, topic, payload) + end, on_node_load = function(pos) CRD(pos).State:on_node_load(pos) end, diff --git a/techage/basic_machines/ta5_chest.lua b/techage/basic_machines/ta5_chest.lua index 1d56064..d99b051 100644 --- a/techage/basic_machines/ta5_chest.lua +++ b/techage/basic_machines/ta5_chest.lua @@ -175,6 +175,15 @@ techage.register_node({"techage:ta5_hl_chest"}, { return "unsupported" end end, + on_beduino_request_data = function(pos, src, topic, payload) + if topic == 131 then -- Chest State + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + return 0, {techage.get_inv_state_num(inv, "main")} + else + return 2, "" + end + end, }) diff --git a/techage/basis/assemble.lua b/techage/basis/assemble.lua index c4d81d9..8763d2d 100644 --- a/techage/basis/assemble.lua +++ b/techage/basis/assemble.lua @@ -173,13 +173,14 @@ local function remove_inv(pos, inv, param2, AssemblyPlan, player_name, idx) if inv:room_for_item("src", stack) then local node = minetest.get_node(pos1) if node.name == node_name then + local meta = M(pos1):to_table() minetest.remove_node(pos1) inv:add_item("src", stack) play_sound(pos, "default_dig_cracky") local ndef = minetest.registered_nodes[node_name] if ndef and ndef.after_dig_node then local digger = minetest.get_player_by_name(player_name) - ndef.after_dig_node(pos1, pos, ItemStack(node_name), {}, digger) + ndef.after_dig_node(pos1, node, meta, digger) end end end diff --git a/techage/basis/command.lua b/techage/basis/command.lua index f2b4362..e17400e 100644 --- a/techage/basis/command.lua +++ b/techage/basis/command.lua @@ -406,6 +406,33 @@ function techage.transfer(pos, outdir, topic, payload, network, nodenames) return false end +------------------------------------------------------------------- +-- Beduino functions (see "bep-005_ta_cmnd.md") +------------------------------------------------------------------- +function techage.beduino_send_cmnd(src, number, topic, payload) + --print("beduino_send_cmnd", src, number, topic) + local ninfo = NodeInfoCache[number] or update_nodeinfo(number) + if ninfo and ninfo.name and ninfo.pos then + local ndef = NodeDef[ninfo.name] + if ndef and ndef.on_beduino_receive_cmnd then + return ndef.on_beduino_receive_cmnd(ninfo.pos, src, topic, payload or {}) + end + end + return 1, "" +end + +function techage.beduino_request_data(src, number, topic, payload) + --print("beduino_request_data", src, number, topic) + local ninfo = NodeInfoCache[number] or update_nodeinfo(number) + if ninfo and ninfo.name and ninfo.pos then + local ndef = NodeDef[ninfo.name] + if ndef and ndef.on_beduino_request_data then + return ndef.on_beduino_request_data(ninfo.pos, src, topic, payload or {}) + end + end + return 1, "" +end + ------------------------------------------------------------------- -- Client side Push/Pull item functions ------------------------------------------------------------------- @@ -564,6 +591,23 @@ function techage.get_inv_state(inv, listname) return state end +-- Beduino variant +function techage.get_inv_state_num(inv, listname) + local state + if inv:is_empty(listname) then + state = 0 + else + local list = inv:get_list(listname) + state = 2 + for _, item in ipairs(list) do + if item:is_empty() then + return 1 + end + end + end + return state +end + minetest.register_chatcommand("ta_send", { description = minetest.formspec_escape( "Send a techage command to the block with the number given: /ta_send []"), diff --git a/techage/basis/fly_lib.lua b/techage/basis/fly_lib.lua index 4ae48b2..be1a137 100644 --- a/techage/basis/fly_lib.lua +++ b/techage/basis/fly_lib.lua @@ -134,13 +134,39 @@ local function dest_offset(lpath) return offs end +------------------------------------------------------------------------------- +-- Protect the doors from being opened by hand +------------------------------------------------------------------------------- +local function new_on_rightclick(old_on_rightclick) + return function(pos, node, clicker, itemstack, pointed_thing) + if M(pos):contains("ta_door_locked") then + return itemstack + end + if old_on_rightclick then + return old_on_rightclick(pos, node, clicker, itemstack, pointed_thing) + else + return itemstack + end + end +end + +function flylib.protect_door_from_being_opened(name) + -- Change on_rightclick function. + local ndef = minetest.registered_nodes[name] + if ndef then + local old_on_rightclick = ndef.on_rightclick + minetest.override_item(ndef.name, { + on_rightclick = new_on_rightclick(old_on_rightclick) + }) + end +end + ------------------------------------------------------------------------------- -- Entity / Move / Attach / Detach ------------------------------------------------------------------------------- local MIN_SPEED = 0.4 local MAX_SPEED = 8 local CORNER_SPEED = 4 -local SimpleNodes = techage.logic.SimpleNodes local function calc_speed(v) return math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z) @@ -292,8 +318,7 @@ local function entity_to_node(pos, obj) local nvm = techage.get_nvm(self.base_pos) nvm.running = nil end - obj:remove() - + minetest.after(0.1, obj.remove, obj) local node = minetest.get_node(pos) local ndef1 = minetest.registered_nodes[name] local ndef2 = minetest.registered_nodes[node.name] @@ -303,6 +328,7 @@ local function entity_to_node(pos, obj) minetest.set_node(pos, {name=name, param2=param2}) meta:from_table(metadata) meta:set_string("ta_move_block", "") + meta:set_int("ta_door_locked", 1) return end local meta = M(pos) @@ -326,11 +352,14 @@ local function node_to_entity(start_pos) node = minetest.deserialize(meta:get_string("ta_move_block")) metadata = {} meta:set_string("ta_move_block", "") - else + meta:set_string("ta_block_locked", "true") + elseif not meta:contains("ta_block_locked") then -- Block with other metadata node = minetest.get_node(start_pos) metadata = meta:to_table() - minetest.remove_node(start_pos) + minetest.after(0.1, minetest.remove_node, start_pos) + else + return end local obj = minetest.add_entity(start_pos, "techage:move_item") if obj then @@ -388,36 +417,38 @@ end -- Handover the entity to the next movecontroller local function handover_to(obj, self, pos1) - local info = techage.get_node_info(self.handover) - if info and info.name == "techage:ta4_movecontroller" then - local meta = M(info.pos) - if self.move2to1 then - self.handover = meta:contains("handoverA") and meta:get_string("handoverA") - else - self.handover = meta:contains("handoverB") and meta:get_string("handoverB") - end - - self.lpath = flylib.to_path(meta:get_string("path")) - if pos1 and self.lpath then - self.path_idx = 2 + if self.handover then + local info = techage.get_node_info(self.handover) + if info and info.name == "techage:ta4_movecontroller" then + local meta = M(info.pos) if self.move2to1 then - self.lpath[1] = vector.multiply(self.lpath[1], - 1) + self.handover = meta:contains("handoverA") and meta:get_string("handoverA") or nil + else + self.handover = meta:contains("handoverB") and meta:get_string("handoverB") or nil end - local pos2 = next_path_pos(pos1, self.lpath, 1) - local dir = determine_dir(pos1, pos2) - --print("handover_to", P2S(pos1), P2S(pos2), P2S(dir), P2S(info.pos), meta:get_string("path")) - if not self.handover then - local nvm = techage.get_nvm(info.pos) - nvm.lpos1 = nvm.lpos1 or {} - if self.move2to1 then - nvm.lpos1[self.pos1_idx] = pos2 - else - nvm.lpos1[self.pos1_idx] = pos1 + self.lpath = flylib.to_path(meta:get_string("path")) + if pos1 and self.lpath then + self.path_idx = 2 + if self.move2to1 then + self.lpath[1] = vector.multiply(self.lpath[1], - 1) end + local pos2 = next_path_pos(pos1, self.lpath, 1) + local dir = determine_dir(pos1, pos2) + --print("handover_to", P2S(pos1), P2S(pos2), P2S(dir), P2S(info.pos), meta:get_string("path")) + if not self.handover then + local nvm = techage.get_nvm(info.pos) + nvm.lpos1 = nvm.lpos1 or {} + if self.move2to1 then + nvm.lpos1[self.pos1_idx] = pos2 + + else + nvm.lpos1[self.pos1_idx] = pos1 + end + end + move_entity(obj, pos2, dir) + return true end - move_entity(obj, pos2, dir) - return true end end end @@ -473,7 +504,7 @@ minetest.register_entity("techage:move_item", { self.object:set_properties({wield_item = self.item}) --print("tbl.respawn", tbl.respawn) if tbl.respawn then - entity_to_node(self.start_pos, self.object) + entity_to_node(self.dest_pos, self.object) end end end, @@ -552,8 +583,7 @@ minetest.register_entity("techage:move_item", { local function is_valid_dest(pos) local node = minetest.get_node(pos) - local ndef = minetest.registered_nodes[node.name] - if ndef and ndef.buildable_to then + if techage.is_air_like(node.name) then return true end if not M(pos):contains("ta_move_block") then @@ -563,20 +593,9 @@ local function is_valid_dest(pos) end local function is_simple_node(pos) - -- special handling - local name = minetest.get_node(pos).name - if SimpleNodes[name] ~= nil then - return SimpleNodes[name] - end - - local ndef = minetest.registered_nodes[name] - if not ndef or name == "air" or name == "ignore" then return false end - -- don't remove nodes with some intelligence or undiggable nodes - if ndef.drop == "" then return false end - if ndef.diggable == false then return false end - if ndef.after_dig_node then return false end - - return true + local node = minetest.get_node(pos) + local ndef = minetest.registered_nodes[node.name] + return not techage.is_air_like(node.name) and techage.can_dig_node(node.name, ndef) end local function move_node(pos, pos1_idx, start_pos, lpath, max_speed, height, move2to1, handover, cpos) @@ -649,6 +668,43 @@ local function move_nodes(pos, meta, nvm, lpath, max_speed, height, move2to1, ha return true end +-- Move nodes from lpos1 by the given x/y/z 'line' +local function move_nodes2(pos, meta, lpos1, line, max_speed, height) + --print("move_nodes2", dump(lpos1), dump(line), max_speed, height) + local owner = meta:get_string("owner") + techage.counting_add(owner, #lpos1) + + local lpos2 = {} + for idx = 1, #lpos1 do + + local pos1 = lpos1[idx] + local pos2 = vector.add(lpos1[idx], line) + lpos2[idx] = pos2 + + if not minetest.is_protected(pos1, owner) and not minetest.is_protected(pos2, owner) then + if is_simple_node(pos1) and is_valid_dest(pos2) then + move_node(pos, idx, pos1, {line}, max_speed, height, false, false) + else + if not is_simple_node(pos1) then + meta:set_string("status", S("No valid node at the start position")) + else + meta:set_string("status", S("No valid destination position")) + end + end + else + if minetest.is_protected(pos1, owner) then + meta:set_string("status", S("Start position is protected")) + else + meta:set_string("status", S("Destination position is protected")) + end + return false, lpos1 + end + end + + meta:set_string("status", "") + return true, lpos2 +end + function flylib.move_to_other_pos(pos, move2to1) local meta = M(pos) local nvm = techage.get_nvm(pos) @@ -671,13 +727,36 @@ function flylib.move_to_other_pos(pos, move2to1) nvm.lpos2 = lvect_add_vec(nvm.lpos1, offs) if move2to1 then - handover = meta:contains("handoverA") and meta:get_string("handoverA") + handover = meta:contains("handoverA") and meta:get_string("handoverA") or nil else - handover = meta:contains("handoverB") and meta:get_string("handoverB") + handover = meta:contains("handoverB") and meta:get_string("handoverB") or nil end return move_nodes(pos, meta, nvm, lpath, max_speed, height, move2to1, handover) end +function flylib.move_to(pos, line) + local meta = M(pos) + local nvm = techage.get_nvm(pos) + local height = techage.in_range(meta:contains("height") and meta:get_float("height") or 1, 0, 1) + local max_speed = meta:contains("max_speed") and meta:get_int("max_speed") or MAX_SPEED + local resp + + resp, nvm.lastpos = move_nodes2(pos, meta, nvm.lastpos or nvm.lpos1, line, max_speed, height) + return resp +end + +function flylib.reset_move(pos) + local meta = M(pos) + local nvm = techage.get_nvm(pos) + local height = techage.in_range(meta:contains("height") and meta:get_float("height") or 1, 0, 1) + local max_speed = meta:contains("max_speed") and meta:get_int("max_speed") or MAX_SPEED + local move = vector.subtract(nvm.lpos1[1], (nvm.lastpos or nvm.lpos1)[1]) + local resp + + resp, nvm.lastpos = move_nodes2(pos, meta, nvm.lastpos or nvm.lpos1, move, max_speed, height) + return resp +end + -- rot is one of "l", "r", "2l", "2r" -- cpos is the center pos (optional) function flylib.rotate_nodes(pos, posses1, rot) @@ -712,6 +791,39 @@ function flylib.rotate_nodes(pos, posses1, rot) return posses2 end +function flylib.exchange_node(pos, name, param2) + local meta = M(pos) + local move_block + + -- consider stored "objects" + if meta:contains("ta_move_block") then + move_block = meta:get_string("ta_move_block") + end + + minetest.swap_node(pos, {name = name, param2 = param2}) + + if move_block then + meta:set_string("ta_move_block", move_block) + end +end + +function flylib.remove_node(pos) + local meta = M(pos) + local move_block + + -- consider stored "objects" + if meta:contains("ta_move_block") then + move_block = meta:get_string("ta_move_block") + end + + minetest.remove_node(pos) + + if move_block then + local node = minetest.deserialize(move_block) + minetest.add_node(pos, node) + meta:set_string("ta_move_block", "") + end +end minetest.register_on_joinplayer(function(player) unlock_player(player) diff --git a/techage/basis/hyperloop.lua b/techage/basis/hyperloop.lua index a694e32..e89b972 100644 --- a/techage/basis/hyperloop.lua +++ b/techage/basis/hyperloop.lua @@ -57,16 +57,19 @@ local function get_remote_pos(pos, rmt_name) end local function get_free_server_list(pos, owner) - local tbl = {M(pos):get_string("remote_name")} - for key,item in pairs(Stations:get_node_table(pos)) do - if item.single and item.owner == owner then - if M(pos):get_string("node_type") == M(S2P(key)):get_string("node_type") then - tbl[#tbl+1] = item.conn_name + if Stations and Stations.get_node_table then + local tbl = {M(pos):get_string("remote_name")} + for key,item in pairs(Stations:get_node_table(pos) or {}) do + if item.single and item.owner == owner then + if M(pos):get_string("node_type") == M(S2P(key)):get_string("node_type") then + tbl[#tbl+1] = item.conn_name + end end end + tbl[#tbl+1] = "" + return tbl end - tbl[#tbl+1] = "" - return tbl + return {} end local function on_lose_connection(pos, node_type) @@ -78,8 +81,11 @@ local function on_lose_connection(pos, node_type) end local function on_dropdown(pos) - local owner = M(pos):get_string("owner") - return table.concat(get_free_server_list(pos, owner), ",") + if pos then + local owner = M(pos):get_string("owner") + return table.concat(get_free_server_list(pos, owner), ",") or "" + end + return "" end local function update_node_data(pos, state, conn_name, remote_name, rmt_pos) diff --git a/techage/basis/lib.lua b/techage/basis/lib.lua index d47f5ac..6311bc5 100644 --- a/techage/basis/lib.lua +++ b/techage/basis/lib.lua @@ -76,7 +76,7 @@ for _,row in ipairs(ROTATION) do end function techage.facedir_to_rotation(facedir) - return FACEDIR_TO_ROT[facedir] + return FACEDIR_TO_ROT[facedir] or FACEDIR_TO_ROT[0] end function techage.param2_turn_left(param2) @@ -129,7 +129,6 @@ function techage.param2_turn_up(facedir, param2) end - ------------------------------------------------------------------------------- -- Rotate nodes around the center ------------------------------------------------------------------------------- @@ -181,12 +180,12 @@ function techage.rotate_around_center(nodes1, turn, cpos) return nodes2 end --- allowed for digging -local RegisteredNodesToBeDug = {} -function techage.register_node_to_be_dug(name) - RegisteredNodesToBeDug[name] = true -end +------------------------------------------------------------------------------- +-- Helper functions +------------------------------------------------------------------------------- +-- allowed for digging +local SimpleNodes = {} -- translation from param2 to dir (out of the node upwards) local Param2Dir = {} @@ -244,6 +243,17 @@ function techage.add_to_set(set, x) end end +-- techage.tbl_filter({"a", "b", "c", "d"}, function(v, k, t) return v >= "c" end) --> {"c","d"} +techage.tbl_filter = function(t, filterIter) + local out = {} + + for k, v in pairs(t) do + if filterIter(v, k, t) then out[k] = v end + end + + return out +end + function techage.get_node_lvm(pos) local node = minetest.get_node_or_nil(pos) if node then @@ -273,21 +283,54 @@ function techage.is_air_like(name) end -- returns true, if node can be dug, otherwise false -function techage.can_node_dig(node, ndef) - if RegisteredNodesToBeDug[node.name] then +function techage.can_dig_node(name, ndef) + if not ndef then return false end + if SimpleNodes[name] ~= nil then + return SimpleNodes[name] + end + + if ndef.groups and ndef.groups.techage_door == 1 then + SimpleNodes[name] = true return true end - if not ndef then return false end - if node.name == "ignore" then return false end - if node.name == "air" then return true end - if ndef.buildable_to == true then return true end - if ndef.diggable == false then return false end - if ndef.after_dig_node then return false end + if name == "ignore" then + SimpleNodes[name] = false + return false + end + if name == "air" then + SimpleNodes[name] = true + return true + end + if ndef.buildable_to == true then + SimpleNodes[name] = true + return true + end + -- don't remove nodes with some intelligence or undiggable nodes + if ndef.drop == "" then + SimpleNodes[name] = false + return false + end + if ndef.diggable == false then + SimpleNodes[name] = false + return false + end + if ndef.after_dig_node then + SimpleNodes[name] = false + return false + end -- add it to the white list - RegisteredNodesToBeDug[node.name] = true + SimpleNodes[name] = true return true end +-- Simple nodes +function techage.register_simple_nodes(node_names, is_valid) + if is_valid == nil then is_valid = true end + for _,name in ipairs(node_names or {}) do + SimpleNodes[name] = is_valid + end +end + techage.dig_states = { NOT_DIGGABLE = 1, INV_FULL = 2, @@ -421,50 +464,6 @@ function techage.item_image_small(x, y, itemname, tooltip_prefix) tooltip end -function techage.mydump(o, indent, nested, level) - local t = type(o) - if not level and t == "userdata" then - -- when userdata (e.g. player) is passed directly, print its metatable: - return "userdata metatable: " .. techage.mydump(getmetatable(o)) - end - if t ~= "table" then - return basic_dump(o) - end - -- Contains table -> true/nil of currently nested tables - nested = nested or {} - if nested[o] then - return "" - end - nested[o] = true - indent = " " - level = level or 1 - local t = {} - local dumped_indexes = {} - for i, v in ipairs(o) do - t[#t + 1] = techage.mydump(v, indent, nested, level + 1) - dumped_indexes[i] = true - end - for k, v in pairs(o) do - if not dumped_indexes[k] then - if type(k) ~= "string" or not is_valid_identifier(k) then - k = "["..techage.mydump(k, indent, nested, level + 1).."]" - end - v = techage.mydump(v, indent, nested, level + 1) - t[#t + 1] = k.." = "..v - end - end - nested[o] = nil - if indent ~= "" then - local indent_str = string.rep(indent, level) - local end_indent_str = string.rep(indent, level - 1) - return string.format("{%s%s%s}", - indent_str, - table.concat(t, ","..indent_str), - end_indent_str) - end - return "{"..table.concat(t, ", ").."}" -end - function techage.vector_dump(posses) local t = {} for _,pos in ipairs(posses) do @@ -493,6 +492,10 @@ function techage.register_mobs_mods(mod) techage.RegisteredMobsMods[mod] = true end +function techage.beduino_signed_var(val) + val = val or 0 + return val >= 32768 and val - 0x10000 or val +end ------------------------------------------------------------------------------- -- Terminal history buffer @@ -561,6 +564,8 @@ function techage.add_expoint(player, number) end end +-- Delete number with: `//lua minetest.get_player_by_name(""):get_meta():set_string("techage_collider_number", "")` + function techage.on_remove_collider(player) if player and player.get_meta then local meta = player:get_meta() diff --git a/techage/basis/mark.lua b/techage/basis/mark.lua index 8058b1f..9400789 100644 --- a/techage/basis/mark.lua +++ b/techage/basis/mark.lua @@ -82,7 +82,7 @@ minetest.register_entity(":techage:region_cube", { initial_properties = { visual = "upright_sprite", textures = {"techage_cube_mark.png"}, - use_texture_alpha = true, + use_texture_alpha = techage.BLEND, physical = false, glow = 12, }, diff --git a/techage/basis/mark2.lua b/techage/basis/mark2.lua index ab1124e..449765b 100644 --- a/techage/basis/mark2.lua +++ b/techage/basis/mark2.lua @@ -70,7 +70,7 @@ minetest.register_entity(":techage:position_cube", { "techage_cube_mark.png", "techage_cube_mark.png", }, - use_texture_alpha = true, + use_texture_alpha = techage.BLEND, physical = false, visual_size = {x = 1.1, y = 1.1}, collisionbox = {-0.55,-0.55,-0.55, 0.55,0.55,0.55}, diff --git a/techage/basis/mark_lib.lua b/techage/basis/mark_lib.lua index 835555a..78458ba 100644 --- a/techage/basis/mark_lib.lua +++ b/techage/basis/mark_lib.lua @@ -97,7 +97,6 @@ minetest.register_entity(":techage:block_marker", { "techage_cube_mark.png", "techage_cube_mark.png", }, - --use_texture_alpha = true, physical = false, visual_size = {x=1.1, y=1.1}, collisionbox = {-0.55,-0.55,-0.55, 0.55,0.55,0.55}, diff --git a/techage/basis/node_states.lua b/techage/basis/node_states.lua index f866910..1b62b35 100644 --- a/techage/basis/node_states.lua +++ b/techage/basis/node_states.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -66,12 +66,14 @@ local N = techage.get_node_lvm -- TechAge machine states -- -techage.RUNNING = 1 -- in normal operation/turned on -techage.BLOCKED = 2 -- a pushing node is blocked due to a full destination inventory -techage.STANDBY = 3 -- nothing to do (e.g. no input items), or node (world) not loaded -techage.NOPOWER = 4 -- only for power consuming nodes, no operation -techage.FAULT = 5 -- any fault state (e.g. wrong source items), which can be fixed by the player -techage.STOPPED = 6 -- not operational/turned off +techage.RUNNING = 1 -- in normal operation/turned on +techage.BLOCKED = 2 -- a pushing node is blocked due to a full destination inventory +techage.STANDBY = 3 -- nothing to do (e.g. no input items), or node (world) not loaded +techage.NOPOWER = 4 -- only for power consuming nodes, no operation +techage.FAULT = 5 -- any fault state (e.g. wrong source items), which can be fixed by the player +techage.STOPPED = 6 -- not operational/turned off +techage.UNLOADED = 7 -- Map block unloaded +techage.INACTIVE = 8 -- Map block loaded but node is not actively working techage.StatesImg = { "techage_inv_button_on.png", @@ -133,13 +135,15 @@ local function has_power(pos, nvm) return true end -local function swap_node(pos, name) +local function swap_node(pos, new_name, old_name) local node = techage.get_node_lvm(pos) - if node.name == name then + if node.name == new_name then return end - node.name = name - minetest.swap_node(pos, node) + if node.name == old_name then + node.name = new_name + minetest.swap_node(pos, node) + end end -- true if node_timer should be executed @@ -174,7 +178,7 @@ function NodeStates:new(attr) cycle_time = attr.cycle_time, -- for running state standby_ticks = attr.standby_ticks, -- for standby state -- optional - countdown_ticks = attr.countdown_ticks or 1, + countdown_ticks = attr.countdown_ticks or 1, node_name_passive = attr.node_name_passive, node_name_active = attr.node_name_active, infotext_name = attr.infotext_name, @@ -220,7 +224,7 @@ function NodeStates:stop(pos, nvm) self.stop_node(pos, nvm, state) end if self.node_name_passive then - swap_node(pos, self.node_name_passive) + swap_node(pos, self.node_name_passive, self.node_name_active) end if self.infotext_name then local number = M(pos):get_string("node_number") @@ -257,7 +261,7 @@ function NodeStates:start(pos, nvm) end nvm.techage_countdown = self.countdown_ticks if self.node_name_active then - swap_node(pos, self.node_name_active) + swap_node(pos, self.node_name_active, self.node_name_passive) end if self.infotext_name then local number = M(pos):get_string("node_number") @@ -288,7 +292,7 @@ function NodeStates:standby(pos, nvm, err_string) if state == RUNNING or state == BLOCKED then nvm.techage_state = STANDBY if self.node_name_passive then - swap_node(pos, self.node_name_passive) + swap_node(pos, self.node_name_passive, self.node_name_active) end if self.infotext_name then local number = M(pos):get_string("node_number") @@ -313,7 +317,7 @@ function NodeStates:blocked(pos, nvm, err_string) if state == RUNNING then nvm.techage_state = BLOCKED if self.node_name_passive then - swap_node(pos, self.node_name_passive) + swap_node(pos, self.node_name_passive, self.node_name_active) end if self.infotext_name then local number = M(pos):get_string("node_number") @@ -337,7 +341,7 @@ function NodeStates:nopower(pos, nvm, err_string) if state ~= NOPOWER then nvm.techage_state = NOPOWER if self.node_name_passive then - swap_node(pos, self.node_name_passive) + swap_node(pos, self.node_name_passive, self.node_name_active) end if self.infotext_name then local number = M(pos):get_string("node_number") @@ -362,7 +366,7 @@ function NodeStates:fault(pos, nvm, err_string) if state == RUNNING or state == STOPPED then nvm.techage_state = FAULT if self.node_name_passive then - swap_node(pos, self.node_name_passive) + swap_node(pos, self.node_name_passive, self.node_name_active) end if self.infotext_name then local number = M(pos):get_string("node_number") @@ -479,6 +483,40 @@ function NodeStates:on_receive_message(pos, topic, payload) end end +function NodeStates:on_beduino_receive_cmnd(pos, topic, payload) + if topic == 1 then + if payload[1] == 0 then + self:stop(pos, techage.get_nvm(pos)) + return 0 + else + self:start(pos, techage.get_nvm(pos)) + return 0 + end + else + return 2 -- unknown or invalid topic + end +end + +function NodeStates:on_beduino_request_data(pos, topic, payload) + local nvm = techage.get_nvm(pos) + if topic == 128 then + return 0, techage.get_node_lvm(pos).name + elseif topic == 129 then + local node = minetest.get_node(pos) + if node.name == "ignore" then -- unloaded node? + return 0, {techage.UNLOADED} + elseif nvm.techage_state == RUNNING then + local ttl = (nvm.last_active or 0) + 2 * (self.cycle_time or 0) + if ttl < minetest.get_gametime() then + return 0, {techage.INACTIVE} + end + end + return 0, {nvm.techage_state or STOPPED} + else + return 2, "" -- topic is unknown or invalid + end +end + -- restart timer function NodeStates:on_node_load(pos) local nvm = techage.get_nvm(pos) diff --git a/techage/basis/node_store.lua b/techage/basis/node_store.lua index cce2e55..ec5b7dc 100644 --- a/techage/basis/node_store.lua +++ b/techage/basis/node_store.lua @@ -71,7 +71,7 @@ end ------------------------------------------------------------------- -- Storage scheduler ------------------------------------------------------------------- -local CYCLE_TIME = 900 -- store data every 15 min +local CYCLE_TIME = 600 -- store data every 10 min local JobQueue = {} local first = 0 local last = -1 diff --git a/techage/basis/recipe_lib.lua b/techage/basis/recipe_lib.lua index 8ff64e7..4d98ee7 100644 --- a/techage/basis/recipe_lib.lua +++ b/techage/basis/recipe_lib.lua @@ -74,9 +74,12 @@ local function input_string(recipe) return table.concat(tbl, "") end -function techage.recipes.get(nvm, rtype) +function techage.recipes.get(nvm, rtype, owner) local recipes = Recipes[rtype] or {} - return recipes[nvm.recipe_idx or 1] + if owner then + recipes = filter_recipes_based_on_points(recipes, owner) + end + return recipes[nvm.recipe_idx or 1] or recipes[1] end -- Add 4 input/output/waste recipe diff --git a/techage/basis/submenu.lua b/techage/basis/submenu.lua index 4c248dc..1aa0d63 100644 --- a/techage/basis/submenu.lua +++ b/techage/basis/submenu.lua @@ -101,7 +101,7 @@ local function generate_formspec_substring(pos, meta, form_def, player_name) elseif elem.type == "dropdown" then local l = elem.choices:split(",") if nvm.running or techage.is_running(nvm) then - local val = elem.default + local val = elem.default or "" if meta:contains(elem.name) then val = meta:get_string(elem.name) or "" end diff --git a/techage/beduino/kv_store.lua b/techage/beduino/kv_store.lua new file mode 100644 index 0000000..81424c2 --- /dev/null +++ b/techage/beduino/kv_store.lua @@ -0,0 +1,60 @@ +--[[ + + TechAge + ======= + + Copyright (C) 2019-2022 Joachim Stolberg + + AGPL v3 + See LICENSE.txt for more information + + K/V Store for the Beduino controller + +]]-- + +local COSTS = 400 + +local function ta_kv_init(cpu_pos, address, regA, regB, regC) + local nvm = techage.get_nvm(cpu_pos) + nvm.kv_store = {} + return 1, COSTS +end + +local function ta_kv_add(cpu_pos, address, regA, regB, regC) + local nvm = techage.get_nvm(cpu_pos) + local text = vm16.read_ascii(cpu_pos, regA, 32) + nvm.kv_store[text] = regB + return 1, COSTS +end + +local function ta_kv_get(cpu_pos, address, regA, regB, regC) + local nvm = techage.get_nvm(cpu_pos) + local text = vm16.read_ascii(cpu_pos, regA, 32) + return nvm.kv_store[text] or 0, COSTS +end + +local kvstore_c = [[ +// Initialize the key/value store +func ta_kv_init() { + return system(0x140, 0); +} + +// Add a key/value pair to the store +func ta_kv_add(key_str, value) { + return system(0x141, key_str, value); +} + +// Returns the value for the given key string +func ta_kv_get(key_str) { + return system(0x142, key_str); +} +]] + +minetest.register_on_mods_loaded(function() + if minetest.global_exists("beduino") and minetest.global_exists("vm16") then + beduino.lib.register_SystemHandler(0x140, ta_kv_init) + beduino.lib.register_SystemHandler(0x141, ta_kv_add) + beduino.lib.register_SystemHandler(0x142, ta_kv_get) + vm16.register_ro_file("beduino", "ta_kvstore.c", kvstore_c) + end +end) diff --git a/techage/carts/chest_cart.lua b/techage/carts/chest_cart.lua index e34e874..ff6da7d 100644 --- a/techage/carts/chest_cart.lua +++ b/techage/carts/chest_cart.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019-2020 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -159,6 +159,15 @@ techage.register_node({"techage:chest_cart"}, { return "unsupported" end end, + on_beduino_request_data = function(pos, src, topic, payload) + if topic == 131 then -- Chest State + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + return 0, {techage.get_inv_state_num(inv, "main")} + else + return 2, "" + end + end, }) Tube:set_valid_sides("techage:chest_cart", {"L", "R", "F", "B"}) diff --git a/techage/chemistry/ta4_doser.lua b/techage/chemistry/ta4_doser.lua index 30abf1e..316a3c6 100644 --- a/techage/chemistry/ta4_doser.lua +++ b/techage/chemistry/ta4_doser.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019-2021 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -360,6 +360,12 @@ techage.register_node({"techage:ta4_doser", "techage:ta4_doser_on"}, { on_recv_message = function(pos, src, topic, payload) return State:on_receive_message(pos, topic, payload) end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + return State:on_beduino_receive_cmnd(pos, topic, payload) + end, + on_beduino_request_data = function(pos, src, topic, payload) + return State:on_beduino_request_data(pos, topic, payload) + end, }) techage.recipes.register_craft_type("ta4_doser", { diff --git a/techage/coal_power_station/firebox.lua b/techage/coal_power_station/firebox.lua index c8849dd..1b732cd 100644 --- a/techage/coal_power_station/firebox.lua +++ b/techage/coal_power_station/firebox.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019-2020 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -207,6 +207,18 @@ techage.register_node({"techage:coalfirebox"}, { return "unsupported" end end, + on_beduino_request_data = function(pos, src, topic, payload) + local nvm = techage.get_nvm(pos) + if topic == 128 then + return 0, techage.get_node_lvm(pos).name + elseif topic == 129 then + return 0, {nvm.running and techage.RUNNING or techage.STOPPED} + elseif topic == 132 then + return 0, {techage.fuel.get_fuel_amount(nvm)} + else + return 2, "" + end + end, }) minetest.register_craft({ diff --git a/techage/coal_power_station/generator.lua b/techage/coal_power_station/generator.lua index e744574..fae05de 100644 --- a/techage/coal_power_station/generator.lua +++ b/techage/coal_power_station/generator.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019-2021 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -231,6 +231,17 @@ techage.register_node({"techage:generator", "techage:generator_on"}, { return State:on_receive_message(pos, topic, payload) end end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + return State:on_beduino_receive_cmnd(pos, topic, payload) + end, + on_beduino_request_data = function(pos, src, topic, payload) + local nvm = techage.get_nvm(pos) + if topic == 135 then -- Delivered Power + return 0, {math.floor((nvm.provided or 0) + 0.5)} + else + return State:on_beduino_request_data(pos, topic, payload) + end + end, }) -- used by power terminal diff --git a/techage/coal_power_station/oilfirebox.lua b/techage/coal_power_station/oilfirebox.lua index 960d581..b2cc309 100644 --- a/techage/coal_power_station/oilfirebox.lua +++ b/techage/coal_power_station/oilfirebox.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019-2021 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -132,6 +132,18 @@ techage.register_node({"techage:oilfirebox"}, { return "unsupported" end end, + on_beduino_request_data = function(pos, src, topic, payload) + local nvm = techage.get_nvm(pos) + if topic == 128 then + return 0, techage.get_node_lvm(pos).name + elseif topic == 129 then + return 0, {nvm.running and techage.RUNNING or techage.STOPPED} + elseif topic == 132 then + return 0, {fuel.get_fuel_amount(nvm)} + else + return 2, "" + end + end, }) minetest.register_craft({ diff --git a/techage/collider/detector.lua b/techage/collider/detector.lua index 2a50207..494d6b9 100644 --- a/techage/collider/detector.lua +++ b/techage/collider/detector.lua @@ -21,7 +21,9 @@ local getpos = techage.assemble.get_pos local CYCLE_TIME = 2 local TNO_MAGNETS = 22 -local PROBABILITY = 180 -- check every 20 s => 20 * 180 * 50% = 30 min +local IMPROBABILITY = 60 -- every 60 min +-- one point per 60 min: check every 20 s => factor = 60 * 3 = 180 +IMPROBABILITY = (minetest.settings:get("techage_expoint_rate_in_min") or 60) * 3 local TIME_SLOTS = 10 local Schedule = {[0] = @@ -59,7 +61,7 @@ local function terminal_message(pos, msg) end local function experience_points(pos) - if math.random(PROBABILITY) == 1 then + if math.random(IMPROBABILITY) == 1 then local owner = M(pos):get_string("owner") local own_num = M(pos):get_string("node_number") local player = minetest.get_player_by_name(owner) diff --git a/techage/doc/items.lua b/techage/doc/items.lua index abad424..b163cc8 100644 --- a/techage/doc/items.lua +++ b/techage/doc/items.lua @@ -110,6 +110,7 @@ techage.Items = { ta3_logic = "techage:ta3_logic", ta3_nodedetector = "techage:ta3_nodedetector_off", ta3_playerdetector = "techage:ta3_playerdetector_off", + ta3_lightdetector = "techage:ta3_lightdetector_off", ta3_repeater = "techage:ta3_repeater", ta3_sequencer = "techage:ta3_sequencer", ta3_timer = "techage:ta3_timer", diff --git a/techage/doc/manual_DE.lua b/techage/doc/manual_DE.lua index 0ea121b..17eecb7 100644 --- a/techage/doc/manual_DE.lua +++ b/techage/doc/manual_DE.lua @@ -124,6 +124,7 @@ techage.manual_DE.aTitel = { "3,TA3 Wagen Detektor / Cart Detector", "3,TA3 Block Detektor / Node Detector", "3,TA3 Spieler Detektor / Player Detector", + "3,TA3 Lichtdetektor", "2,TA3 Maschinen", "3,TA3 Schieber / Pusher", "3,TA3 Verteiler / Distributor", @@ -1145,9 +1146,15 @@ techage.manual_DE.aText = { "\n".. "Wird ein 'on' / 'off' Kommando an den Tür Controller II gesendet\\, entfernt bzw. setzt er die Blöcke ebenfalls.\n".. "\n".. - "Über ein 'exchange' Kommando können einzelne Böcke gesetzt\\, entfernt\\, bzw. durch andere Blöcke ersetzt werden. Die Slot-Nummer des Inventars (1 .. 16) muss als payload übergeben werden\\, also:\n".. + "Mit '$send_cmnd(node_number\\, \"exchange\"\\, 2)' können einzelne Böcke gesetzt\\, entfernt\\, bzw. durch andere Blöcke aus dem Inventar ersetzt werden. \n".. "\n".. - " $send_cmnd(node_number\\, \"exchange\"\\, 2)\n".. + "Mit '$send_cmnd(node_number\\, \"set\"\\, 2)' kann ein Block aus dem Inventory explizit gesetzt werden\\, sofern der Inventory Slot nicht leer ist.\n".. + "\n".. + "Mit '$send_cmnd(node_number\\, \"dig\"\\, 2)' kann ein Block wieder entfernt werden\\, sofern der Inventory Slot leer ist. \n".. + "\n".. + "Mit '$send_cmnd(node_number\\, \"get\"\\, 2)' wird der Name des gesetzten Blocks zurückgeliefert. \n".. + "\n".. + "Die Slot-Nummer des Inventars (1 .. 16) muss in allen drei Fällen als payload übergeben werden.\n".. "\n".. "Damit lassen sich auch ausfahrbare Treppen und ähnliches simulieren.\n".. "\n".. @@ -1159,7 +1166,7 @@ techage.manual_DE.aText = { "\n".. " - Kommando 'on' zum Abspielen eines Sounds\n".. " - Kommando 'sound ' zur Auswahl eines Sounds über den Index\n".. - " - Kommando 'gain ' zum Einstellen der Lautstärke über den '' Wert (0 bis 1.0).\n".. + " - Kommando 'gain ' zum Einstellen der Lautstärke über den '' Wert (1 bis 5).\n".. "\n".. "\n".. "\n", @@ -1198,6 +1205,11 @@ techage.manual_DE.aText = { "\n".. "\n".. "\n", + "Der Lichtdetektor sendet einen 'on'-Kommando\\, wenn der Lichtpegel des darüber liegenden Blocks einen bestimmten Pegel überschreitet\\, der über das Rechtsklickmenü eingestellt werden kann.\n".. + "Mit einen TA4 Lua Controller kann die genaue Lichtstärke mit $get_cmd(num\\, 'light_level') ermitteln werden.\n".. + "\n".. + "\n".. + "\n", "Bei TA3 existieren die gleichen Maschinen wie bei TA2\\, nur sind diese hier leistungsfähiger und benötigen Strom statt Achsenantrieb.\n".. "Im folgenden sind daher nur die unterschiedlichen\\, technischen Daten angegeben.\n".. "\n".. @@ -1680,6 +1692,7 @@ techage.manual_DE.aText = { "\n".. " - 'goto ' Zu einer Kommandozeile springen und damit den Sequenzer starten\n".. " - 'stop' Den Sequenzer anhalten\n".. + " - 'on' und 'off' als Alias für 'goto 1' bzw. 'stop'\n".. "\n".. "Das 'goto' Kommando wird nur angenommen\\, wenn der Sequenzer gestoppt ist.\n".. "\n".. @@ -1907,7 +1920,7 @@ techage.manual_DE.aText = { "\n".. "Der TA4 Schieber besitzt zwei zusätzliche Kommandos für den Lua Controller:\n".. "\n".. - " - 'config' dient zur Konfiguration des Schiebers\\, analog zum manuellen Konfiguration über das Menü.\nBeispiel: '$send_cmnd(1234\\, \"config\"\\, \"default:dirt\")'\n".. + " - 'config' dient zur Konfiguration des Schiebers\\, analog zum manuellen Konfiguration über das Menü.\nBeispiel: '$send_cmnd(1234\\, \"config\"\\, \"default:dirt\")'\nMit '$send_cmnd(1234\\, \"config\"\\, \"\")' wird die Konfiguration gelöscht\n".. " - 'pull' dient zum Absetzen eines Auftrags an den Schieber:\nBeispiel: '$send_cmnd(1234\\, \"pull\"\\, \"default:dirt 8\")'\nAls Nummer sind Werte von 1 bis 12 zulässig. Danach geht der Schieber wieder in den 'stopped' Mode und sendet ein \"off\" Kommando zurück an den Sender des \"pull\" Kommandos.\n".. "\n".. "\n".. @@ -2240,6 +2253,7 @@ techage.manual_DE.aItemName = { "ta3_cartdetector", "ta3_nodedetector", "ta3_playerdetector", + "ta3_lightdetector", "ta3_grinder", "ta3_pusher", "ta3_distributor", @@ -2511,6 +2525,7 @@ techage.manual_DE.aPlanTable = { "", "", "", + "", "ta4_windturbine", "", "", diff --git a/techage/doc/manual_EN.lua b/techage/doc/manual_EN.lua index 0abb1d6..4ec4352 100644 --- a/techage/doc/manual_EN.lua +++ b/techage/doc/manual_EN.lua @@ -124,6 +124,7 @@ techage.manual_EN.aTitel = { "3,TA3 Cart Detector", "3,TA3 Block Detector", "3,TA3 Player Detector", + "3,TA3 Light Detector", "2,TA3 Machines", "3,TA3 Pusher", "3,TA3 Distributor", @@ -1143,9 +1144,15 @@ techage.manual_EN.aText = { "\n", "The Door Controller II can remove and set all types of blocks. To teach in the Door Controller II\\, the \"Record\" button must be pressed. Then all blocks that should be part of the door / gate must be clicked. Then the \"Done\" button must be pressed. Up to 16 blocks can be selected. The removed blocks are saved in the controller's inventory. The function of the controller can be tested manually using the \"Remove\" or \"Set\" buttons. If an 'on' /'off' command is sent to the Door Controller II\\, it removes or sets the blocks as well.\n".. "\n".. - "Individual blocks can be set\\, removed or replaced by other blocks via an 'exchange' command. The slot number of the inventory (1 .. 16) must be transferred as payload\\, i.e.:\n".. + "With '$send_cmnd(node_number\\, \"exchange\"\\, 2)' individual blocks can be set\\, removed or replaced by other blocks from the inventory. \n".. "\n".. - " $send_cmnd(node_number\\, \"exchange\"\\, 2)\n".. + "With '$send_cmnd(node_number\\, \"set\"\\, 2)' a block from the inventory can be set explicitly\\, as long as the inventory slot is not empty.\n".. + "\n".. + "A block can be removed again with '$send_cmnd(node_number\\, \"dig\"\\, 2)' if the inventory slot is empty. \n".. + "\n".. + "The name of the set block is returned with '$send_cmnd(node_number\\, \"get\"\\, 2)'.\n".. + "\n".. + "The slot number of the inventory (1 .. 16) must be passed as payload in all three cases.\n".. "\n".. "This can also be used to simulate extendable stairs and the like. \n".. "\n".. @@ -1157,7 +1164,7 @@ techage.manual_EN.aText = { "\n".. " - Command 'on' to play a sound\n".. " - Command 'sound ' to select a sound via the index\n".. - " - Command 'gain ' to adjust the volume via the '' value (0 to 1.0).\n".. + " - Command 'gain ' to adjust the volume via the '' value (1 to 5).\n".. "\n".. "\n".. "\n", @@ -1196,6 +1203,11 @@ techage.manual_EN.aText = { "\n".. "\n".. "\n", + "The light detector sends an 'on' command if the light level of the block above exceeds a certain level\\, which can be set through the right-click menu.\n".. + "If you have a TA4 Lua Controller\\, you can get the exact light level with $get_cmd(num\\, 'light_level')\n".. + "\n".. + "\n".. + "\n", "TA3 has the same machines as TA2\\, only these are more powerful and require electricity instead of axis drive.\n".. "Therefore\\, only the different technical data are given below.\n".. "\n".. @@ -1676,6 +1688,7 @@ techage.manual_EN.aText = { "\n".. " - 'goto ' Jump to a command line and start the sequencer\n".. " - 'stop' Stop the sequencer\n".. + " - 'on' and 'off' as aliases for 'goto 1' resp. 'stop'\n".. "\n".. "The 'goto' command is only accepted when the sequencer is stopped.\n".. "\n".. @@ -1903,7 +1916,7 @@ techage.manual_EN.aText = { "\n".. "The TA4 pusher has two additional commands for the Lua controller:\n".. "\n".. - " - 'config' is used to configure the pusher\\, analogous to manual configuration via the menu.\nExample: '$send_cmnd(1234\\, \"config\"\\, \"default: dirt\")'\n".. + " - 'config' is used to configure the pusher\\, analogous to manual configuration via the menu.\nExample: '$send_cmnd(1234\\, \"config\"\\, \"default: dirt\")'\nWith '$send_cmnd(1234\\, \"config\"\\, \"\")' the configuration is deleted\n".. " - 'pull' is used to send an order to the pusher:\nExample: '$send_cmnd(1234\\, \"pull\"\\, \"default: dirt 8\")'\nValues ​​from 1 to 12 are permitted as numbers. Then the pusher goes back to 'stopped' mode and sends an\" off \"command back to the transmitter of the\" pull \"command.\n".. "\n".. "\n".. @@ -2235,6 +2248,7 @@ techage.manual_EN.aItemName = { "ta3_cartdetector", "ta3_nodedetector", "ta3_playerdetector", + "ta3_lightdetector", "ta3_grinder", "ta3_pusher", "ta3_distributor", @@ -2505,6 +2519,7 @@ techage.manual_EN.aPlanTable = { "", "", "", + "", "ta4_windturbine", "", "", diff --git a/techage/doc/plans.lua b/techage/doc/plans.lua index 3cf0476..282997c 100644 --- a/techage/doc/plans.lua +++ b/techage/doc/plans.lua @@ -511,8 +511,6 @@ techage.ConstructionPlans["ta5_teleport"] = { {false, false, false, false, false, false, false, false, false, false, false}, {false, false, false, false, false, false, false, false, false, false, false}, {false, TANK4, PUMP4, TELEP, false, ARROW, false, TELEP, PIPEH, TANK4, false}, - {false, false, false, false, false, false, false, false, false, false, false}, - {false, TANK4, PIPEH, TELEP, false, ARROW, false, TELEP, PUMP4, TANK4, false}, } -- diff --git a/techage/energy_storage/heatexchanger2.lua b/techage/energy_storage/heatexchanger2.lua index 2478288..dc4b1d3 100644 --- a/techage/energy_storage/heatexchanger2.lua +++ b/techage/energy_storage/heatexchanger2.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019-2021 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -356,6 +356,37 @@ techage.register_node({"techage:heatexchanger2"}, { return "unsupported" end end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + local nvm = techage.get_nvm(pos) + if topic == 1 and payload[1] == 1 then + start_node(pos, techage.get_nvm(pos)) + return 0 + elseif topic == 1 and payload[1] == 0 then + stop_node(pos, techage.get_nvm(pos)) + return 0 + else + return 2, "" + end + end, + on_beduino_request_data = function(pos, src, topic, payload) + local nvm = techage.get_nvm(pos) + if topic == 128 then + return 0, techage.get_node_lvm(pos).name + elseif topic == 129 then -- State + if techage.is_running(nvm) then + return 0, {techage.RUNNING} + else + return 0, {techage.STOPPED} + end + elseif topic == 135 then -- Delivered Power + local data = power.get_network_data(pos, Cable, DOWN) + return 0, {data.consumed - data.provided} + elseif topic == 134 then -- Tank Load Percent + return 0, {techage.power.percent(nvm.capa_max, nvm.capa)} + else + return 2, "" + end + end, on_node_load = function(pos, node) local nvm = techage.get_nvm(pos) if techage.is_running(nvm) then diff --git a/techage/fermenter/gasflare.lua b/techage/fermenter/gasflare.lua index 4f4c741..c11b38d 100644 --- a/techage/fermenter/gasflare.lua +++ b/techage/fermenter/gasflare.lua @@ -74,7 +74,7 @@ for idx,ratio in ipairs(lRatio) do end end, - use_texture_alpha = true, + use_texture_alpha = techage.BLEND, inventory_image = "techage_flame.png", paramtype = "light", light_source = 13, diff --git a/techage/furnace/firebox.lua b/techage/furnace/firebox.lua index e933d08..e3678db 100644 --- a/techage/furnace/firebox.lua +++ b/techage/furnace/firebox.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019-2021 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -173,6 +173,18 @@ techage.register_node({"techage:furnace_firebox", "techage:furnace_firebox_on"}, return "unsupported" end end, + on_beduino_request_data = function(pos, src, topic, payload) + local nvm = techage.get_nvm(pos) + if topic == 128 then + return 0, techage.get_node_lvm(pos).name + elseif topic == 129 then -- State + return 0, {nvm.running and techage.RUNNING or techage.STOPPED} + elseif topic == 132 then -- Fuel Level + return 0, {fuel.get_fuel_amount(nvm)} + else + return 2, "" + end + end, -- called from furnace_top on_transfer = function(pos, in_dir, topic, payload) local nvm = techage.get_nvm(pos) diff --git a/techage/furnace/furnace_top.lua b/techage/furnace/furnace_top.lua index e49e748..b1c8aff 100644 --- a/techage/furnace/furnace_top.lua +++ b/techage/furnace/furnace_top.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019-2020 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -257,6 +257,17 @@ local tubing = { 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 == 141 then -- Furnace Output + local nvm = techage.get_nvm(pos) + return 0, string.split(nvm.output or "unknown", " ")[1] + else + return CRD(pos).State:on_beduino_request_data(pos, topic, payload) + end + end, } local _, node_name_ta3, _ = diff --git a/techage/fusion_reactor/controller.lua b/techage/fusion_reactor/controller.lua index 848cdaf..653602d 100644 --- a/techage/fusion_reactor/controller.lua +++ b/techage/fusion_reactor/controller.lua @@ -46,6 +46,7 @@ local function count_trues(t) end local function nucleus(t) + t = techage.tbl_filter(t, function(v, k, t) return type(v) == "table" end) if #t == 4 then if vector.equals(t[1], t[2]) and vector.equals(t[3], t[4]) then return true @@ -268,6 +269,12 @@ techage.register_node({"techage:ta5_fr_controller_pas", "techage:ta5_fr_controll on_recv_message = function(pos, src, topic, payload) return State:on_receive_message(pos, topic, payload) end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + return State:on_beduino_receive_cmnd(pos, topic, payload) + end, + on_beduino_request_data = function(pos, src, topic, payload) + return State:on_beduino_request_data(pos, topic, payload) + end, }) power.register_nodes({"techage:ta5_fr_controller_pas", "techage:ta5_fr_controller_act"}, Cable, "con", {"L", "R"}) diff --git a/techage/fusion_reactor/heatexchanger2.lua b/techage/fusion_reactor/heatexchanger2.lua index 7ea1df2..999efbb 100644 --- a/techage/fusion_reactor/heatexchanger2.lua +++ b/techage/fusion_reactor/heatexchanger2.lua @@ -183,7 +183,7 @@ local function steam_management(pos, nvm) nvm.temperature = math.min(nvm.temperature + 10, 100) elseif resp ~= true then State:fault(pos, nvm, resp) - stop_node(pos, nvm) + State:stop(pos, nvm) return false end @@ -325,15 +325,44 @@ techage.register_node({"techage:ta5_heatexchanger2"}, { local data = power.get_network_data(pos, Cable, DOWN) return data.consumed - data.provided elseif topic == "on" then - start_node(pos, techage.get_nvm(pos)) + State:start(pos, nvm) return true elseif topic == "off" then - stop_node(pos, techage.get_nvm(pos)) + State:stop(pos, nvm) return true else return "unsupported" end end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + local nvm = techage.get_nvm(pos) + if topic == 1 and payload[1] == 1 then + start_node(pos, techage.get_nvm(pos)) + return 0 + elseif topic == 1 and payload[1] == 0 then + stop_node(pos, techage.get_nvm(pos)) + return 0 + else + return 2, "" + end + end, + on_beduino_request_data = function(pos, src, topic, payload) + local nvm = techage.get_nvm(pos) + if topic == 128 then + return 0, techage.get_node_lvm(pos).name + elseif topic == 129 then -- State + if techage.is_running(nvm) then + return 0, {techage.RUNNING} + else + return 0, {techage.STOPPED} + end + elseif topic == 135 then -- Delivered Power + local data = power.get_network_data(pos, Cable, DOWN) + return 0, {data.consumed - data.provided} + else + return 2, "" + end + end, on_node_load = function(pos, node) local nvm = techage.get_nvm(pos) if techage.is_running(nvm) then @@ -344,7 +373,7 @@ techage.register_node({"techage:ta5_heatexchanger2"}, { -- Attempt to restart the system as the heat exchanger goes into error state -- when parts of the storage block are unloaded. if nvm.techage_state == techage.FAULT then - start_node(pos, nvm) + State:start(pos, nvm) end end, }) diff --git a/techage/fusion_reactor/ta5_pump.lua b/techage/fusion_reactor/ta5_pump.lua index fab96a0..a522bc3 100644 --- a/techage/fusion_reactor/ta5_pump.lua +++ b/techage/fusion_reactor/ta5_pump.lua @@ -170,6 +170,12 @@ techage.register_node({"techage:ta5_pump", "techage:ta5_pump_on"}, { on_recv_message = function(pos, src, topic, payload) return State:on_receive_message(pos, topic, payload) end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + return State:on_beduino_receive_cmnd(pos, topic, payload) + end, + on_beduino_request_data = function(pos, src, topic, payload) + return State:on_beduino_request_data(pos, topic, payload) + end, }) -- Pumps have to provide one output and one input side diff --git a/techage/hydrogen/electrolyzer.lua b/techage/hydrogen/electrolyzer.lua index c3cc336..155091f 100644 --- a/techage/hydrogen/electrolyzer.lua +++ b/techage/hydrogen/electrolyzer.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019-2021 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -197,11 +197,11 @@ local tool_config = { }, { type = "dropdown", - choices = "0%,20%,40%,60%,80%", + choices = "0%,20%,40%,60%,80%,98%", name = "turnoff", label = S("Turnoff point"), tooltip = S("If the charge of the storage\nsystem exceeds the configured value,\nthe block switches off"), - default = "0%", + default = "98%", }, } @@ -332,11 +332,24 @@ techage.register_node({"techage:ta4_electrolyzer", "techage:ta4_electrolyzer_on" return State:on_receive_message(pos, topic, payload) end end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + return State:on_beduino_receive_cmnd(pos, topic, payload) + end, + on_beduino_request_data = function(pos, src, topic, payload) + local nvm = techage.get_nvm(pos) + if topic == 134 and payload[1] == 1 then + return 0, {techage.power.percent(CAPACITY, (nvm.liquid and nvm.liquid.amount) or 0)} + elseif topic == 135 then + return 0, {math.floor((nvm.provided or 0) + 0.5)} + else + return State:on_beduino_request_data(pos, topic, payload) + end + end, on_node_load = function(pos, node) local meta = M(pos) if not meta:contains("reduction") then meta:set_string("reduction", "100%") - meta:set_string("turnoff", "0%") + meta:set_string("turnoff", "100%") end end, }) diff --git a/techage/hydrogen/fuelcell.lua b/techage/hydrogen/fuelcell.lua index 81301af..791558c 100644 --- a/techage/hydrogen/fuelcell.lua +++ b/techage/hydrogen/fuelcell.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019-2021 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -304,6 +304,19 @@ techage.register_node({"techage:ta4_fuelcell", "techage:ta4_fuelcell_on"}, { return State:on_receive_message(pos, topic, payload) end end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + return State:on_beduino_receive_cmnd(pos, topic, payload) + end, + on_beduino_request_data = function(pos, src, topic, payload) + local nvm = techage.get_nvm(pos) + if topic == 134 and payload[1] == 1 then + return 0, {techage.power.percent(CAPACITY, (nvm.liquid and nvm.liquid.amount) or 0)} + elseif topic == 135 then + return 0, {math.floor((nvm.provided or 0) + 0.5)} + else + return State:on_beduino_request_data(pos, topic, payload) + end + end, }) control.register_nodes({"techage:ta4_fuelcell", "techage:ta4_fuelcell_on"}, { diff --git a/techage/icta_controller/battery.lua b/techage/icta_controller/battery.lua index 24c710c..1b4082e 100644 --- a/techage/icta_controller/battery.lua +++ b/techage/icta_controller/battery.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019-2020 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -176,4 +176,12 @@ techage.register_node({"techage:ta4_battery"}, { return "unsupported" end end, + on_beduino_request_data = function(pos, src, topic, payload) + if topic == 134 then + local meta = minetest.get_meta(pos) + return 0, {calc_percent(meta:get_int("content"))} + else + return 2, "" + end + end, }) diff --git a/techage/icta_controller/commands.lua b/techage/icta_controller/commands.lua index 09d1b47..db5c5bc 100644 --- a/techage/icta_controller/commands.lua +++ b/techage/icta_controller/commands.lua @@ -153,7 +153,7 @@ techage.icta_register_condition("input", { return env.input[data.number] end local result = function(val) - return techage.compare(val, data.value, data.operand) + return techage.compare(val, tonumber(data.value) or 0, data.operand) end return condition, result end, @@ -196,7 +196,7 @@ techage.icta_register_condition("state", { return techage.send_single(environ.number, data.number, "state") end local result = function(val) - return techage.compare(val, data.value, data.operand) + return techage.compare(val, tonumber(data.value) or 0, data.operand) end return condition, result end, @@ -238,7 +238,7 @@ techage.icta_register_condition("fuel", { return techage.send_single(environ.number, data.number, "fuel") end local result = function(val) - return techage.compare(val, tonumber(data.value), data.operand) + return techage.compare(val, tonumber(data.value) or 0, data.operand) end return condition, result end, @@ -280,7 +280,7 @@ techage.icta_register_condition("load", { return techage.send_single(environ.number, data.number, "load") end local result = function(val) - return techage.compare(val, tonumber(data.value), data.operand) + return techage.compare(val, tonumber(data.value) or 0, data.operand) end return condition, result end, @@ -322,7 +322,7 @@ techage.icta_register_condition("depth", { return techage.send_single(environ.number, data.number, "depth") end local result = function(val) - return techage.compare(val, tonumber(data.value), data.operand) + return techage.compare(val, tonumber(data.value) or 0, data.operand) end return condition, result end, @@ -364,7 +364,7 @@ techage.icta_register_condition("delivered", { return techage.send_single(environ.number, data.number, "delivered") end local result = function(val) - return techage.compare(val, tonumber(data.value), data.operand) + return techage.compare(val, tonumber(data.value) or 0, data.operand) end return condition, result end, @@ -408,7 +408,7 @@ techage.icta_register_condition("chest", { return techage.send_single(environ.number, data.number, "state") end local result = function(val) - return techage.compare(val, data.value, data.operand) + return techage.compare(val, tonumber(data.value) or 0, data.operand) end return condition, result end, @@ -449,7 +449,7 @@ techage.icta_register_condition("signaltower", { return techage.send_single(environ.number, data.number, "state") end local result = function(val) - return techage.compare(val, data.value, data.operand) + return techage.compare(val, tonumber(data.value) or 0, data.operand) end return condition, result end, @@ -919,7 +919,7 @@ techage.icta_register_condition("get_filter", { return techage.send_single(environ.number, data.number, "port", data.color) end local result = function(val) - return techage.compare(val, data.value, data.operand) + return techage.compare(val, tonumber(data.value) or 0, data.operand) end return condition, result end, diff --git a/techage/icta_controller/controller.lua b/techage/icta_controller/controller.lua index 7c3292e..6c75af8 100644 --- a/techage/icta_controller/controller.lua +++ b/techage/icta_controller/controller.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019-2020 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -444,4 +444,30 @@ techage.register_node({"techage:ta4_icta_controller"}, { return "unsupported" end end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + local meta = minetest.get_meta(pos) + local number = meta:get_string("number") + local state = meta:get_int("state") + + if state == techage.RUNNING and topic == 1 and payload[1] == 1 then + set_input(pos, number, src, topic) + elseif state == techage.RUNNING and topic == 1 and payload[1] == 0 then + set_input(pos, number, src, topic) + else + return 2 + end + return 0 + end, + on_beduino_request_data = function(pos, src, topic, payload) + local meta = minetest.get_meta(pos) + local number = meta:get_string("number") + local state = meta:get_int("state") + + if topic == 129 then + local state = meta:get_int("state") or 0 + return 0, {state or techage.STOPPED} + else + return 2, "" + end + end, }) diff --git a/techage/icta_controller/display.lua b/techage/icta_controller/display.lua index e2a182d..1b1b1bc 100644 --- a/techage/icta_controller/display.lua +++ b/techage/icta_controller/display.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019-2020 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -211,13 +211,21 @@ function techage.display.add_line(pos, payload, cycle_time) table.insert(nvm.text, str) end -function techage.display.write_row(pos, payload, cycle_time) +function techage.display.write_row(pos, payload, cycle_time, beduino) local nvm = techage.get_nvm(pos) local mem = techage.get_mem(pos) + local str, row + nvm.text = nvm.text or {} mem.ticks = mem.ticks or 0 - local str = tostring(payload.get("str")) or "oops" - local row = tonumber(payload.get("row")) or 1 + + if beduino then + row = tonumber(payload:sub(1,1) or "1") or 1 + str = payload:sub(2) or "oops" + else + str = tostring(payload.get("str")) or "oops" + row = tonumber(payload.get("row")) or 1 + end if mem.ticks == 0 then mem.ticks = cycle_time @@ -254,6 +262,18 @@ techage.register_node({"techage:ta4_display"}, { techage.display.clear_screen(pos, 1) end end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + if topic == 67 then -- add one line and scroll if necessary + techage.display.add_line(pos, payload, 1) + elseif topic == 68 then -- overwrite the given row + techage.display.write_row(pos, payload, 1, true) + elseif topic == 17 then -- clear the screen + techage.display.clear_screen(pos, 1) + else + return 2 + end + return 0 + end, }) techage.register_node({"techage:ta4_displayXL"}, { @@ -266,6 +286,18 @@ techage.register_node({"techage:ta4_displayXL"}, { techage.display.clear_screen(pos, 2) end end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + if topic == 67 then -- add one line and scroll if necessary + techage.display.add_line(pos, payload, 2) + elseif topic == 68 then -- overwrite the given row + techage.display.write_row(pos, payload, 2, true) + elseif topic == 17 then -- clear the screen + techage.display.clear_screen(pos, 2) + else + return 2 + end + return 0 + end, }) lcdlib.register_display_entity("techage:display_entity") diff --git a/techage/icta_controller/signaltower.lua b/techage/icta_controller/signaltower.lua index 6377494..13b0d8e 100644 --- a/techage/icta_controller/signaltower.lua +++ b/techage/icta_controller/signaltower.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019-2020 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -132,4 +132,27 @@ techage.register_node({"techage:ta4_signaltower", return meta:get_string("state") end end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + if topic == 2 then + local color = ({"green", "amber", "red"})[payload[1]] + local node = minetest.get_node(pos) + if color then + switch_on(pos, node, color) + else + switch_off(pos, node) + end + return 0 + else + return 2 -- unknown or invalid topic + end + end, + on_beduino_request_data = function(pos, src, topic, payload) + if topic == 130 then + local meta = minetest.get_meta(pos) + local color = ({off = 0, green = 1, amber = 2, red = 3})[meta:get_string("state")] or 1 + return 0, {color} + else + return 2, "" -- unknown or invalid topic + end + end, }) diff --git a/techage/init.lua b/techage/init.lua index 7674ca0..40d9d1f 100644 --- a/techage/init.lua +++ b/techage/init.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019-2021 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -13,7 +13,7 @@ techage = {} -- Version for compatibility checks, see readme.md/history -techage.version = 1.07 +techage.version = 1.08 if minetest.global_exists("tubelib") then minetest.log("error", "[techage] Techage can't be used together with the mod tubelib!") @@ -285,6 +285,7 @@ dofile(MP.."/logic/timer.lua") dofile(MP.."/logic/lua_logic.lua") -- old dofile(MP.."/logic/logic_block.lua") -- new dofile(MP.."/logic/node_detector.lua") +dofile(MP.."/logic/light_detector.lua") dofile(MP.."/logic/player_detector.lua") dofile(MP.."/logic/mba_detector.lua") dofile(MP.."/logic/cart_detector.lua") @@ -412,8 +413,8 @@ dofile(MP.."/fusion_reactor/generator.lua") dofile(MP.."/fusion_reactor/turbine.lua") dofile(MP.."/fusion_reactor/ta5_pump.lua") +-- Beduino extensions +dofile(MP.."/beduino/kv_store.lua") + -- Prevent other mods from using IE techage.IE = nil - - -function techage.icta_register_condition(key, tData) end diff --git a/techage/items/moreblocks.lua b/techage/items/moreblocks.lua index 67bfa18..66c323a 100644 --- a/techage/items/moreblocks.lua +++ b/techage/items/moreblocks.lua @@ -13,7 +13,7 @@ ]]-- local function register_alias(name) - minetest.register_alias("stairs:slab_" ..name, "techage:slab_" ..name) + --minetest.register_alias("stairs:slab_" ..name, "techage:slab_" ..name) minetest.register_alias("stairs:slab_" ..name.. "_inverted", "techage:slab_" ..name.. "_inverted") minetest.register_alias("stairs:slab_" ..name.. "_wall", "techage:slab_" ..name.. "_wall") minetest.register_alias("stairs:slab_" ..name.. "_quarter", "techage:slab_" ..name.. "_quarter") @@ -22,7 +22,7 @@ local function register_alias(name) minetest.register_alias("stairs:slab_" ..name.. "_three_quarter", "techage:slab_" ..name.. "_three_quarter") minetest.register_alias("stairs:slab_" ..name.. "_three_quarter_inverted", "techage:slab_" ..name.. "_three_quarter_inverted") minetest.register_alias("stairs:slab_" ..name.. "_three_quarter_wall", "techage:slab_" ..name.. "_three_quarter_wall") - minetest.register_alias("stairs:stair_" ..name, "techage:stair_" ..name) + --minetest.register_alias("stairs:stair_" ..name, "techage:stair_" ..name) minetest.register_alias("stairs:stair_" ..name.. "_inverted", "techage:stair_" ..name.. "_inverted") minetest.register_alias("stairs:stair_" ..name.. "_wall", "techage:stair_" ..name.. "_wall") minetest.register_alias("stairs:stair_" ..name.. "_wall_half", "techage:stair_" ..name.. "_wall_half") diff --git a/techage/items/registered_nodes.lua b/techage/items/registered_nodes.lua index a6a6bae..bf29591 100644 --- a/techage/items/registered_nodes.lua +++ b/techage/items/registered_nodes.lua @@ -64,4 +64,7 @@ techage.register_mobs_mods("wildlife") techage.register_mobs_mods("mobs_skeletons") techage.register_mobs_mods("mobs_dwarves") techage.register_mobs_mods("mobf_trader") -techage.register_mobs_mods("ts_vehicles") +techage.register_mobs_mods("ts_vehicles_cars") + +-- Used as e.g. crane cable +techage.register_simple_nodes({"techage:power_lineS"}, true) \ No newline at end of file diff --git a/techage/liquids/pump.lua b/techage/liquids/pump.lua index 868d81a..99f0b51 100644 --- a/techage/liquids/pump.lua +++ b/techage/liquids/pump.lua @@ -284,6 +284,17 @@ techage.register_node({"techage:t4_pump", "techage:t4_pump_on"}, { return State4:on_receive_message(pos, topic, payload) end end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + return State4:on_beduino_receive_cmnd(pos, topic, payload) + end, + on_beduino_request_data = function(pos, src, topic, payload) + if topic == 137 then -- Total Flow Rate + local nvm = techage.get_nvm(pos) + return 0, {nvm.flowrate or 0} + else + return State4:on_beduino_request_data(pos, topic, payload) + end + end, }) -- Pumps have to provide one output and one input side diff --git a/techage/liquids/silo.lua b/techage/liquids/silo.lua index 0ef45c8..254b246 100644 --- a/techage/liquids/silo.lua +++ b/techage/liquids/silo.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019-2021 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -312,6 +312,25 @@ techage.register_node({"techage:ta3_silo", "techage:ta4_silo"}, { return "unsupported" end end, + on_beduino_request_data = function(pos, src, topic, payload) + if topic == 131 then -- Chest State + local meta = M(pos) + local inv = meta:get_inventory() + return 0, {techage.get_inv_state_num(inv, "main")} + elseif topic == 134 then + local inv = M(pos):get_inventory() + local nvm = techage.get_nvm(pos) + nvm.item_count = nvm.item_count or get_item_count(pos) + nvm.capa = nvm.capa or get_silo_capa(pos) + if payload[1] == 1 then + return 0, {techage.power.percent(nvm.capa, nvm.item_count)} + else + return 0, {nvm.item_count} + end + else + return 2, "" + end + end, on_node_load = function(pos) local nvm = techage.get_nvm(pos) nvm.item_count = nil diff --git a/techage/liquids/valve.lua b/techage/liquids/valve.lua index 8c9edd7..bf59c35 100644 --- a/techage/liquids/valve.lua +++ b/techage/liquids/valve.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019-2021 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -139,6 +139,29 @@ techage.register_node({"techage:ta3_valve_closed", "techage:ta3_valve_open"}, { return "unsupported" end end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + local node = techage.get_node_lvm(pos) + if topic == 1 and payload[1] == 1 and node.name == "techage:ta3_valve_closed" then + liquid.turn_valve_on(pos, Pipe, "techage:ta3_valve_closed", "techage:ta3_valve_open") + return 0 + elseif topic == 1 and payload[1] == 0 and node.name == "techage:ta3_valve_open" then + liquid.turn_valve_off(pos, Pipe, "techage:ta3_valve_closed", "techage:ta3_valve_open") + return 0 + else + return 2, "" + end + end, + on_beduino_request_data = function(pos, src, topic, payload) + local node = techage.get_node_lvm(pos) + if topic == 142 then -- State + if node.name == "techage:ta3_valve_open" then + return 0, {1} + end + return 0, {0} + else + return 2, "" + end + end, }) liquid.register_nodes({"techage:ta3_valve_closed"}, Pipe, "special", {}, {}) diff --git a/techage/liquids/waterpump.lua b/techage/liquids/waterpump.lua index 82ecf08..6911493 100644 --- a/techage/liquids/waterpump.lua +++ b/techage/liquids/waterpump.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019-2020 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -158,4 +158,10 @@ techage.register_node({"techage:t4_waterpump"}, { on_recv_message = function(pos, src, topic, payload) return State:on_receive_message(pos, topic, payload) end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + return State:on_beduino_receive_cmnd(pos, topic, payload) + end, + on_beduino_request_data = function(pos, src, topic, payload) + return State:on_beduino_request_data(pos, topic, payload) + end, }) diff --git a/techage/locale/techage.de.tr b/techage/locale/techage.de.tr index b59c664..6ce7269 100644 --- a/techage/locale/techage.de.tr +++ b/techage/locale/techage.de.tr @@ -127,6 +127,7 @@ Command=Kommando ### button.lua ### ### cart_detector.lua ### ### detector.lua ### +### light_detector.lua ### ### lua_logic.lua ### ### mesecons_converter.lua ### ### node_detector.lua ### @@ -178,6 +179,7 @@ TA4 4x Button=TA4 4x Taster TA3 Cart Detector=TA3 Wagen Detektor ### cart_detector.lua ### +### light_detector.lua ### ### node_detector.lua ### accept=akzeptieren @@ -732,6 +734,11 @@ Block has an@nadditional wrench menu=Block besitzt ein@nzusätzliches@nSchrauben connected with=verbunden mit +### light_detector.lua ### + +Send signal if light level is above:=Sende ein Signal wenn der Lichtwert größer ist als: +TA3 Light Detector=TA3 Lichtdetektor + ### lighter.lua ### TA1 Lighter=TA1 Anzünder diff --git a/techage/locale/template.txt b/techage/locale/template.txt index 63384bd..6067446 100644 --- a/techage/locale/template.txt +++ b/techage/locale/template.txt @@ -127,6 +127,7 @@ Command= ### button.lua ### ### cart_detector.lua ### ### detector.lua ### +### light_detector.lua ### ### lua_logic.lua ### ### mesecons_converter.lua ### ### node_detector.lua ### @@ -178,6 +179,7 @@ TA4 4x Button= TA3 Cart Detector= ### cart_detector.lua ### +### light_detector.lua ### ### node_detector.lua ### accept= @@ -732,6 +734,11 @@ Block has an@nadditional wrench menu= connected with= +### light_detector.lua ### + +Send signal if light level is above:= +TA3 Light Detector= + ### lighter.lua ### TA1 Lighter= diff --git a/techage/logic/button.lua b/techage/logic/button.lua index 9778e6d..c04d1f3 100644 --- a/techage/logic/button.lua +++ b/techage/logic/button.lua @@ -55,7 +55,10 @@ local function switch_off(pos, is_button) elseif name == "techage:ta4_button_on" then logic.swap_node(pos, "techage:ta4_button_off") end - logic.send_off(pos, M(pos)) + local meta = M(pos) + if not meta:contains("command") or meta:get_string("command") == "on" then + logic.send_off(pos, M(pos)) + end if not is_button then minetest.sound_play("techage_button", { pos = pos, @@ -149,6 +152,9 @@ local function on_rightclick_on(pos, node, clicker) if fixed == "true" then if can_access(pos, clicker) then switch_on(pos) + local mem = techage.get_mem(pos) + mem.clicker = clicker and clicker:get_player_name() + mem.time = math.floor(minetest.get_us_time() / 100000) end end end @@ -331,3 +337,31 @@ minetest.register_craft({ {"", "", ""}, }, }) + +techage.register_node({ + "techage:ta4_button_off", "techage:ta4_button_on", + }, { + on_recv_message = function(pos, src, topic, payload) + if topic == "name" then + local mem = techage.get_mem(pos) + return mem.clicker or "" + elseif topic == "time" then + local mem = techage.get_mem(pos) + return mem.time or 0 + else + return "unsupported" + end + end, + on_beduino_request_data = function(pos, src, topic, payload) + if topic == 144 then -- Player Name + local mem = techage.get_mem(pos) + return 0, mem.clicker + elseif topic == 149 then --time + local mem = techage.get_mem(pos) + return 0, {mem.time or 0} + else + return 2, "" + end + end, + } +) diff --git a/techage/logic/cart_detector.lua b/techage/logic/cart_detector.lua index 244e40f..99c12b6 100644 --- a/techage/logic/cart_detector.lua +++ b/techage/logic/cart_detector.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019-2020 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -151,6 +151,28 @@ techage.register_node({"techage:ta3_cartdetector_off", "techage:ta3_cartdetector return "unsupported" end end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + if topic == 1 then + local node = minetest.get_node(pos) + local dir = minetest.facedir_to_dir(node.param2) + minecart.punch_cart(pos, nil, 1.6, dir) + return 0 + else + return 2 + end + end, + on_beduino_request_data = function(pos, src, topic, payload) + if topic == 142 then -- Binary State + local node = techage.get_node_lvm(pos) + if node.name == "techage:ta3_cartdetector_on" then + return 0, {1} + else + return 0, {0} + end + else + return 2, "" + end + end, on_node_load = function(pos) minetest.get_node_timer(pos):start(CYCLE_TIME) end, diff --git a/techage/logic/collector.lua b/techage/logic/collector.lua index d50a1e0..6083952 100644 --- a/techage/logic/collector.lua +++ b/techage/logic/collector.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2017-2020 Joachim Stolberg + Copyright (C) 2017-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -24,6 +24,7 @@ local CYCLE_TIME = 1 local tStates = {stopped = 0, running = 0, standby = 1, blocked = 2, nopower = 3, fault = 4} local tDropdownPos = {["1 standby"] = 1, ["2 blocked"] = 2, ["3 nopower"] = 3, ["4 fault"] = 4} local lStates = {[0] = "stopped", "standby", "blocked", "nopower", "fault"} +local TaStates = {running = 1, blocked = 2, standby = 3, nopower = 4, fault = 5, stopped = 6} local function formspec(nvm, meta) nvm.poll_numbers = nvm.poll_numbers or {} @@ -200,13 +201,21 @@ minetest.register_craft({ techage.register_node({"techage:ta4_collector"}, { on_recv_message = function(pos, src, topic, payload) - if topic == "state" then + if topic == "state" then local nvm = techage.get_nvm(pos) return lStates[nvm.stored_state or 0] else return "unsupported" end end, + on_beduino_request_data = function(pos, src, topic, payload) + if topic == 129 then + local nvm = techage.get_nvm(pos) + return 0, {TaStates[lStates[nvm.stored_state or 0]]} + else + return 2, "" + end + end, on_node_load = function(pos) minetest.get_node_timer(pos):start(CYCLE_TIME) end, diff --git a/techage/logic/detector.lua b/techage/logic/detector.lua index b0e709b..a7f66d0 100644 --- a/techage/logic/detector.lua +++ b/techage/logic/detector.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2017-2020 Joachim Stolberg + Copyright (C) 2017-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -83,12 +83,21 @@ local function formspec(meta) "button_exit[2,2;3,1;exit;"..S("Save").."]" end -local function after_place_node(pos, placer) +local function after_place_node3(pos, placer) local meta = M(pos) local inv = meta:get_inventory() inv:set_size('cfg', 4) - logic.after_place_node(pos, placer, "techage:ta3_detector_off", NDEF(pos).description) - logic.infotext(meta, NDEF(pos).description) + logic.after_place_node(pos, placer, "techage:ta3_detector_off", S("TA3 Detector")) + logic.infotext(meta, S("TA3 Detector")) + meta:set_string("formspec", formspec(meta)) +end + +local function after_place_node4(pos, placer) + local meta = M(pos) + local inv = meta:get_inventory() + inv:set_size('cfg', 4) + logic.after_place_node(pos, placer, "techage:ta4_detector_off", S("TA4 Detector")) + logic.infotext(meta, S("TA4 Detector")) meta:set_string("formspec", formspec(meta)) end @@ -126,7 +135,7 @@ minetest.register_node("techage:ta3_detector_off", { "techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_detector.png", }, - after_place_node = after_place_node, + after_place_node = after_place_node3, on_receive_fields = on_receive_fields, techage_set_numbers = techage_set_numbers, after_dig_node = after_dig_node, @@ -179,7 +188,7 @@ minetest.register_node("techage:ta4_detector_off", { "techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_detector.png", }, - after_place_node = after_place_node, + after_place_node = after_place_node4, on_receive_fields = on_receive_fields, techage_set_numbers = techage_set_numbers, after_dig_node = after_dig_node, @@ -276,4 +285,21 @@ techage.register_node({"techage:ta4_detector_off", "techage:ta4_detector_on"}, { return "unsupported" end end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + if topic == 6 then -- Detector Block Reset + local nvm = techage.get_nvm(pos) + nvm.counter = 0 + return 0 + else + return 2 + end + end, + on_beduino_request_data = function(pos, src, topic, payload) + if topic == 139 then + local nvm = techage.get_nvm(pos) + return 0, {nvm.counter or 0} + else + return 2, "" + end + end, }) diff --git a/techage/logic/light_detector.lua b/techage/logic/light_detector.lua new file mode 100755 index 0000000..4072f88 --- /dev/null +++ b/techage/logic/light_detector.lua @@ -0,0 +1,189 @@ +--[[ + + TechAge + ======= + + Copyright (C) 2019-2022 Joachim Stolberg + + AGPL v3 + See LICENSE.txt for more information + + Light Detector + +]]-- + +-- for lazy programmers +local M = minetest.get_meta +local S = techage.S +local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end + +local logic = techage.logic +local CYCLE_TIME = 2 + +local function switch_off(pos) + local node = minetest.get_node(pos) + if node.name == "techage:ta3_lightdetector_on" then + logic.swap_node(pos, "techage:ta3_lightdetector_off") + logic.send_off(pos, M(pos)) + end +end + +local function switch_on(pos) + logic.swap_node(pos, "techage:ta3_lightdetector_on") + if logic.send_on(pos, M(pos)) then + minetest.after(1, switch_off, pos) + end +end + +local function node_timer(pos) + + local nvm = techage.get_nvm(pos) + + local trigger = nvm.mode or 7 + + local pos_above = {x = pos.x, y = pos.y + 1, z = pos.z} + if minetest.get_node_light(pos_above, nil) == nil then + switch_off(pos) + return true + end + + if minetest.get_node_light(pos_above, nil) > trigger then + switch_on(pos) + else + switch_off(pos) + end + return true +end + +local function formspec(meta, nvm) + local numbers = meta:get_string("numbers") or "" + local dropdown_label = "1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15" -- Has to be a cleaner way of doing this, but it's just easier this way + return "size[7.5,4]".. + default.gui_bg.. + default.gui_bg_img.. + default.gui_slots.. + "field[0.5,1;7,1;numbers;"..S("Insert destination node number(s)")..";"..numbers.."]" .. + "label[0.2,1.6;"..S("Send signal if light level is above:").."]".. + "dropdown[0.2,2.1;7.3,1;mode;"..dropdown_label.."; "..(nvm.mode or 7).."]".. + "button_exit[2,3.2;3,1;accept;"..S("accept").."]" +end + +local function on_receive_fields(pos, formname, fields, player) + if minetest.is_protected(pos, player:get_player_name()) then + return + end + + local meta = minetest.get_meta(pos) + local nvm = techage.get_nvm(pos) + + if fields.accept then + nvm.mode = tonumber(fields.mode) or 7 + if techage.check_numbers(fields.numbers, player:get_player_name()) then + meta:set_string("numbers", fields.numbers) + logic.infotext(M(pos), S("TA3 Light Detector")) + end + meta:set_string("formspec", formspec(meta, nvm)) + end +end + +local function techage_set_numbers(pos, numbers, player_name) + local meta = M(pos) + local res = logic.set_numbers(pos, numbers, player_name, S("TA3 Light Detector")) + meta:set_string("formspec", formspec(meta)) + return res +end + +local function after_dig_node(pos, oldnode, oldmetadata, digger) + techage.remove_node(pos, oldnode, oldmetadata) +end + +minetest.register_node("techage:ta3_lightdetector_off", { + description = S("TA3 Light Detector"), + tiles = { + -- up, down, right, left, back, front + "techage_filling_ta3.png^techage_frame_ta3_top.png^techage_appl_lightdetector.png", + "techage_filling_ta3.png^techage_frame_ta3_top.png", + "techage_filling_ta3.png^techage_frame_ta3_top.png^techage_appl_arrow.png^[transformR90", + }, + after_place_node = function(pos, placer) + local meta = M(pos) + local nvm = techage.get_nvm(pos) + logic.after_place_node(pos, placer, "techage:ta3_lightdetector_off", S("TA3 Light Detector")) + logic.infotext(meta, S("TA3 Light Detector")) + meta:set_string("formspec", formspec(meta, nvm)) + minetest.get_node_timer(pos):start(CYCLE_TIME) + end, + + on_receive_fields = on_receive_fields, + on_timer = node_timer, + techage_set_numbers = techage_set_numbers, + after_dig_node = after_dig_node, + paramtype2 = "facedir", + groups = {choppy=2, cracky=2, crumbly=2}, + is_ground_content = false, + sounds = default.node_sound_metal_defaults(), +}) + +minetest.register_node("techage:ta3_lightdetector_on", { + description = "TA3 Light Detector (On)", + tiles = { + -- up, down, right, left, back, front + "techage_filling_ta3.png^techage_frame_ta3_top.png^techage_appl_lightdetector_on.png", + "techage_filling_ta3.png^techage_frame_ta3_top.png", + "techage_filling_ta3.png^techage_frame_ta3_top.png^techage_appl_arrow.png^[transformR90", + }, + on_receive_fields = on_receive_fields, + on_timer = node_timer, + techage_set_numbers = techage_set_numbers, + after_dig_node = after_dig_node, + paramtype2 = "facedir", + groups = {choppy=2, cracky=2, crumbly=2, not_in_creative_inventory=1}, + is_ground_content = false, + sounds = default.node_sound_wood_defaults(), + drop = "techage:ta3_lightdetector_off" +}) + +minetest.register_craft({ + output = "techage:ta3_lightdetector_off", + recipe = { + {"", "group:wood", "default:glass"}, + {"", "default:copper_ingot", "techage:vacuum_tube"}, + {"", "group:wood", "default:mese_crystal"}, + }, +}) + +techage.register_node({"techage:ta3_lightdetector_off", "techage:ta3_lightdetector_on"}, { + on_recv_message = function(pos, src, topic, payload) + if topic == "state" then + local node = techage.get_node_lvm(pos) + if node.name == "techage:ta3_lightdetector_on" then + return "on" + else + return "off" + end + elseif topic == "light_level" then -- Allow finding the specific light level + local pos_above = {x = pos.x, y = pos.y + 1, z = pos.z} + return minetest.get_node_light(pos_above, nil) + else + return "unsupported" + end + end, + on_beduino_request_data = function(pos, src, topic, payload) + if topic == 142 then -- Binary State + local node = techage.get_node_lvm(pos) + if node.name == "techage:ta3_lightdetector_on" then + return 0, {1} + else + return 0, {0} + end + elseif topic == 143 then -- Allow finding the specific light level + local pos_above = {x = pos.x, y = pos.y + 1, z = pos.z} + return 0, {minetest.get_node_light(pos_above, nil)} + else + return 2, "" + end + end, + on_node_load = function(pos) + minetest.get_node_timer(pos):start(CYCLE_TIME) + end, +}) diff --git a/techage/logic/logic_block.lua b/techage/logic/logic_block.lua index 0b83272..e15d652 100644 --- a/techage/logic/logic_block.lua +++ b/techage/logic/logic_block.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2017-2021 Joachim Stolberg + Copyright (C) 2017-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -407,4 +407,29 @@ techage.register_node({"techage:ta3_logic2"}, { mem.ttl = techage.SystemTime + (nvm.blocking_time or 0) end end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + local nvm = techage.get_nvm(pos) + local mem = techage.get_mem(pos) + nvm.own_num = nvm.own_num or M(pos):get_string("node_number") + nvm.blocking_time = nvm.blocking_time or M(pos):get_float("blocking_time") + nvm.inp_tbl = nvm.inp_tbl or {} + + if src ~= nvm.own_num then + if topic == 1 and payload[1] == 1 then + debug(mem, "(inp) " .. src .. " = on") + nvm.inp_tbl[src] = "on" + return 0 + elseif topic == 1 and payload[1] == 0 then + debug(mem, "(inp) " .. src .. " = off") + nvm.inp_tbl[src] = "off" + return 0 + else + debug(mem, "(inp) invalid command") + return 2 + end + local t = math.max((mem.ttl or 0) - techage.SystemTime, 0.1) + minetest.get_node_timer(pos):start(t) + mem.ttl = techage.SystemTime + (nvm.blocking_time or 0) + end + end, }) diff --git a/techage/logic/lua_logic.lua b/techage/logic/lua_logic.lua index 57cc629..48e3418 100644 --- a/techage/logic/lua_logic.lua +++ b/techage/logic/lua_logic.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2017-2020 Joachim Stolberg + Copyright (C) 2017-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -246,7 +246,19 @@ techage.register_node({"techage:ta3_logic"}, { end minetest.get_node_timer(pos):start(0.1) end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + if topic == 1 and payload[1] == 1 then + nvm.inp_tbl.inp = true + nvm.inp_tbl["n"..src] = true + return 0 + elseif topic == 1 and payload[1] == 0 then + nvm.inp_tbl.inp = false + nvm.inp_tbl["n"..src] = false + return 0 + else + return 2 + end + end, on_node_load = function(pos) - end, }) diff --git a/techage/logic/mba_detector.lua b/techage/logic/mba_detector.lua index 96cdd17..ab5d744 100644 --- a/techage/logic/mba_detector.lua +++ b/techage/logic/mba_detector.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2017-2020 Joachim Stolberg + Copyright (C) 2017-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -92,6 +92,23 @@ techage.register_node({"techage:ta4_mbadetector"}, { return "unsupported" end end, + on_beduino_request_data = function(pos, src, topic, payload) + if topic == 142 then -- Binary State + if minetest.compare_block_status then + if minetest.compare_block_status(pos, "active") then + return 0, {1} + else + return 0, {0} + end + else + local mem = techage.get_mem(pos) + local res = mem.gametime and mem.gametime > (minetest.get_gametime() - 2) + return 0, {res and 1 or 0} + end + else + return 2, "" + end + end, on_node_load = function(pos) minetest.get_node_timer(pos):start(1) end, diff --git a/techage/logic/node_detector.lua b/techage/logic/node_detector.lua index 7d3c89c..25f0db0 100644 --- a/techage/logic/node_detector.lua +++ b/techage/logic/node_detector.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2017-2020 Joachim Stolberg + Copyright (C) 2017-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -189,20 +189,29 @@ minetest.register_craft({ techage.register_node({"techage:ta3_nodedetector_off", "techage:ta3_nodedetector_on"}, { on_recv_message = function(pos, src, topic, payload) - if topic == "name" then - local nvm = techage.get_nvm(pos) - return nvm.player_name or "" - elseif topic == "state" then + if topic == "state" then local node = techage.get_node_lvm(pos) if node.name == "techage:ta3_nodedetector_off" then - return "on" - else return "off" + else + return "on" end else return "unsupported" end end, + on_beduino_request_data = function(pos, src, topic, payload) + if topic == 142 then + local node = techage.get_node_lvm(pos) + if node.name == "techage:ta3_nodedetector_off" then + return 0, {0} + else + return 0, {1} + end + else + return 2, "" + end + end, on_node_load = function(pos) minetest.get_node_timer(pos):start(CYCLE_TIME) end, diff --git a/techage/logic/player_detector.lua b/techage/logic/player_detector.lua index 791eb8d..f189185 100644 --- a/techage/logic/player_detector.lua +++ b/techage/logic/player_detector.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2017-2020 Joachim Stolberg + Copyright (C) 2017-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -323,6 +323,22 @@ techage.register_node({ return "unsupported" end end, + on_beduino_request_data = function(pos, src, topic, payload) + if topic == 144 then -- Player Name + local nvm = techage.get_nvm(pos) + return 0, nvm.player_name or "" + elseif topic == 142 then -- Binary State + local node = techage.get_node_lvm(pos) + if node.name == "techage:ta3_playerdetector_on" or + node.name == "techage:ta4_playerdetector_on" then + return 0, {1} + else + return 0, {0} + end + else + return 2, "" + end + end, on_node_load = function(pos) minetest.get_node_timer(pos):start(CYCLE_TIME) end, diff --git a/techage/logic/sequencer.lua b/techage/logic/sequencer.lua index e2c6005..1d5d936 100644 --- a/techage/logic/sequencer.lua +++ b/techage/logic/sequencer.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2017-2020 Joachim Stolberg + Copyright (C) 2017-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -278,6 +278,28 @@ techage.register_node({"techage:ta3_sequencer"}, { return "unsupported" end end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + local nvm = techage.get_nvm(pos) + if topic == 7 then -- TA3 Sequenzer + if payload[1] == 1 then + start_the_sequencer(pos) + return 0 + elseif payload[1] == 0 then + -- do not stop immediately + local nvm = techage.get_nvm(pos) + if not nvm.running then + nvm.endless = not (nvm.endless or false) + else + nvm.endless = false + end + return 0 + elseif payload[1] == 2 then + stop_the_sequencer(pos) + return 0 + end + end + return 2 + end, on_node_load = function(pos) local nvm = techage.get_nvm(pos) if nvm.running then diff --git a/techage/logic/sequencer2.lua b/techage/logic/sequencer2.lua index e051ab9..0151863 100644 --- a/techage/logic/sequencer2.lua +++ b/techage/logic/sequencer2.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2017-2021 Joachim Stolberg + Copyright (C) 2017-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -30,6 +30,7 @@ local HELP = S("Syntax:\n") .. S(" - 'send ' (techage command)\n") .. S(" - 'goto ' (jump to another line)\n") .. S(" - 'stop' (stop the execution)\n") .. + S(" - 'nop' (do nothing)\n") .. S("\n") .. S("Example:\n") .. " -- move controller commands\n" .. @@ -108,7 +109,7 @@ local function compile(s, tRes) tCode[idx] = {next_idx = tonumber(cmnd2) or 1} elseif cmnd1 == "stop" then tCode[idx] = false - elseif cmnd1 == nil then + elseif cmnd1 == nil or cmnd1 == "nop" then tCode[idx] = {} end old_idx = idx @@ -290,18 +291,18 @@ minetest.register_craft({ }, }) -local INFO = [[Commands: 'goto ', 'stop']] +local INFO = [[Commands: 'goto ', 'stop', 'on', 'off']] techage.register_node({"techage:ta4_sequencer"}, { on_recv_message = function(pos, src, topic, payload) local nvm = techage.get_nvm(pos) - if topic == "goto" and not nvm.running then + if (topic == "goto" or topic == "on") and not nvm.running then local mem = techage.get_mem(pos) nvm.running = true mem.idx = tonumber(payload or 1) or 1 restart_timer(pos, 0.1) logic.infotext(M(pos), S("TA4 Sequencer"), S("running")) - elseif topic == "stop" then + elseif topic == "stop" or topic == "off" then nvm.running = false minetest.get_node_timer(pos):stop() logic.infotext(M(pos), S("TA4 Sequencer"), S("stopped")) @@ -311,4 +312,23 @@ techage.register_node({"techage:ta4_sequencer"}, { return "unsupported" end end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + local nvm = techage.get_nvm(pos) + if topic == 13 then + if payload[1] ~= 0 and not nvm.running then + local mem = techage.get_mem(pos) + nvm.running = true + mem.idx = tonumber(payload or 1) or 1 + restart_timer(pos, 0.1) + logic.infotext(M(pos), S("TA4 Sequencer"), S("running")) + return 0 + elseif payload[1] == 0 then + nvm.running = false + minetest.get_node_timer(pos):stop() + logic.infotext(M(pos), S("TA4 Sequencer"), S("stopped")) + return 0 + end + end + return 2 + end, }) diff --git a/techage/logic/signallamp.lua b/techage/logic/signallamp.lua index 0a7ae1c..982bde2 100644 --- a/techage/logic/signallamp.lua +++ b/techage/logic/signallamp.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2020 Joachim Stolberg + Copyright (C) 2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -121,6 +121,19 @@ techage.register_node({"techage:signal_lamp_off", "techage:signal_lamp_on"}, { return "unsupported" end end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + if topic == 1 and payload[1] == 1 then + local node = techage.get_node_lvm(pos) + switch_on(pos, node) + return 0 + elseif topic == 1 and payload[1] == 0 then + local node = techage.get_node_lvm(pos) + switch_off(pos, node) + return 0 + else + return 2 + end + end, }) minetest.register_craft({ diff --git a/techage/logic/signallamp_2x.lua b/techage/logic/signallamp_2x.lua index 793cca9..3692b30 100644 --- a/techage/logic/signallamp_2x.lua +++ b/techage/logic/signallamp_2x.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2017-2021 Joachim Stolberg + Copyright (C) 2017-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -17,9 +17,9 @@ local M = minetest.get_meta local S = techage.S local OFF = 0 -local RED = 1 -local GREEN = 2 -local AMBER = 3 +local GREEN = 1 +local AMBER = 2 +local RED = 3 local WRENCH_MENU = { { @@ -139,6 +139,19 @@ techage.register_node({"techage:ta4_signallamp_2x"}, { lcdlib.update_entities(pos) end end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + local nvm = techage.get_nvm(pos) + nvm.lamp = nvm.lamp or {} + if topic == 3 then -- Signal Lamp + local num = math.min(payload[1] or 1, 2) + local color = math.min(payload[2] or 0, 3) + nvm.lamp[num] = color + lcdlib.update_entities(pos) + return 0 + else + return 2 + end + end, }) minetest.register_craft({ diff --git a/techage/logic/signallamp_4x.lua b/techage/logic/signallamp_4x.lua index 6482785..a098ba6 100644 --- a/techage/logic/signallamp_4x.lua +++ b/techage/logic/signallamp_4x.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2017-2021 Joachim Stolberg + Copyright (C) 2017-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -17,9 +17,9 @@ local M = minetest.get_meta local S = techage.S local OFF = 0 -local RED = 1 -local GREEN = 2 -local AMBER = 3 +local GREEN = 1 +local AMBER = 2 +local RED = 3 local WRENCH_MENU = { { @@ -170,6 +170,19 @@ techage.register_node({"techage:ta4_signallamp_4x"}, { lcdlib.update_entities(pos) end end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + local nvm = techage.get_nvm(pos) + nvm.lamp = nvm.lamp or {} + if topic == 3 then -- Signal Lamp + local num = math.min(payload[1] or 1, 4) + local color = math.min(payload[2] or 0, 3) + nvm.lamp[num] = color + lcdlib.update_entities(pos) + return 0 + else + return 2 + end + end, }) minetest.register_craft({ diff --git a/techage/lua_controller/controller.lua b/techage/lua_controller/controller.lua index 68fe4df..01c7b05 100644 --- a/techage/lua_controller/controller.lua +++ b/techage/lua_controller/controller.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019-2020 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -654,4 +654,27 @@ techage.register_node({"techage:ta4_lua_controller"}, { return "unsupported" end end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + local meta = minetest.get_meta(pos) + local number = meta:get_string("number") + + if topic == 1 and payload[1] == 1 then + set_input(pos, number, src, "on") + elseif topic == 1 and payload[1] == 0 then + set_input(pos, number, src, "off") + else + return 2 + end + return 0 + end, + on_beduino_request_data = function(pos, src, topic, payload) + local meta = minetest.get_meta(pos) + + if topic == 142 then + local running = meta:get_int("running") or STATE_STOPPED + return 0, {running} + else + return 2, "" + end + end, }) diff --git a/techage/lua_controller/sensorchest.lua b/techage/lua_controller/sensorchest.lua index 5a483b9..5ba2f1e 100644 --- a/techage/lua_controller/sensorchest.lua +++ b/techage/lua_controller/sensorchest.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019-2020 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -46,6 +46,13 @@ local function send_command(pos) end end +local function get_stack(pos, idx) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + local stack = inv:get_stack("main", idx) + return stack:get_name(), stack:get_count() +end + local function get_stacks(pos) local meta = minetest.get_meta(pos) local inv = meta:get_inventory() @@ -215,7 +222,7 @@ techage.register_node({"techage:ta4_sensor_chest"}, { elseif topic == "action" then local meta = minetest.get_meta(pos) local number = meta:get_string("node_number") - return PlayerActions[number][1], PlayerActions[number][2] + return (PlayerActions[number] or {})[1], (PlayerActions[number] or {})[2] elseif topic == "stacks" then return get_stacks(pos) elseif topic == "text" then @@ -226,6 +233,40 @@ techage.register_node({"techage:ta4_sensor_chest"}, { return "unsupported" end end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + if topic == 66 then + local meta = minetest.get_meta(pos) + meta:set_string("text", tostring(payload)) + meta:set_string("formspec", formspec2(pos)) + return 0 + else + return 2 + end + end, + on_beduino_request_data = function(pos, src, topic, payload) + if topic == 131 then -- Chest State + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + return 0, {techage.get_inv_state_num(inv, "main")} + elseif topic == 138 and payload[1] == 1 then -- Sensor Chests State (action) + local meta = minetest.get_meta(pos) + local number = meta:get_string("node_number") + local action = (PlayerActions[number] or {})[2] or "None" + return 0, {({put = 1, get = 2})[action] or 0} + elseif topic == 138 and payload[1] == 2 then -- Sensor Chests State (player name) + local meta = minetest.get_meta(pos) + local number = meta:get_string("node_number") + return 0, (PlayerActions[number] or {})[1] + elseif topic == 138 and payload[1] == 3 then -- Sensor Chests State (stack item name) + local name, _ = get_stack(pos, payload[2] or 1) + return 0, name + elseif topic == 138 and payload[1] == 4 then -- Sensor Chests State (stack item count) + local _, count = get_stack(pos, payload[2] or 1) + return 0, {count} + else + return 2, "" + end + end, }) minetest.register_craft({ diff --git a/techage/manuals/manual_ta3_DE.md b/techage/manuals/manual_ta3_DE.md index e44f9f7..4ccfcd2 100644 --- a/techage/manuals/manual_ta3_DE.md +++ b/techage/manuals/manual_ta3_DE.md @@ -661,11 +661,15 @@ Der Tür Controller II kann alle Arten von Blöcken entfernen und wieder setzen. Wird ein `on` / `off` Kommando an den Tür Controller II gesendet, entfernt bzw. setzt er die Blöcke ebenfalls. -Über ein `exchange` Kommando können einzelne Böcke gesetzt, entfernt, bzw. durch andere Blöcke ersetzt werden. Die Slot-Nummer des Inventars (1 .. 16) muss als payload übergeben werden, also: +Mit `$send_cmnd(node_number, "exchange", 2)` können einzelne Böcke gesetzt, entfernt, bzw. durch andere Blöcke aus dem Inventar ersetzt werden. -``` -$send_cmnd(node_number, "exchange", 2) -``` +Mit `$send_cmnd(node_number, "set", 2)` kann ein Block aus dem Inventory explizit gesetzt werden, sofern der Inventory Slot nicht leer ist. + +Mit `$send_cmnd(node_number, "dig", 2)` kann ein Block wieder entfernt werden, sofern der Inventory Slot leer ist. + +Mit `$send_cmnd(node_number, "get", 2)` wird der Name des gesetzten Blocks zurückgeliefert. + +Die Slot-Nummer des Inventars (1 .. 16) muss in allen drei Fällen als payload übergeben werden. Damit lassen sich auch ausfahrbare Treppen und ähnliches simulieren. @@ -679,7 +683,7 @@ Die Sounds können über das Menü und über ein Kommando ausgewählt und abgesp - Kommando `on` zum Abspielen eines Sounds - Kommando `sound ` zur Auswahl eines Sounds über den Index -- Kommando `gain ` zum Einstellen der Lautstärke über den `` Wert (0 bis 1.0). +- Kommando `gain ` zum Einstellen der Lautstärke über den `` Wert (1 bis 5). [ta3_soundblock|image] @@ -737,6 +741,14 @@ Soll die Suche auf bestimmte Spieler eingegrenzt werden, so können diese Spiele [ta3_playerdetector|image] +### TA3 Lichtdetektor + +Der Lichtdetektor sendet einen `on`-Kommando, wenn der Lichtpegel des darüber liegenden Blocks einen bestimmten Pegel überschreitet, der über das Rechtsklickmenü eingestellt werden kann. +Mit einen TA4 Lua Controller kann die genaue Lichtstärke mit $get_cmd(num, 'light_level') ermitteln werden. + +[ta3_lightdetector|image] + + ## TA3 Maschinen Bei TA3 existieren die gleichen Maschinen wie bei TA2, nur sind diese hier leistungsfähiger und benötigen Strom statt Achsenantrieb. @@ -865,4 +877,4 @@ Der Techage Schraubendreher dient als Ersatz für den normalen Schraubendreher. - Shift+Linksklick: Ausrichtung des angeklickten Blockes speichern - Shift+Rechtsklick: Die gespeicherte Ausrichtung auf den angeklickten Block anwenden -[ta3_screwdriver|image] \ No newline at end of file +[ta3_screwdriver|image] diff --git a/techage/manuals/manual_ta3_EN.md b/techage/manuals/manual_ta3_EN.md index b24434c..5e45494 100644 --- a/techage/manuals/manual_ta3_EN.md +++ b/techage/manuals/manual_ta3_EN.md @@ -654,11 +654,15 @@ The door controller is used to control the TA3 door/gate blocks. With the door c The Door Controller II can remove and set all types of blocks. To teach in the Door Controller II, the "Record" button must be pressed. Then all blocks that should be part of the door / gate must be clicked. Then the "Done" button must be pressed. Up to 16 blocks can be selected. The removed blocks are saved in the controller's inventory. The function of the controller can be tested manually using the "Remove" or "Set" buttons. If an `on` /`off` command is sent to the Door Controller II, it removes or sets the blocks as well. -Individual blocks can be set, removed or replaced by other blocks via an `exchange` command. The slot number of the inventory (1 .. 16) must be transferred as payload, i.e.: +With `$send_cmnd(node_number, "exchange", 2)` individual blocks can be set, removed or replaced by other blocks from the inventory. -``` -$send_cmnd(node_number, "exchange", 2) -``` +With `$send_cmnd(node_number, "set", 2)` a block from the inventory can be set explicitly, as long as the inventory slot is not empty. + +A block can be removed again with `$send_cmnd(node_number, "dig", 2)` if the inventory slot is empty. + +The name of the set block is returned with `$send_cmnd(node_number, "get", 2)`. + +The slot number of the inventory (1 .. 16) must be passed as payload in all three cases. This can also be used to simulate extendable stairs and the like. @@ -672,7 +676,7 @@ The sounds can be selected and played via the menu and via command. - Command `on` to play a sound - Command `sound ` to select a sound via the index -- Command `gain ` to adjust the volume via the `` value (0 to 1.0). +- Command `gain ` to adjust the volume via the `` value (1 to 5). [ta3_soundblock|image] @@ -730,6 +734,12 @@ If the search should be limited to specific players, these player names can also [ta3_playerdetector|image] +### TA3 Light Detector + +The light detector sends an `on` command if the light level of the block above exceeds a certain level, which can be set through the right-click menu. +If you have a TA4 Lua Controller, you can get the exact light level with $get_cmd(num, 'light_level') + +[ta3_lightdetector|image] ## TA3 Machines diff --git a/techage/manuals/manual_ta4_DE.md b/techage/manuals/manual_ta4_DE.md index 15e33cf..3d5cde5 100644 --- a/techage/manuals/manual_ta4_DE.md +++ b/techage/manuals/manual_ta4_DE.md @@ -550,6 +550,7 @@ Der TA4 Sequenzer unterstützt folgende techage Kommandos: - `goto ` Zu einer Kommandozeile springen und damit den Sequenzer starten - `stop` Den Sequenzer anhalten +- `on` und `off` als Alias für `goto 1` bzw. `stop` Das `goto` Kommando wird nur angenommen, wenn der Sequenzer gestoppt ist. @@ -843,6 +844,7 @@ Der TA4 Schieber besitzt zwei zusätzliche Kommandos für den Lua Controller: - `config` dient zur Konfiguration des Schiebers, analog zum manuellen Konfiguration über das Menü. Beispiel: `$send_cmnd(1234, "config", "default:dirt")` + Mit `$send_cmnd(1234, "config", "")` wird die Konfiguration gelöscht - `pull` dient zum Absetzen eines Auftrags an den Schieber: Beispiel: `$send_cmnd(1234, "pull", "default:dirt 8")` Als Nummer sind Werte von 1 bis 12 zulässig. Danach geht der Schieber wieder in den `stopped` Mode und sendet ein "off" Kommando zurück an den Sender des "pull" Kommandos. diff --git a/techage/manuals/manual_ta4_EN.md b/techage/manuals/manual_ta4_EN.md index d242b3c..a82e4d0 100644 --- a/techage/manuals/manual_ta4_EN.md +++ b/techage/manuals/manual_ta4_EN.md @@ -542,6 +542,7 @@ The TA4 sequencer supports the following techage commands: - `goto ` Jump to a command line and start the sequencer - `stop` Stop the sequencer +- `on` and `off` as aliases for `goto 1` resp. `stop` The `goto` command is only accepted when the sequencer is stopped. @@ -835,6 +836,7 @@ The TA4 pusher has two additional commands for the Lua controller: - `config` is used to configure the pusher, analogous to manual configuration via the menu. Example: `$send_cmnd(1234, "config", "default: dirt")` + With `$send_cmnd(1234, "config", "")` the configuration is deleted - `pull` is used to send an order to the pusher: Example: `$send_cmnd(1234, "pull", "default: dirt 8")` Values ​​from 1 to 12 are permitted as numbers. Then the pusher goes back to `stopped` mode and sends an" off "command back to the transmitter of the" pull "command. diff --git a/techage/manuals/ta4_lua_controller_EN.md b/techage/manuals/ta4_lua_controller_EN.md index 51bf2a7..a9c3315 100644 --- a/techage/manuals/ta4_lua_controller_EN.md +++ b/techage/manuals/ta4_lua_controller_EN.md @@ -374,7 +374,9 @@ Please note, that this is not a technical distinction, only a logical. | "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. | +| "input" | \ | Read a recipe from the TA4 Recipe Block. `` is the number of the recipe. The block return a list of recipe items. | +| "name" | \ | Player name of the TA3/TA4 Player Detector or TA4 Button | +| "time" | number | Time in system ticks (norm. 100 ms) when the TA4 Button is clicked | @@ -390,14 +392,19 @@ Please note, that this is not a technical distinction, only a logical. | "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" | string
`=on/off` | Enable/disable a Distributor filter slot..
Example: `"yellow=on"`
colors: red, green, blue, yellow | +| "config" | "\ \" | Configure a Distributor filter slot, like: "red default:dirt dye:blue" | | "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) | +| "exchange" | inventory slot number | TA3 Door Controller II (techage:ta3_doorcontroller2)
Exchange a block
*idx* is the inventory slot number (1..n) of/for the block to be exchanged | +| "set" | inventory slot number | TA3 Door Controller II (techage:ta3_doorcontroller2)
Set/add a block
*idx* is the inventory slot number (1..n) with the block to be set | +| "dig" | inventory slot number | TA3 Door Controller II (techage:ta3_doorcontroller2)
Dig/remove a block
*idx* is the empty inventory slot number (1..n) for the block | | "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 | +| "move2" | x,y,z | TA4 Move Controller command to move the block(s) by the given
x/y/z-distance. Valid ranges for x, y, and z are -100 to 100. | +| "reset" | nil | Reset TA4 Move Controller (move block(s) to start 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 | diff --git a/techage/manuals/ta_iom.md b/techage/manuals/ta_iom.md new file mode 100644 index 0000000..7d6d9c7 --- /dev/null +++ b/techage/manuals/ta_iom.md @@ -0,0 +1,85 @@ +# Techage/Beduino I/O Module + +I/O modules support the following functions: + +### event + +Every signal that is sent to an I/O module triggers an event on the controller. +Events can be queried using the `event()` function. +If the function returns the value `1`, one or more signals have been received. +Calling `event()` resets the event flag. + +```c +event() +``` + +### read + +Read a value from a remote techage block. + +- *port* is the I/O module port number +- *cmnd* is the command, like `IO_STATE` (see example code "ta_cmnd.c") + +```c +read(port, cmnd) +``` + +### send_cmnd + +Send a command to a techage block (see [commands](https://github.com/joe7575/beduino/blob/main/BEPs/bep-005_ta_cmnd.md)). + +- *port* is the I/O module port number +- *topic* is a number from the list of [Beduino commands](https://github.com/joe7575/beduino/blob/main/BEPs/bep-005_ta_cmnd.md) +- *payload* is an array or a string with additional information, depending on the command. If no additional commands are required, "" can be used. + +```c +send_cmnd(port, topic, payload) +``` + +### request_data + +Request information from a techage block (see [commands](https://github.com/joe7575/beduino/blob/main/BEPs/bep-005_ta_cmnd.md)). + +- *port* is the I/O module port number +- *topic* is a number from the list of [Beduino commands](https://github.com/joe7575/beduino/blob/main/BEPs/bep-005_ta_cmnd.md) +- *payload* is an array or a string with additional information, depending on the command. If no additional commands are required, "" can be used. +- *resp* is an array for the response data. The array must be defined large enough to hold the response data. + +```c +request_data(port, topic, payload, resp) +``` + +## Functions for TA4 Display and TA4 Display XL + +### clear_screen + +Clear the display. + +- *port* is the I/O module port number + +```c +clear_screen(port) +``` + +### append_line + +Add a new line to the display. +- *port* is the I/O module port number +- *text* is the text for one line + +```c +append_line(port, text) +``` + + +### write_line + +Overwrite a text line with the given string. + +- *port* is the I/O module port number +- *row* ist the display line/row (1-5) +- *text* is the text for one line + +```c +write_line(port, row, text) +``` diff --git a/techage/manuals/ta_kvstore.md b/techage/manuals/ta_kvstore.md new file mode 100644 index 0000000..ddee165 --- /dev/null +++ b/techage/manuals/ta_kvstore.md @@ -0,0 +1,78 @@ +# Techage/Beduino Key/Value Store + +The key/value store simplifies the handling/comparison of strings. + +The following example shows the use of the Key/Value Store, here to check the names from the Player Detector: + +```c +import "ta_kvstore.c" +import "ta_iom.c" + +var s[16]; + +func init() { + // Init and fill-up the k/v store + ta_kv_init(); + ta_kv_add("singleplayer", 1); + ta_kv_add("Tom", 2); + ta_kv_add("Betty", 3); + ta_kv_add("Joe", 4); +} + +func loop() { + var val; + + if(event()) { // Signal from player detector received + request_data(5, 144, "", s); // Request player name from player detector + val = ta_kv_get(s); // Read value for the given name in 's' + if(val == 1) { + // do A... + } else if(val == 2) { + // do B... + } else if(val == 3) { + // do C... + } + } +} +``` + + + +Each controller has a key/value store that must be initialized via `ta_kv_init()` and filled via `ta_kv_add` before it can be used. + +### ta_kv_init + +Initializes the key/value store. Has to be called once at the beginning. + +```c +ta_kv_init() +``` + + + +### ta_kv_add + +Add a new key/value pair to the store. + +- *key_str* is the string +- *value* is the value to be stored, which can be read again using the key string + +```c + ta_kv_add(key_str, value) +``` + + + +### ta_kv_get + +Read a value from thre store. + +- *key_str* is the string + +The function returns 0, if *key_str* is unknown. + +```c +ta_kv_get(key_str) +``` + + diff --git a/techage/manuals/toc_DE.md b/techage/manuals/toc_DE.md index 36fc807..7d02fb9 100644 --- a/techage/manuals/toc_DE.md +++ b/techage/manuals/toc_DE.md @@ -123,6 +123,7 @@ - [TA3 Wagen Detektor / Cart Detector](./manual_ta3_DE.md#ta3-wagen-detektor--cart-detector) - [TA3 Block Detektor / Node Detector](./manual_ta3_DE.md#ta3-block-detektor--node-detector) - [TA3 Spieler Detektor / Player Detector](./manual_ta3_DE.md#ta3-spieler-detektor--player-detector) + - [TA3 Lichtdetektor](./manual_ta3_DE.md#ta3-lichtdetektor) - [TA3 Maschinen](./manual_ta3_DE.md#ta3-maschinen) - [TA3 Schieber / Pusher](./manual_ta3_DE.md#ta3-schieber--pusher) - [TA3 Verteiler / Distributor](./manual_ta3_DE.md#ta3-verteiler--distributor) diff --git a/techage/manuals/toc_EN.md b/techage/manuals/toc_EN.md index 705a0a2..bb5becf 100644 --- a/techage/manuals/toc_EN.md +++ b/techage/manuals/toc_EN.md @@ -123,6 +123,7 @@ - [TA3 Cart Detector](./manual_ta3_EN.md#ta3-cart-detector) - [TA3 Block Detector](./manual_ta3_EN.md#ta3-block-detector) - [TA3 Player Detector](./manual_ta3_EN.md#ta3-player-detector) + - [TA3 Light Detector](./manual_ta3_EN.md#ta3-light-detector) - [TA3 Machines](./manual_ta3_EN.md#ta3-machines) - [TA3 Pusher](./manual_ta3_EN.md#ta3-pusher) - [TA3 Distributor](./manual_ta3_EN.md#ta3-distributor) diff --git a/techage/move_controller/doorcontroller.lua b/techage/move_controller/doorcontroller.lua index f859290..2b99ad7 100644 --- a/techage/move_controller/doorcontroller.lua +++ b/techage/move_controller/doorcontroller.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2020 Joachim Stolberg + Copyright (C) 2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -124,6 +124,17 @@ techage.register_node({"techage:ta3_doorcontroller"}, { swap_door_nodes(pos, false) end end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + if topic == 1 and payload[1] == 1 then + swap_door_nodes(pos, true) + return 0 + elseif topic == 1 and payload[1] == 0 then + swap_door_nodes(pos, false) + return 0 + else + return 2 + end + end, }) minetest.register_craft({ diff --git a/techage/move_controller/doorcontroller2.lua b/techage/move_controller/doorcontroller2.lua index 0a7f458..48aa46d 100644 --- a/techage/move_controller/doorcontroller2.lua +++ b/techage/move_controller/doorcontroller2.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2020-2021 Joachim Stolberg + Copyright (C) 2020-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -17,28 +17,16 @@ local M = minetest.get_meta local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end local S = techage.S +local MP = minetest.get_modpath("techage") +local flylib = dofile(MP .. "/basis/fly_lib.lua") local logic = techage.logic local MarkedNodes = {} -- t[player] = {{entity, pos},...} local CurrentPos -- to mark punched entities -local RegisteredNodes = {} -- to be checked before removed/placed local function is_simple_node(name) - -- special handling - if RegisteredNodes[name] ~= nil then - return RegisteredNodes[name] - end - local ndef = minetest.registered_nodes[name] - if not ndef or name == "air" then return true end - if ndef.groups and ndef.groups.techage_door == 1 then return true end - - -- don't remove nodes with some intelligence or undiggable nodes - if ndef.drop == "" then return false end - if ndef.diggable == false then return false end - if ndef.after_dig_node then return false end - - return true + return techage.can_dig_node(name, ndef) end local function unmark_position(name, pos) @@ -94,7 +82,6 @@ minetest.register_entity(":techage:marker", { "techage_cube_mark.png", "techage_cube_mark.png", }, - --use_texture_alpha = true, physical = false, visual_size = {x = 1.1, y = 1.1}, collisionbox = {-0.55,-0.55,-0.55, 0.55,0.55,0.55}, @@ -154,11 +141,11 @@ local function exchange_node(pos, item, param2) local node = minetest.get_node_or_nil(pos) if node and is_simple_node(node.name) then if item and item:get_name() ~= "" and minetest.registered_nodes[item:get_name()] then - minetest.swap_node(pos, {name = item:get_name(), param2 = param2}) + flylib.exchange_node(pos, item:get_name(), param2) else - minetest.remove_node(pos) + flylib.remove_node(pos) end - if node.name ~= "air" then + if not techage.is_air_like(node.name) then return ItemStack(node.name), node.param2 else return ItemStack(), nil @@ -167,7 +154,7 @@ local function exchange_node(pos, item, param2) return item, param2 end -local function exchange_nodes(pos, nvm, slot) +local function exchange_nodes(pos, nvm, slot, force) local meta = M(pos) local inv = meta:get_inventory() @@ -179,9 +166,14 @@ local function exchange_nodes(pos, nvm, slot) for idx = (slot or 1), (slot or 16) do local pos = nvm.pos_list[idx] + local item = item_list[idx] if pos then - item_list[idx], nvm.param2_list[idx] = exchange_node(pos, item_list[idx], nvm.param2_list[idx]) - res = true + if (force == nil) + or (force == "dig" and item:get_count() == 0) + or (force == "set" and item:get_count() > 0) then + item_list[idx], nvm.param2_list[idx] = exchange_node(pos, item, nvm.param2_list[idx]) + res = true + end end end @@ -189,6 +181,14 @@ local function exchange_nodes(pos, nvm, slot) return res end +local function get_node_name(nvm, slot) + local pos = nvm.pos_list[slot] + if pos then + return techage.get_node_lvm(pos).name + end + return "unknown" +end + local function show_nodes(pos) local nvm = techage.get_nvm(pos) if not nvm.is_on then @@ -342,9 +342,42 @@ techage.register_node({"techage:ta3_doorcontroller2"}, { elseif topic == "exchange" then local nvm = techage.get_nvm(pos) return exchange_nodes(pos, nvm, tonumber(payload)) + elseif topic == "set" then + local nvm = techage.get_nvm(pos) + return exchange_nodes(pos, nvm, tonumber(payload), "set") + elseif topic == "dig" then + local nvm = techage.get_nvm(pos) + return exchange_nodes(pos, nvm, tonumber(payload), "dig") + elseif topic == "get" then + local nvm = techage.get_nvm(pos) + return get_node_name(nvm, tonumber(payload)) end return false end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + if topic == 1 and payload[1] == 1 then + return hide_nodes(pos) and 0 or 3 + elseif topic == 1 and payload[1] == 0 then + return show_nodes(pos) and 0 or 3 + elseif topic == 9 and payload[1] == 0 then -- Exchange Block + local nvm = techage.get_nvm(pos) + return exchange_nodes(pos, nvm, payload[2] or 1) and 0 or 3 + elseif topic == 9 and payload[1] == 1 then -- Set Block + local nvm = techage.get_nvm(pos) + return exchange_nodes(pos, nvm, payload[2] or 1, "set") and 0 or 3 + elseif topic == 9 and payload[1] == 2 then -- Dig Block + local nvm = techage.get_nvm(pos) + return exchange_nodes(pos, nvm, payload[2] or 1, "dig") and 0 or 3 + end + return 2 + end, + on_beduino_request_data = function(pos, src, topic, payload) + if topic == 147 then -- Get Name + local nvm = techage.get_nvm(pos) + return 0, get_node_name(nvm, payload[1] or 1) + end + return 2, "" + end, on_node_load = function(pos) local meta = M(pos) local nvm = techage.get_nvm(pos) @@ -387,12 +420,6 @@ minetest.register_on_punchnode(function(pos, node, puncher, pointed_thing) end end) -function logic.register_doorcontroller_nodes(node_names) - for _,name in ipairs(node_names or {}) do - RegisteredNodes[name] = true - end -end - local Doors = { "doors:door_steel", "doors:prison_door", @@ -411,7 +438,8 @@ local Doors = { for _, name in ipairs(Doors) do for _, postfix in ipairs({"a", "b", "c", "d"}) do - logic.register_doorcontroller_nodes({name .. "_" .. postfix}) + techage.register_simple_nodes({name .. "_" .. postfix}, true) + flylib.protect_door_from_being_opened(name .. "_" .. postfix) end end @@ -424,8 +452,7 @@ local ProtectorDoors = { for _, name in ipairs(ProtectorDoors) do for _, postfix in ipairs({"b_1", "b_2", "t_1", "t_2"}) do - logic.register_doorcontroller_nodes({name .. "_" .. postfix}) + techage.register_simple_nodes({name .. "_" .. postfix}, true) + flylib.protect_door_from_being_opened(name .. "_" .. postfix) end end - -logic.SimpleNodes = RegisteredNodes diff --git a/techage/move_controller/flycontroller.lua b/techage/move_controller/flycontroller.lua index 7bdf96c..4f1c7ed 100644 --- a/techage/move_controller/flycontroller.lua +++ b/techage/move_controller/flycontroller.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2020-2021 Joachim Stolberg + Copyright (C) 2020-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -228,6 +228,33 @@ techage.register_node({"techage:ta5_flycontroller"}, { end return false end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + local nvm = techage.get_nvm(pos) + if topic == 11 then + if payload[1] == 1 then + nvm.moveBA = true + nvm.running = true + return fly.move_to_other_pos(pos, false) and 0 or 3 + elseif payload[1] == 2 then + nvm.moveBA = false + nvm.running = true + return fly.move_to_other_pos(pos, true) and 0 or 3 + elseif payload[1] == 3 then + nvm.moveBA = nvm.moveBA == false + nvm.running = true + return fly.move_to_other_pos(pos, nvm.moveBA == false) and 0 or 3 + end + else + return 2 + end + end, + on_beduino_request_data = function(pos, src, topic, payload) + local nvm = techage.get_nvm(pos) + if topic == 129 then + return 0, {nvm.running and 1 or 6} + end + return 2, "" + end, }) minetest.register_craft({ diff --git a/techage/move_controller/movecontroller.lua b/techage/move_controller/movecontroller.lua index ab000ec..c6b3ecc 100644 --- a/techage/move_controller/movecontroller.lua +++ b/techage/move_controller/movecontroller.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2020-2021 Joachim Stolberg + Copyright (C) 2020-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -62,11 +62,30 @@ local WRENCH_MENU = { tooltip = S("Y-offset for non-player objects like vehicles (-0.5 to 0.5)"), default = "0.0", }, + { + type = "dropdown", + choices = "A-B / B-A,move xyz", + name = "opmode", + label = S("Operational mode"), + tooltip = S("Switch to the remote controlled 'move xyz' mode"), + default = "A-B / B-A", + }, } local function formspec(nvm, meta) local status = meta:get_string("status") local path = meta:contains("path") and meta:get_string("path") or "0,3,0" + local buttons + if meta:get_string("opmode") == "move xyz" then + buttons = "field[0.4,2.5;3.8,1;path;" .. S("Move distance") .. ";" .. path .. "]" .. + "button_exit[4.1,2.2;3.8,1;move2;" .. S("Move") .. "]" .. + "button_exit[0.1,3.3;3.8,1;reset;" .. S("Reset") .. "]" + else + buttons = "field[0.4,2.5;3.8,1;path;" .. S("Move distance (A to B)") .. ";" .. path .. "]" .. + "button_exit[0.1,3.3;3.8,1;moveAB;" .. S("Move A-B") .. "]" .. + "button_exit[4.1,3.3;3.8,1;moveBA;" .. S("Move B-A") .. "]" .. + "button[4.1,2.2;3.8,1;store;" .. S("Store") .. "]" + end return "size[8,5]" .. default.gui_bg .. default.gui_bg_img .. @@ -76,10 +95,7 @@ local function formspec(nvm, meta) techage.wrench_image(7.4, -0.05) .. "button[0.1,0.8;3.8,1;record;" .. S("Record") .. "]" .. "button[4.1,0.8;3.8,1;done;" .. S("Done") .. "]" .. - "field[0.4,2.5;3.8,1;path;" .. S("Move distance (A to B)") .. ";" .. path .. "]" .. - "button[4.1,2.2;3.8,1;store;" .. S("Store") .. "]" .. - "button_exit[0.1,3.3;3.8,1;moveAB;" .. S("Move A-B") .. "]" .. - "button_exit[4.1,3.3;3.8,1;moveBA;" .. S("Move B-A") .. "]" .. + buttons .. "label[0.3,4.3;" .. status .. "]" end @@ -163,9 +179,30 @@ minetest.register_node("techage:ta4_movecontroller", { mark.stop(name) end meta:set_string("formspec", formspec(nvm, meta)) + elseif fields.move2 then + if fly.to_vector(fields.path or "", MAX_DIST) then + meta:set_string("path", fields.path) + end + local line = fly.to_vector(meta:get_string("path")) + if line then + nvm.running = true + fly.move_to(pos, line) + end + elseif fields.reset then + nvm.running = true + fly.reset_move(pos) end end, + on_rightclick = function(pos, node, clicker, itemstack, pointed_thing) + if not clicker or minetest.is_protected(pos, clicker:get_player_name()) then + return + end + local meta = M(pos) + local nvm = techage.get_nvm(pos) + meta:set_string("formspec", formspec(nvm, meta)) + end, + after_dig_node = function(pos, oldnode, oldmetadata, digger) local name = digger:get_player_name() mark.unmark_all(name) @@ -185,25 +222,80 @@ local INFO = [[Commands: 'state', 'a2b', 'b2a', 'move']] techage.register_node({"techage:ta4_movecontroller"}, { on_recv_message = function(pos, src, topic, payload) local nvm = techage.get_nvm(pos) + local move_xyz = M(pos):get_string("opmode") == "move xyz" if topic == "info" then return INFO elseif topic == "state" then return nvm.running and "running" or "stopped" - elseif topic == "a2b" then + elseif not move_xyz and topic == "a2b" then nvm.moveBA = true nvm.running = true return fly.move_to_other_pos(pos, false) - elseif topic == "b2a" then + elseif not move_xyz and topic == "b2a" then nvm.moveBA = false nvm.running = true return fly.move_to_other_pos(pos, true) - elseif topic == "move" then + elseif move_xyz and topic == "move" then nvm.moveBA = nvm.moveBA == false nvm.running = true return fly.move_to_other_pos(pos, nvm.moveBA == false) + elseif move_xyz and topic == "move2" then + local line = fly.to_vector(payload) + if line then + nvm.running = true + nvm.controller_mode = true + return fly.move_to(pos, line) + end + return false + elseif topic == "reset" then + nvm.running = true + nvm.controller_mode = true + return fly.reset_move(pos) end return false end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + local nvm = techage.get_nvm(pos) + local move_xyz = M(pos):get_string("opmode") == "move xyz" + --print("on_beduino_receive_cmnd", P2S(pos), move_xyz, topic, payload[1]) + if not move_xyz and topic == 11 then + if payload[1] == 1 then + nvm.moveBA = true + nvm.running = true + return fly.move_to_other_pos(pos, false) and 0 or 3 + elseif payload[1] == 2 then + nvm.moveBA = false + nvm.running = true + return fly.move_to_other_pos(pos, true) and 0 or 3 + elseif payload[1] == 3 then + nvm.moveBA = nvm.moveBA == false + nvm.running = true + return fly.move_to_other_pos(pos, nvm.moveBA == false) and 0 or 3 + end + elseif move_xyz and topic == 18 then -- move xyz + local line = { + x = techage.in_range(techage.beduino_signed_var(payload[1]), -10, 10), + y = techage.in_range(techage.beduino_signed_var(payload[2]), -10, 10), + z = techage.in_range(techage.beduino_signed_var(payload[3]), -10, 10), + } + nvm.running = true + nvm.controller_mode = true + return fly.move_to(pos, line) and 0 or 3 + elseif move_xyz and topic == 19 then -- reset + nvm.running = true + nvm.controller_mode = true + return fly.reset_move(pos) and 0 or 3 + else + return 2 + end + end, + on_beduino_request_data = function(pos, src, topic, payload) + local nvm = techage.get_nvm(pos) + if topic == 129 then + return 0, {nvm.running and 1 or 6} + end + return 2, "" + end, }) minetest.register_craft({ diff --git a/techage/move_controller/soundblock.lua b/techage/move_controller/soundblock.lua index 24ab6fd..bafcbb2 100644 --- a/techage/move_controller/soundblock.lua +++ b/techage/move_controller/soundblock.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2021 Joachim Stolberg + Copyright (C) 2021-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -44,6 +44,18 @@ local function formspec(meta) "button[2.5,7.2;3,1;play;" .. S("Play") .. "]" end +local function play_predefined_sound(pos) + local mem = techage.get_mem(pos) + if not mem.blocking_time or (mem.blocking_time < minetest.get_gametime()) then + local idx = M(pos):get_int("idx") + local ogg = techage.OggFileList[idx or 1] or techage.OggFileList[1] + local gain = M(pos):get_int("gain") + play_sound(pos, ogg, gain) + mem.blocking_time = minetest.get_gametime() + 2 + return true + end +end + minetest.register_node("techage:ta3_soundblock", { description = S("TA3 Sound Block"), tiles = { @@ -94,23 +106,32 @@ techage.register_node({"techage:ta3_soundblock"}, { if topic == "info" then return INFO elseif topic == "on" then - local mem = techage.get_mem(pos) - if not mem.blocking_time or (mem.blocking_time < minetest.get_gametime()) then - local idx = M(pos):get_int("idx") - local ogg = techage.OggFileList[idx or 1] or techage.OggFileList[1] - local gain = M(pos):get_float("gain") - play_sound(pos, ogg, gain) - mem.blocking_time = minetest.get_gametime() + 2 - return true - end + play_predefined_sound(pos) elseif topic == "sound" then - M(pos):get_int("idx", tonumber(payload or 1) or 1) + M(pos):set_int("idx", tonumber(payload or 1) or 1) elseif topic == "gain" then - M(pos):get_int("gain", tonumber(payload or 1) or 1) + M(pos):set_int("gain", tonumber(payload or 1) or 1) else return "unsupported" end end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + if topic == 1 then + if payload[1] == 0 then + play_predefined_sound(pos) + return 0 + end + elseif topic == 14 then + if payload[1] == 1 then + M(pos):set_int("gain", payload[2]) + return 0 + elseif payload[1] == 2 then + M(pos):set_int("idx", payload[2]) + return 0 + end + end + return 2 -- unknown or invalid topic + end, on_node_load = function(pos) local meta = M(pos) meta:set_string("formspec", formspec(meta)) diff --git a/techage/move_controller/turncontroller.lua b/techage/move_controller/turncontroller.lua index a41fedf..33a3b56 100644 --- a/techage/move_controller/turncontroller.lua +++ b/techage/move_controller/turncontroller.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2020-2021 Joachim Stolberg + Copyright (C) 2020-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -83,20 +83,24 @@ minetest.register_node("techage:ta4_turncontroller", { meta:set_string("formspec", formspec(nvm, meta)) elseif fields.left then meta:set_string("status", "") - local new_posses = fly.rotate_nodes(pos, nvm.lpos, "l") - if new_posses then - nvm.lpos = new_posses - local name = player:get_player_name() - mark.stop(name) + if nvm.lpos then + local new_posses = fly.rotate_nodes(pos, nvm.lpos, "l") + if new_posses then + nvm.lpos = new_posses + local name = player:get_player_name() + mark.stop(name) + end end meta:set_string("formspec", formspec(nvm, meta)) elseif fields.right then meta:set_string("status", "") - local new_posses = fly.rotate_nodes(pos, nvm.lpos, "r") - if new_posses then - nvm.lpos = new_posses - local name = player:get_player_name() - mark.stop(name) + if nvm.lpos then + local new_posses = fly.rotate_nodes(pos, nvm.lpos, "r") + if new_posses then + nvm.lpos = new_posses + local name = player:get_player_name() + mark.stop(name) + end end meta:set_string("formspec", formspec(nvm, meta)) end @@ -152,6 +156,43 @@ techage.register_node({"techage:ta4_turncontroller"}, { end return false end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + local nvm = techage.get_nvm(pos) + if topic == 12 then + if payload[1] == 1 then + local nvm = techage.get_nvm(pos) + local new_posses = fly.rotate_nodes(pos, nvm.lpos, "l") + if new_posses then + nvm.lpos = new_posses + return 0 + end + return 3 + elseif payload[1] == 2 then + local nvm = techage.get_nvm(pos) + local new_posses = fly.rotate_nodes(pos, nvm.lpos, "r") + if new_posses then + nvm.lpos = new_posses + return 0 + end + return 3 + elseif payload[1] == 3 then + local nvm = techage.get_nvm(pos) + local new_posses = fly.rotate_nodes(pos, nvm.lpos, "r") + if new_posses then + nvm.lpos = new_posses + new_posses = fly.rotate_nodes(pos, nvm.lpos, "r") + if new_posses then + nvm.lpos = new_posses + return 0 + end + end + return 3 + end + return 2 + else + return 2 + end + end, }) minetest.register_craft({ diff --git a/techage/oil/drillbox.lua b/techage/oil/drillbox.lua index deec9fb..63b9c92 100644 --- a/techage/oil/drillbox.lua +++ b/techage/oil/drillbox.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019-2020 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -149,7 +149,7 @@ local function drilling(pos, crd, nvm, inv) inv:remove_item("src", ItemStack("techage:oil_drillbit")) nvm.drill_pos.y = nvm.drill_pos.y-1 crd.State:keep_running(pos, nvm, COUNTDOWN_TICKS) - elseif techage.can_node_dig(node, ndef) then + elseif techage.can_dig_node(node.name, ndef) then local drop_name = techage.dropped_node(node, ndef) if drop_name then local item = ItemStack(drop_name) @@ -255,6 +255,12 @@ local tubing = { on_recv_message = function(pos, src, topic, payload) return CRD(pos).State:on_receive_message(pos, topic, payload) 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) + return CRD(pos).State:on_beduino_request_data(pos, topic, payload) + end, on_node_load = function(pos, node) CRD(pos).State:on_node_load(pos) local nvm = techage.get_nvm(pos) diff --git a/techage/oil/pumpjack.lua b/techage/oil/pumpjack.lua index 7088107..ff66028 100644 --- a/techage/oil/pumpjack.lua +++ b/techage/oil/pumpjack.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019-2021 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -186,6 +186,24 @@ local tubing = { return CRD(pos).State:on_receive_message(pos, topic, payload) end end, + on_beduino_request_data = function(pos, src, topic, payload) + if topic == 134 then -- Load + local storage_pos = M(pos):get_string("storage_pos") + if storage_pos ~= "" then + local amount, capa = techage.explore.get_oil_amount(P(storage_pos)) + if amount and capa and capa > 0 then + if payload[1] == 1 then + return 0, {techage.power.percent(capa or 0, amount or 0)} + else + return 0, {math.min(amount or 0, 65535)} + end + end + end + return 2 + else + return CRD(pos).State:on_beduino_request_data(pos, topic, payload) + end + end, on_node_load = function(pos, node) CRD(pos).State:on_node_load(pos) if node.name == "techage:ta3_pumpjack_act" then diff --git a/techage/oil/reboiler.lua b/techage/oil/reboiler.lua index 51cdc41..a78d7fd 100644 --- a/techage/oil/reboiler.lua +++ b/techage/oil/reboiler.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019-2021 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -254,15 +254,6 @@ liquid.register_nodes({"techage:ta3_reboiler", "techage:ta3_reboiler_on"}, Pipe, power.register_nodes({"techage:ta3_reboiler", "techage:ta3_reboiler_on"}, Cable, "con") techage.register_node({"techage:ta3_reboiler", "techage:ta3_reboiler_on"}, { - on_recv_message = function(pos, src, topic, payload) - local nvm = techage.get_nvm(pos) - if topic == "state" then - nvm.state = nvm.state or techage.STOPPED - return techage.StateStrings[nvm.state] - else - return "unsupported" - end - end, on_node_load = function(pos, node) if node.name == "techage:ta3_reboiler_on" then play_sound(pos) diff --git a/techage/power/power_line.lua b/techage/power/power_line.lua index 39c92cc..e5e5f2c 100644 --- a/techage/power/power_line.lua +++ b/techage/power/power_line.lua @@ -20,11 +20,13 @@ local Cable = techage.ElectricCable local power = networks.power local function can_dig(pos, digger) - if M(pos):get_string("owner") == digger:get_player_name() then - return true - end - if minetest.check_player_privs(digger:get_player_name(), "powerline") then - return true + if digger and digger:is_player() then + if M(pos):get_string("owner") == digger:get_player_name() then + return true + end + if minetest.check_player_privs(digger:get_player_name(), "powerline") then + return true + end end return false end diff --git a/techage/power/powerswitch.lua b/techage/power/powerswitch.lua index ede50c3..95378ab 100644 --- a/techage/power/powerswitch.lua +++ b/techage/power/powerswitch.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019-2020 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -255,6 +255,36 @@ techage.register_node({"techage:powerswitch", "techage:powerswitch_on", return "unsupported" end end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + local node = techage.get_node_lvm(pos) + if topic == 1 and payload[1] == 1 and node.name == "techage:powerswitch" then + switch_on(pos, node, nil, "techage:powerswitch_on") + return 0 + elseif topic == 1 and payload[1] == 1 and node.name == "techage:powerswitchsmall" then + switch_on(pos, node, nil, "techage:powerswitchsmall_on") + return 0 + elseif topic == 1 and payload[1] == 0 and node.name == "techage:powerswitch_on" then + switch_off(pos, node, nil, "techage:powerswitch") + return 0 + elseif topic == 1 and payload[1] == 0 and node.name == "techage:powerswitchsmall_on" then + switch_off(pos, node, nil, "techage:powerswitchsmall") + return 0 + else + return 2 + end + end, + on_beduino_request_data = function(pos, src, topic, payload) + local node = techage.get_node_lvm(pos) + if topic == 142 then + if node.name == "techage:powerswitch_on" or + node.name == "techage:powerswitchsmall_on" then + return 0, {1} + end + return 0, {0} + else + return 2, "" + end + end, }) minetest.register_craft({ diff --git a/techage/recipe_checker.lua b/techage/recipe_checker.lua index 95558e1..93b83fe 100644 --- a/techage/recipe_checker.lua +++ b/techage/recipe_checker.lua @@ -14,7 +14,7 @@ end minetest.after(1, function() for name,_ in pairs(minetest.registered_items) do local mod = string.split(name, ":")[1] - if mod == "techage" or mod == "signs_bot" then + if mod == "techage" or mod == "signs_bot" or mod == "vm16" or mod == "beduino" then local recipes = minetest.get_all_craft_recipes(name) if recipes then for _,recipe in ipairs(recipes) do diff --git a/techage/settingtypes.txt b/techage/settingtypes.txt index 377539a..b1219fd 100644 --- a/techage/settingtypes.txt +++ b/techage/settingtypes.txt @@ -33,4 +33,8 @@ techage_command_limit (Max. number of commands sent per minute) int 1200 # Colliders are huge systems and should not be built on the surface. # 'techage_collider_min_depth specifies' the min. depth (Y) to build a TA4 Collider -techage_collider_min_depth (Min. depth to build a TA4 Collider) int -30 \ No newline at end of file +techage_collider_min_depth (Min. depth to build a TA4 Collider) int -30 + +# Average waiting time in minutes to get one Collider expoint. +# Default value is 60, which means one point per hour. +techage_expoint_rate_in_min (average waiting time for one expoint) int 60 \ No newline at end of file diff --git a/techage/solar/inverter.lua b/techage/solar/inverter.lua index 94c87ed..dc65574 100644 --- a/techage/solar/inverter.lua +++ b/techage/solar/inverter.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019-2021 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -218,6 +218,17 @@ techage.register_node({"techage:ta4_solar_inverter"}, { return State:on_receive_message(pos, topic, payload) end end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + return State:on_beduino_receive_cmnd(pos, topic, payload) + end, + on_beduino_request_data = function(pos, src, topic, payload) + local nvm = techage.get_nvm(pos) + if topic == 135 then -- Delivered Power + return 0, {math.floor((nvm.provided or 0) + 0.5)} + else + return State:on_beduino_request_data(pos, topic, payload) + end + end, }) control.register_nodes({"techage:ta4_solar_inverter"}, { diff --git a/techage/solar/minicell.lua b/techage/solar/minicell.lua index 1364ec1..6eedee5 100644 --- a/techage/solar/minicell.lua +++ b/techage/solar/minicell.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019-2021 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -120,6 +120,20 @@ techage.register_node({"techage:ta4_solar_minicell"}, { return "unsupported" end end, + on_beduino_request_data = function(pos, src, topic, payload) + local nvm = techage.get_nvm(pos) + if topic == 145 then -- Solar Cell State + if nvm.providing then + return 0, {2} + elseif (nvm.capa or 0) > 0 then + return 0, {1} + else + return 0, {0} + end + else + return 2, "" + end + end, on_node_load = function(pos) minetest.get_node_timer(pos):start(CYCLE_TIME) end, diff --git a/techage/ta2_energy_storage/ta2_winch.lua b/techage/ta2_energy_storage/ta2_winch.lua index 19308a9..00a7b54 100644 --- a/techage/ta2_energy_storage/ta2_winch.lua +++ b/techage/ta2_energy_storage/ta2_winch.lua @@ -56,7 +56,13 @@ end local function add_chest_entity(pos, nvm) local mem = techage.get_mem(pos) - local length = (nvm.length or MAX_ROPE_LEN) * (1 - (nvm.load or 0) / (nvm.capa or 1)) + local length + + if not nvm.capa or nvm.capa == 0 then + length = (nvm.length or MAX_ROPE_LEN) * (1 - (nvm.load or 0)) + else + length = (nvm.length or MAX_ROPE_LEN) * (1 - (nvm.load or 0) / nvm.capa) + end local y = pos.y - length - 1 techage.renew_rope(pos, length, true) if mem.obj then diff --git a/techage/ta3_power/akkubox.lua b/techage/ta3_power/akkubox.lua index f856c6f..e3276a7 100644 --- a/techage/ta3_power/akkubox.lua +++ b/techage/ta3_power/akkubox.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019-2020 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -172,6 +172,17 @@ techage.register_node({"techage:ta3_akku"}, { return State:on_receive_message(pos, topic, payload) end end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + return State:on_beduino_receive_cmnd(pos, topic, payload) + end, + on_beduino_request_data = function(pos, src, topic, payload) + local nvm = techage.get_nvm(pos) + if topic == 134 then -- load + return 0, {math.floor(techage.power.percent(PWR_CAPA, nvm.capa) + 0.5)} + else + return State:on_beduino_request_data(pos, topic, payload) + end + end, }) control.register_nodes({"techage:ta3_akku"}, { diff --git a/techage/ta3_power/tiny_generator.lua b/techage/ta3_power/tiny_generator.lua index db82c46..a6d31a9 100644 --- a/techage/ta3_power/tiny_generator.lua +++ b/techage/ta3_power/tiny_generator.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019-2021 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -338,6 +338,19 @@ techage.register_node({"techage:tiny_generator", "techage:tiny_generator_on"}, { return State:on_receive_message(pos, topic, payload) end end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + return State:on_beduino_receive_cmnd(pos, topic, payload) + end, + on_beduino_request_data = function(pos, src, topic, payload) + local nvm = techage.get_nvm(pos) + if topic == 135 then + return 0, {nvm.provided or 0} + elseif topic == 132 then + return 0, {techage.fuel.get_fuel_amount(nvm)} + else + return State:on_beduino_request_data(pos, topic, payload) + end + end, on_node_load = function(pos, node) State:on_node_load(pos) if node.name == "techage:tiny_generator_on" then diff --git a/techage/ta4_power/electricmeter.lua b/techage/ta4_power/electricmeter.lua index 75c149b..ca10ad9 100644 --- a/techage/ta4_power/electricmeter.lua +++ b/techage/ta4_power/electricmeter.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019-2021 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -160,6 +160,17 @@ techage.register_node({"techage:ta4_electricmeter"}, { return State:on_receive_message(pos, topic, payload) end end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + return State:on_beduino_receive_cmnd(pos, topic, payload) + end, + on_beduino_request_data = function(pos, src, topic, payload) + local nvm = techage.get_nvm(pos) + if topic == 146 then -- Consumption + return 0, {math.floor((nvm.units or 0) / techage.CYCLES_PER_DAY)} + else + return State:on_beduino_request_data(pos, topic, payload) + end + end, }) control.register_nodes({"techage:ta4_electricmeter"}, { diff --git a/techage/ta4_power/laser.lua b/techage/ta4_power/laser.lua index 9391d2d..ad1eb73 100644 --- a/techage/ta4_power/laser.lua +++ b/techage/ta4_power/laser.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019-2021 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg GPL v3 See LICENSE.txt for more information @@ -135,6 +135,14 @@ techage.register_node({"techage:ta4_laser_emitter"}, { return "unsupported" end end, + on_beduino_request_data = function(pos, src, topic, payload) + if topic == 142 then -- Binary State + local nvm = techage.get_nvm(pos) + return 0, {nvm.running and 1 or 0} + else + return 2, "" + end + end, }) power.register_nodes({"techage:ta4_laser_emitter", "techage:ta4_laser_receiver"}, Cable, "special", {"F"}) diff --git a/techage/ta4_power/transformer.lua b/techage/ta4_power/transformer.lua index 225df2c..d1ff216 100644 --- a/techage/ta4_power/transformer.lua +++ b/techage/ta4_power/transformer.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019-2021 Joachim Stolberg + Copyright (C) 2019-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -150,6 +150,12 @@ techage.register_node({"techage:ta4_transformer"}, { on_recv_message = function(pos, src, topic, payload) return State:on_receive_message(pos, topic, payload) end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + return State:on_beduino_receive_cmnd(pos, topic, payload) + end, + on_beduino_request_data = function(pos, src, topic, payload) + return State:on_beduino_request_data(pos, topic, payload) + end, }) control.register_nodes({"techage:ta4_transformer"}, { diff --git a/techage/teleport/teleport_pipe.lua b/techage/teleport/teleport_pipe.lua index 10b0454..e07a167 100644 --- a/techage/teleport/teleport_pipe.lua +++ b/techage/teleport/teleport_pipe.lua @@ -161,19 +161,21 @@ liquid.register_nodes({"techage:ta5_tele_pipe"}, Pipe, "tank", {"L"}, { nvm.oil_amount = nvm.oil_amount or 0 if not blocked and techage.is_operational(nvm) then local rmt_pos = teleport.get_remote_pos(pos) - local rmt_nvm = techage.get_nvm(rmt_pos) - if techage.is_operational(rmt_nvm) then - local pipe_dir = M(rmt_pos):get_int("pipe_dir") - blocked = true - local leftover = liquid.put(rmt_pos, Pipe, pipe_dir, name, amount) - blocked = false - if leftover < amount then - State:keep_running(pos, nvm, COUNTDOWN_TICKS) - State:keep_running(rmt_pos, rmt_nvm, COUNTDOWN_TICKS) + if rmt_pos then + local rmt_nvm = techage.get_nvm(rmt_pos) + if techage.is_operational(rmt_nvm) then + local pipe_dir = M(rmt_pos):get_int("pipe_dir") + blocked = true + local leftover = liquid.put(rmt_pos, Pipe, pipe_dir, name, amount) + blocked = false + if leftover < amount then + State:keep_running(pos, nvm, COUNTDOWN_TICKS) + State:keep_running(rmt_pos, rmt_nvm, COUNTDOWN_TICKS) + end + return leftover + else + State:blocked(pos, nvm, S("Remote block error")) end - return leftover - else - State:blocked(pos, nvm, S("Remote block error")) end end return amount @@ -184,6 +186,12 @@ techage.register_node({"techage:ta5_tele_pipe"}, { on_recv_message = function(pos, src, topic, payload) return State:on_receive_message(pos, topic, payload) end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + return State:on_beduino_receive_cmnd(pos, topic, payload) + end, + on_beduino_request_data = function(pos, src, topic, payload) + return State:on_beduino_request_data(pos, topic, payload) + end, }) power.register_nodes({"techage:ta5_tele_pipe"}, Cable, "con", {"B", "R", "F", "D", "U"}) diff --git a/techage/teleport/teleport_tube.lua b/techage/teleport/teleport_tube.lua index 11517d3..d1e278a 100644 --- a/techage/teleport/teleport_tube.lua +++ b/techage/teleport/teleport_tube.lua @@ -175,6 +175,12 @@ techage.register_node({"techage:ta5_tele_tube"}, { on_recv_message = function(pos, src, topic, payload) return State:on_receive_message(pos, topic, payload) end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + return State:on_beduino_receive_cmnd(pos, topic, payload) + end, + on_beduino_request_data = function(pos, src, topic, payload) + return State:on_beduino_request_data(pos, topic, payload) + end, }) power.register_nodes({"techage:ta5_tele_tube"}, Cable, "con", {"B", "R", "F", "D", "U"}) diff --git a/techage/textures/techage_appl_lightdetector.png b/techage/textures/techage_appl_lightdetector.png new file mode 100755 index 0000000..ebd2db7 Binary files /dev/null and b/techage/textures/techage_appl_lightdetector.png differ diff --git a/techage/textures/techage_appl_lightdetector_on.png b/techage/textures/techage_appl_lightdetector_on.png new file mode 100755 index 0000000..6994033 Binary files /dev/null and b/techage/textures/techage_appl_lightdetector_on.png differ diff --git a/techage/tools/repairkit.lua b/techage/tools/repairkit.lua index 2622a47..58ba18c 100644 --- a/techage/tools/repairkit.lua +++ b/techage/tools/repairkit.lua @@ -76,6 +76,11 @@ local function read_state(itemstack, user, pointed_thing) state = dump(state) minetest.chat_send_player(user:get_player_name(), ndef.description.." "..number..": state = "..state.." ") end + local state = techage.send_single("0", number, "count", nil) + if state and state ~= "" and state ~= "unsupported" then + state = dump(state) + minetest.chat_send_player(user:get_player_name(), ndef.description.." "..number..": count = "..state.." ") + end local fuel = techage.send_single("0", number, "fuel", nil) if fuel and fuel ~= "" and fuel ~= "unsupported" then fuel = dump(fuel) diff --git a/techage/wind_turbine/rotor.lua b/techage/wind_turbine/rotor.lua index 5be96d2..d84245a 100644 --- a/techage/wind_turbine/rotor.lua +++ b/techage/wind_turbine/rotor.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2019-2021 DS-Minetest, Joachim Stolberg + Copyright (C) 2019-2022 DS-Minetest, Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -117,9 +117,11 @@ local function stop_rotor(pos, nvm, state) end local function can_start(pos, nvm) + check_rotor(pos, nvm) if nvm.error then return nvm.error end + add_rotor(pos, nvm) return true end @@ -305,9 +307,41 @@ techage.register_node({"techage:ta4_wind_turbine"}, { return "unsupported" end end, + on_beduino_receive_cmnd = function(pos, src, topic, payload) + local nvm = techage.get_nvm(pos) + if topic == 1 and payload[1] == 1 then + State:start(pos, nvm) + elseif topic == 1 and payload[1] == 0 then + State:stop(pos, nvm) + else + return 2 + end + return 0 + end, + on_beduino_request_data = function(pos, src, topic, payload) + local nvm = techage.get_nvm(pos) + if topic == 129 then + local node = minetest.get_node(pos) + if node.name == "ignore" then -- unloaded node? + return 0, {techage.UNLOADED} + end + if nvm.error then + return 0, {techage.FAULT} + elseif techage.is_running(nvm) then + return 0, {techage.RUNNING} + else + return 0, {techage.STOPPED} + end + elseif topic == 135 then -- Delivered Power + return 0, {nvm.delivered or 0} + else + return 2, "" + end + end, on_node_load = function(pos) local nvm = techage.get_nvm(pos) add_rotor(pos, nvm, true) + start_rotor(pos, nvm) minetest.get_node_timer(pos):start(CYCLE_TIME) end, }) diff --git a/tubelib2/README.md b/tubelib2/README.md index acb8c22..e6e69da 100644 --- a/tubelib2/README.md +++ b/tubelib2/README.md @@ -50,8 +50,7 @@ func(node, pos, out_dir, peer_pos, peer_in_dir) will be called for every change ## Dependencies -default -optional: intllib +optional: default ## License @@ -90,5 +89,6 @@ Textures: CC0 - 2021-01-23 v2.0 * Add functions for easy & fast 'valid side' checking (PR #8) - 2021-05-24 v2.1 * Add API functions 'register_on_tube_update2' - 2022-01-05 v2.2 * Extend the 'node.param2' support for all 24 possible values +- 2022-03-11 v2.2.1 * Changed to minetest 5.0 translation (#12) diff --git a/tubelib2/depends.txt b/tubelib2/depends.txt deleted file mode 100644 index 60f8390..0000000 --- a/tubelib2/depends.txt +++ /dev/null @@ -1,2 +0,0 @@ -default? -intllib? diff --git a/tubelib2/i18n.py b/tubelib2/i18n.py new file mode 100644 index 0000000..5390ab9 --- /dev/null +++ b/tubelib2/i18n.py @@ -0,0 +1,476 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# Script to generate the template file and update the translation files. +# Copy the script into the mod or modpack root folder and run it there. +# +# Copyright (C) 2019 Joachim Stolberg, 2020 FaceDeer, 2020 Louis Royer +# LGPLv2.1+ +# +# See https://github.com/minetest-tools/update_translations for +# potential future updates to this script. + +from __future__ import print_function +import os, fnmatch, re, shutil, errno +from sys import argv as _argv +from sys import stderr as _stderr + +# Running params +params = {"recursive": False, + "help": False, + "mods": False, + "verbose": False, + "folders": [], + "no-old-file": False, + "break-long-lines": False, + "sort": False, + "print-source": False, + "truncate-unused": False, +} +# Available CLI options +options = {"recursive": ['--recursive', '-r'], + "help": ['--help', '-h'], + "mods": ['--installed-mods', '-m'], + "verbose": ['--verbose', '-v'], + "no-old-file": ['--no-old-file', '-O'], + "break-long-lines": ['--break-long-lines', '-b'], + "sort": ['--sort', '-s'], + "print-source": ['--print-source', '-p'], + "truncate-unused": ['--truncate-unused', '-t'], +} + +# Strings longer than this will have extra space added between +# them in the translation files to make it easier to distinguish their +# beginnings and endings at a glance +doublespace_threshold = 80 + +def set_params_folders(tab: list): + '''Initialize params["folders"] from CLI arguments.''' + # Discarding argument 0 (tool name) + for param in tab[1:]: + stop_param = False + for option in options: + if param in options[option]: + stop_param = True + break + if not stop_param: + params["folders"].append(os.path.abspath(param)) + +def set_params(tab: list): + '''Initialize params from CLI arguments.''' + for option in options: + for option_name in options[option]: + if option_name in tab: + params[option] = True + break + +def print_help(name): + '''Prints some help message.''' + print(f'''SYNOPSIS + {name} [OPTIONS] [PATHS...] +DESCRIPTION + {', '.join(options["help"])} + prints this help message + {', '.join(options["recursive"])} + run on all subfolders of paths given + {', '.join(options["mods"])} + run on locally installed modules + {', '.join(options["no-old-file"])} + do not create *.old files + {', '.join(options["sort"])} + sort output strings alphabetically + {', '.join(options["break-long-lines"])} + add extra line breaks before and after long strings + {', '.join(options["print-source"])} + add comments denoting the source file + {', '.join(options["verbose"])} + add output information + {', '.join(options["truncate-unused"])} + delete unused strings from files +''') + + +def main(): + '''Main function''' + set_params(_argv) + set_params_folders(_argv) + if params["help"]: + print_help(_argv[0]) + elif params["recursive"] and params["mods"]: + print("Option --installed-mods is incompatible with --recursive") + else: + # Add recursivity message + print("Running ", end='') + if params["recursive"]: + print("recursively ", end='') + # Running + if params["mods"]: + print(f"on all locally installed modules in {os.path.expanduser('~/.minetest/mods/')}") + run_all_subfolders(os.path.expanduser("~/.minetest/mods")) + elif len(params["folders"]) >= 2: + print("on folder list:", params["folders"]) + for f in params["folders"]: + if params["recursive"]: + run_all_subfolders(f) + else: + update_folder(f) + elif len(params["folders"]) == 1: + print("on folder", params["folders"][0]) + if params["recursive"]: + run_all_subfolders(params["folders"][0]) + else: + update_folder(params["folders"][0]) + else: + print("on folder", os.path.abspath("./")) + if params["recursive"]: + run_all_subfolders(os.path.abspath("./")) + else: + update_folder(os.path.abspath("./")) + +#group 2 will be the string, groups 1 and 3 will be the delimiters (" or ') +#See https://stackoverflow.com/questions/46967465/regex-match-text-in-either-single-or-double-quote +pattern_lua_s = re.compile(r'[\.=^\t,{\(\s]N?S\(\s*(["\'])((?:\\\1|(?:(?!\1)).)*)(\1)[\s,\)]', re.DOTALL) +pattern_lua_fs = re.compile(r'[\.=^\t,{\(\s]N?FS\(\s*(["\'])((?:\\\1|(?:(?!\1)).)*)(\1)[\s,\)]', re.DOTALL) +pattern_lua_bracketed_s = re.compile(r'[\.=^\t,{\(\s]N?S\(\s*\[\[(.*?)\]\][\s,\)]', re.DOTALL) +pattern_lua_bracketed_fs = re.compile(r'[\.=^\t,{\(\s]N?FS\(\s*\[\[(.*?)\]\][\s,\)]', re.DOTALL) + +# Handles "concatenation" .. " of strings" +pattern_concat = re.compile(r'["\'][\s]*\.\.[\s]*["\']', re.DOTALL) + +pattern_tr = re.compile(r'(.*?[^@])=(.*)') +pattern_name = re.compile(r'^name[ ]*=[ ]*([^ \n]*)') +pattern_tr_filename = re.compile(r'\.tr$') +pattern_po_language_code = re.compile(r'(.*)\.po$') + +#attempt to read the mod's name from the mod.conf file or folder name. Returns None on failure +def get_modname(folder): + try: + with open(os.path.join(folder, "mod.conf"), "r", encoding='utf-8') as mod_conf: + for line in mod_conf: + match = pattern_name.match(line) + if match: + return match.group(1) + except FileNotFoundError: + if not os.path.isfile(os.path.join(folder, "modpack.txt")): + folder_name = os.path.basename(folder) + # Special case when run in Minetest's builtin directory + if folder_name == "builtin": + return "__builtin" + else: + return folder_name + else: + return None + return None + +#If there are already .tr files in /locale, returns a list of their names +def get_existing_tr_files(folder): + out = [] + for root, dirs, files in os.walk(os.path.join(folder, 'locale/')): + for name in files: + if pattern_tr_filename.search(name): + out.append(name) + return out + +# A series of search and replaces that massage a .po file's contents into +# a .tr file's equivalent +def process_po_file(text): + # The first three items are for unused matches + text = re.sub(r'#~ msgid "', "", text) + text = re.sub(r'"\n#~ msgstr ""\n"', "=", text) + text = re.sub(r'"\n#~ msgstr "', "=", text) + # comment lines + text = re.sub(r'#.*\n', "", text) + # converting msg pairs into "=" pairs + text = re.sub(r'msgid "', "", text) + text = re.sub(r'"\nmsgstr ""\n"', "=", text) + text = re.sub(r'"\nmsgstr "', "=", text) + # various line breaks and escape codes + text = re.sub(r'"\n"', "", text) + text = re.sub(r'"\n', "\n", text) + text = re.sub(r'\\"', '"', text) + text = re.sub(r'\\n', '@n', text) + # remove header text + text = re.sub(r'=Project-Id-Version:.*\n', "", text) + # remove double-spaced lines + text = re.sub(r'\n\n', '\n', text) + return text + +# Go through existing .po files and, if a .tr file for that language +# *doesn't* exist, convert it and create it. +# The .tr file that results will subsequently be reprocessed so +# any "no longer used" strings will be preserved. +# Note that "fuzzy" tags will be lost in this process. +def process_po_files(folder, modname): + for root, dirs, files in os.walk(os.path.join(folder, 'locale/')): + for name in files: + code_match = pattern_po_language_code.match(name) + if code_match == None: + continue + language_code = code_match.group(1) + tr_name = f'{modname}.{language_code}.tr' + tr_file = os.path.join(root, tr_name) + if os.path.exists(tr_file): + if params["verbose"]: + print(f"{tr_name} already exists, ignoring {name}") + continue + fname = os.path.join(root, name) + with open(fname, "r", encoding='utf-8') as po_file: + if params["verbose"]: + print(f"Importing translations from {name}") + text = process_po_file(po_file.read()) + with open(tr_file, "wt", encoding='utf-8') as tr_out: + tr_out.write(text) + +# from https://stackoverflow.com/questions/600268/mkdir-p-functionality-in-python/600612#600612 +# Creates a directory if it doesn't exist, silently does +# nothing if it already exists +def mkdir_p(path): + try: + os.makedirs(path) + except OSError as exc: # Python >2.5 + if exc.errno == errno.EEXIST and os.path.isdir(path): + pass + else: raise + +# Converts the template dictionary to a text to be written as a file +# dKeyStrings is a dictionary of localized string to source file sets +# dOld is a dictionary of existing translations and comments from +# the previous version of this text +def strings_to_text(dkeyStrings, dOld, mod_name, header_comments): + lOut = [f"# textdomain: {mod_name}"] + if header_comments is not None: + lOut.append(header_comments) + + dGroupedBySource = {} + + for key in dkeyStrings: + sourceList = list(dkeyStrings[key]) + if params["sort"]: + sourceList.sort() + sourceString = "\n".join(sourceList) + listForSource = dGroupedBySource.get(sourceString, []) + listForSource.append(key) + dGroupedBySource[sourceString] = listForSource + + lSourceKeys = list(dGroupedBySource.keys()) + lSourceKeys.sort() + for source in lSourceKeys: + localizedStrings = dGroupedBySource[source] + if params["sort"]: + localizedStrings.sort() + if params["print-source"]: + if lOut[-1] != "": + lOut.append("") + lOut.append(source) + for localizedString in localizedStrings: + val = dOld.get(localizedString, {}) + translation = val.get("translation", "") + comment = val.get("comment") + if params["break-long-lines"] and len(localizedString) > doublespace_threshold and not lOut[-1] == "": + lOut.append("") + if comment != None and comment != "" and not comment.startswith("# textdomain:"): + lOut.append(comment) + lOut.append(f"{localizedString}={translation}") + if params["break-long-lines"] and len(localizedString) > doublespace_threshold: + lOut.append("") + + + unusedExist = False + if not params["truncate-unused"]: + for key in dOld: + if key not in dkeyStrings: + val = dOld[key] + translation = val.get("translation") + comment = val.get("comment") + # only keep an unused translation if there was translated + # text or a comment associated with it + if translation != None and (translation != "" or comment): + if not unusedExist: + unusedExist = True + lOut.append("\n\n##### not used anymore #####\n") + if params["break-long-lines"] and len(key) > doublespace_threshold and not lOut[-1] == "": + lOut.append("") + if comment != None: + lOut.append(comment) + lOut.append(f"{key}={translation}") + if params["break-long-lines"] and len(key) > doublespace_threshold: + lOut.append("") + return "\n".join(lOut) + '\n' + +# Writes a template.txt file +# dkeyStrings is the dictionary returned by generate_template +def write_template(templ_file, dkeyStrings, mod_name): + # read existing template file to preserve comments + existing_template = import_tr_file(templ_file) + + text = strings_to_text(dkeyStrings, existing_template[0], mod_name, existing_template[2]) + mkdir_p(os.path.dirname(templ_file)) + with open(templ_file, "wt", encoding='utf-8') as template_file: + template_file.write(text) + + +# Gets all translatable strings from a lua file +def read_lua_file_strings(lua_file): + lOut = [] + with open(lua_file, encoding='utf-8') as text_file: + text = text_file.read() + #TODO remove comments here + + text = re.sub(pattern_concat, "", text) + + strings = [] + for s in pattern_lua_s.findall(text): + strings.append(s[1]) + for s in pattern_lua_bracketed_s.findall(text): + strings.append(s) + for s in pattern_lua_fs.findall(text): + strings.append(s[1]) + for s in pattern_lua_bracketed_fs.findall(text): + strings.append(s) + + for s in strings: + s = re.sub(r'"\.\.\s+"', "", s) + s = re.sub("@[^@=0-9]", "@@", s) + s = s.replace('\\"', '"') + s = s.replace("\\'", "'") + s = s.replace("\n", "@n") + s = s.replace("\\n", "@n") + s = s.replace("=", "@=") + lOut.append(s) + return lOut + +# Gets strings from an existing translation file +# returns both a dictionary of translations +# and the full original source text so that the new text +# can be compared to it for changes. +# Returns also header comments in the third return value. +def import_tr_file(tr_file): + dOut = {} + text = None + header_comment = None + if os.path.exists(tr_file): + with open(tr_file, "r", encoding='utf-8') as existing_file : + # save the full text to allow for comparison + # of the old version with the new output + text = existing_file.read() + existing_file.seek(0) + # a running record of the current comment block + # we're inside, to allow preceeding multi-line comments + # to be retained for a translation line + latest_comment_block = None + for line in existing_file.readlines(): + line = line.rstrip('\n') + if line.startswith("###"): + if header_comment is None and not latest_comment_block is None: + # Save header comments + header_comment = latest_comment_block + # Strip textdomain line + tmp_h_c = "" + for l in header_comment.split('\n'): + if not l.startswith("# textdomain:"): + tmp_h_c += l + '\n' + header_comment = tmp_h_c + + # Reset comment block if we hit a header + latest_comment_block = None + continue + elif line.startswith("#"): + # Save the comment we're inside + if not latest_comment_block: + latest_comment_block = line + else: + latest_comment_block = latest_comment_block + "\n" + line + continue + match = pattern_tr.match(line) + if match: + # this line is a translated line + outval = {} + outval["translation"] = match.group(2) + if latest_comment_block: + # if there was a comment, record that. + outval["comment"] = latest_comment_block + latest_comment_block = None + dOut[match.group(1)] = outval + return (dOut, text, header_comment) + +# Walks all lua files in the mod folder, collects translatable strings, +# and writes it to a template.txt file +# Returns a dictionary of localized strings to source file sets +# that can be used with the strings_to_text function. +def generate_template(folder, mod_name): + dOut = {} + for root, dirs, files in os.walk(folder): + for name in files: + if fnmatch.fnmatch(name, "*.lua"): + fname = os.path.join(root, name) + found = read_lua_file_strings(fname) + if params["verbose"]: + print(f"{fname}: {str(len(found))} translatable strings") + + for s in found: + sources = dOut.get(s, set()) + sources.add(f"### {os.path.basename(fname)} ###") + dOut[s] = sources + + if len(dOut) == 0: + return None + templ_file = os.path.join(folder, "locale/template.txt") + write_template(templ_file, dOut, mod_name) + return dOut + +# Updates an existing .tr file, copying the old one to a ".old" file +# if any changes have happened +# dNew is the data used to generate the template, it has all the +# currently-existing localized strings +def update_tr_file(dNew, mod_name, tr_file): + if params["verbose"]: + print(f"updating {tr_file}") + + tr_import = import_tr_file(tr_file) + dOld = tr_import[0] + textOld = tr_import[1] + + textNew = strings_to_text(dNew, dOld, mod_name, tr_import[2]) + + if textOld and textOld != textNew: + print(f"{tr_file} has changed.") + if not params["no-old-file"]: + shutil.copyfile(tr_file, f"{tr_file}.old") + + with open(tr_file, "w", encoding='utf-8') as new_tr_file: + new_tr_file.write(textNew) + +# Updates translation files for the mod in the given folder +def update_mod(folder): + modname = get_modname(folder) + if modname is not None: + process_po_files(folder, modname) + print(f"Updating translations for {modname}") + data = generate_template(folder, modname) + if data == None: + print(f"No translatable strings found in {modname}") + else: + for tr_file in get_existing_tr_files(folder): + update_tr_file(data, modname, os.path.join(folder, "locale/", tr_file)) + else: + print(f"\033[31mUnable to find modname in folder {folder}.\033[0m", file=_stderr) + exit(1) + +# Determines if the folder being pointed to is a mod or a mod pack +# and then runs update_mod accordingly +def update_folder(folder): + is_modpack = os.path.exists(os.path.join(folder, "modpack.txt")) or os.path.exists(os.path.join(folder, "modpack.conf")) + if is_modpack: + subfolders = [f.path for f in os.scandir(folder) if f.is_dir() and not f.name.startswith('.')] + for subfolder in subfolders: + update_mod(subfolder) + else: + update_mod(folder) + print("Done.") + +def run_all_subfolders(folder): + for modfolder in [f.path for f in os.scandir(folder) if f.is_dir() and not f.name.startswith('.')]: + update_folder(modfolder) + + +main() diff --git a/tubelib2/init.lua b/tubelib2/init.lua index 509dc07..e44736f 100644 --- a/tubelib2/init.lua +++ b/tubelib2/init.lua @@ -1,9 +1,9 @@ tubelib2 = {} -local MP = minetest.get_modpath("tubelib2") +-- Load support for I18n. +tubelib2.S = minetest.get_translator("tubelib2") --- Load support for intllib. -dofile(MP .. "/intllib.lua") +local MP = minetest.get_modpath("tubelib2") dofile(MP .. "/internal2.lua") dofile(MP .. "/internal1.lua") dofile(MP .. "/tube_api.lua") diff --git a/tubelib2/internal1.lua b/tubelib2/internal1.lua index 1ee3246..7fcd603 100644 --- a/tubelib2/internal1.lua +++ b/tubelib2/internal1.lua @@ -15,13 +15,12 @@ ]]-- -- for lazy programmers -local S = function(pos) if pos then return minetest.pos_to_string(pos) end end -local P = minetest.string_to_pos +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 --- Load support for intllib. -local MP = minetest.get_modpath("tubelib2") -local I,_ = dofile(MP.."/intllib.lua") +-- Load support for I18n. +local S = tubelib2.S local Tube = tubelib2.Tube local Turn180Deg = tubelib2.Turn180Deg @@ -71,11 +70,11 @@ end -- pos/dir are the pos of the stable secondary node pointing to the head tube node. function Tube:del_from_cache(pos, dir) - local key = S(pos) + local key = P2S(pos) if self.connCache[key] and self.connCache[key][dir] then local pos2 = self.connCache[key][dir].pos2 local dir2 = self.connCache[key][dir].dir2 - local key2 = S(pos2) + local key2 = P2S(pos2) if self.connCache[key2] and self.connCache[key2][dir2] then self.connCache[key2][dir2] = nil if self.debug_info then self.debug_info(pos2, "del") end @@ -89,7 +88,7 @@ end -- pos/dir are the pos of the secondary nodes pointing to the head tube nodes. function Tube:add_to_cache(pos1, dir1, pos2, dir2) - local key = S(pos1) + local key = P2S(pos1) if not self.connCache[key] then self.connCache[key] = {} end @@ -120,9 +119,9 @@ function Tube:infotext(pos1, pos2) if self.show_infotext then if pos1 and pos2 then if vector.equals(pos1, pos2) then - M(pos1):set_string("infotext", I("Not connected!")) + M(pos1):set_string("infotext", S("Not connected!")) else - M(pos1):set_string("infotext", I("Connected with ")..S(pos2)) + M(pos1):set_string("infotext", S("Connected to @1", P2S(pos2))) end end end @@ -135,10 +134,10 @@ end -- Pairing helper function. NOT USED (see internal2.lua)!!! function Tube:store_teleport_data(pos, peer_pos) local meta = M(pos) - meta:set_string("tele_pos", S(peer_pos)) + meta:set_string("tele_pos", P2S(peer_pos)) meta:set_string("channel", nil) meta:set_string("formspec", nil) - meta:set_string("infotext", I("Paired with ")..S(peer_pos)) + meta:set_string("infotext", S("Paired with @1", P2S(peer_pos))) return meta:get_int("tube_dir") end diff --git a/tubelib2/internal2.lua b/tubelib2/internal2.lua index 6c9d0dd..5a641d0 100644 --- a/tubelib2/internal2.lua +++ b/tubelib2/internal2.lua @@ -13,14 +13,12 @@ ]]-- -- for lazy programmers -local S = function(pos) if pos then return minetest.pos_to_string(pos) end end -local P = minetest.string_to_pos +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 --- Load support for intllib. -local MP = minetest.get_modpath("tubelib2") -local I,IS = dofile(MP.."/intllib.lua") - +-- Load support for I18n. +local S = tubelib2.S local Tube = {} @@ -376,10 +374,10 @@ end -- Pairing helper function function Tube:store_teleport_data(pos, peer_pos) local meta = M(pos) - meta:set_string("tele_pos", S(peer_pos)) + meta:set_string("tele_pos", P2S(peer_pos)) meta:set_string("channel", nil) meta:set_string("formspec", nil) - meta:set_string("infotext", I("Connected with ")..S(peer_pos)) + meta:set_string("infotext", S("Connected to @1", P2S(peer_pos))) return meta:get_int("tube_dir") end @@ -393,7 +391,7 @@ function Tube:get_next_teleport_node(pos, dir) local meta = M(npos) local s = meta:get_string("tele_pos") if s ~= "" then - local tele_pos = P(s) + local tele_pos = S2P(s) local tube_dir = M(tele_pos):get_int("tube_dir") if tube_dir ~= 0 then return tele_pos, tube_dir @@ -405,7 +403,7 @@ end function Tube:dbg_out() for pos1,item1 in pairs(self.connCache) do for dir1,item2 in pairs(item1) do - print("pos1="..pos1..", dir1="..dir1..", pos2="..S(item2.pos2)..", dir2="..item2.dir2) + print("pos1="..pos1..", dir1="..dir1..", pos2="..P2S(item2.pos2)..", dir2="..item2.dir2) end end end diff --git a/tubelib2/intllib.lua b/tubelib2/intllib.lua deleted file mode 100644 index 6669d72..0000000 --- a/tubelib2/intllib.lua +++ /dev/null @@ -1,45 +0,0 @@ - --- Fallback functions for when `intllib` is not installed. --- Code released under Unlicense . - --- Get the latest version of this file at: --- https://raw.githubusercontent.com/minetest-mods/intllib/master/lib/intllib.lua - -local function format(str, ...) - local args = { ... } - local function repl(escape, open, num, close) - if escape == "" then - local replacement = tostring(args[tonumber(num)]) - if open == "" then - replacement = replacement..close - end - return replacement - else - return "@"..open..num..close - end - end - return (str:gsub("(@?)@(%(?)(%d+)(%)?)", repl)) -end - -local gettext, ngettext -if minetest.get_modpath("intllib") then - if intllib.make_gettext_pair then - -- New method using gettext. - gettext, ngettext = intllib.make_gettext_pair() - else - -- Old method using text files. - gettext = intllib.Getter() - end -end - --- Fill in missing functions. - -gettext = gettext or function(msgid, ...) - return format(msgid, ...) -end - -ngettext = ngettext or function(msgid, msgid_plural, n, ...) - return format(n==1 and msgid or msgid_plural, ...) -end - -return gettext, ngettext diff --git a/tubelib2/locale/de.mo b/tubelib2/locale/de.mo deleted file mode 100644 index c769b79..0000000 Binary files a/tubelib2/locale/de.mo and /dev/null differ diff --git a/tubelib2/locale/de.po b/tubelib2/locale/de.po deleted file mode 100644 index b19d36e..0000000 --- a/tubelib2/locale/de.po +++ /dev/null @@ -1,45 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR , YEAR. -# -msgid "" -msgstr "" -"Project-Id-Version: \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-12-22 11:16+0100\n" -"PO-Revision-Date: 2018-12-22 11:19+0100\n" -"Last-Translator: \n" -"Language-Team: \n" -"Language: de\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 2.0.6\n" - -#: tube_api.lua -msgid "Maximum length reached!" -msgstr "Maximale Länge erreicht!" - -#: tube_api.lua -msgid "Pairing is missing" -msgstr "Das Pairing fehlt noch" - -#: tube_api.lua -msgid "Connection to a tube is missing!" -msgstr "Eine Verbindung zu einer Röhre fehlt!" - -#: internal1.lua -msgid "Not connected!" -msgstr "Nicht verbunden!" - -#: internal1.lua internal2.lua -msgid "Connected with " -msgstr "Verbunden mit " - -#: internal1.lua -msgid "Paired with " -msgstr "Gepaart mit " - -#~ msgid "Unconnected" -#~ msgstr "Nicht verbunden" diff --git a/tubelib2/locale/template.pot b/tubelib2/locale/template.pot deleted file mode 100644 index fa6cc33..0000000 --- a/tubelib2/locale/template.pot +++ /dev/null @@ -1,42 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR , YEAR. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-12-22 11:16+0100\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=CHARSET\n" -"Content-Transfer-Encoding: 8bit\n" - -#: tube_api.lua -msgid "Maximum length reached!" -msgstr "" - -#: tube_api.lua -msgid "Pairing is missing" -msgstr "" - -#: tube_api.lua -msgid "Connection to a tube is missing!" -msgstr "" - -#: internal1.lua -msgid "Not connected!" -msgstr "" - -#: internal1.lua internal2.lua -msgid "Connected with " -msgstr "" - -#: internal1.lua -msgid "Paired with " -msgstr "" diff --git a/tubelib2/locale/template.txt b/tubelib2/locale/template.txt new file mode 100644 index 0000000..3c47e84 --- /dev/null +++ b/tubelib2/locale/template.txt @@ -0,0 +1,8 @@ +# textdomain: tubelib2 +Not connected!= +Paired with @1= +Connected to @1= +Maximum length reached!= +Pairing is missing= +Connection to a tube is missing!= +Pairing is missing (@1)= diff --git a/tubelib2/locale/tubelib2.de.tr b/tubelib2/locale/tubelib2.de.tr new file mode 100644 index 0000000..b41fa5e --- /dev/null +++ b/tubelib2/locale/tubelib2.de.tr @@ -0,0 +1,8 @@ +# textdomain: tubelib2 +Not connected!=Nicht verbunden! +Paired with @1=Gepaart mit @1 +Connected to @1=erbunden mit @1 +Maximum length reached!=Maximale Länge erreicht! +Pairing is missing=Das Pairing fehlt +Connection to a tube is missing!=Eine Verbindung zu einer Röhre fehlt! +Pairing is missing (@1)=Das Pairing fehlt (@1) diff --git a/tubelib2/mod.conf b/tubelib2/mod.conf index a967bf9..a5c92ea 100644 --- a/tubelib2/mod.conf +++ b/tubelib2/mod.conf @@ -1 +1,3 @@ name=tubelib2 +description = A library for mods which need connecting tubes / pipes / cables or similar. +optional_depends = default diff --git a/tubelib2/settingtypes.txt b/tubelib2/settingtypes.txt index 7386cc2..f6860e1 100644 --- a/tubelib2/settingtypes.txt +++ b/tubelib2/settingtypes.txt @@ -1,3 +1,3 @@ -# Maximim number of Forceload Blocks per player (default 20) -tubelib2_testingblocks_enabled (enbale the testing blocks) bool false +# Enable/disable test blocks +tubelib2_testingblocks_enabled (enable test blocks) bool false diff --git a/tubelib2/storage.lua b/tubelib2/storage.lua index b41657c..6a88bd0 100644 --- a/tubelib2/storage.lua +++ b/tubelib2/storage.lua @@ -129,16 +129,22 @@ function tubelib2.get_mem_data(pos, key, default) return tubelib2.get_mem(pos)[key] or default end -function tubelib2.walk_over_all(clbk) +function tubelib2.walk_over_all(clbk, key) local data = storage:to_table() for block_key,sblock in pairs(data.fields) do local block = minetest.deserialize(sblock) for node_key,mem in pairs(block) do - if mem then - if node_key ~= "used" and node_key ~= "best_before" then + if mem and node_key ~= "used" and node_key ~= "best_before" then + if key == nil or (type(mem) == "table" and mem[key] ~= nil) then local pos = keys_to_pos(block_key, node_key) local node = tubelib2.get_node_lvm(pos) - clbk(pos, node, mem) + if key ~= nil then + -- only specified 'key' + clbk(pos, node, {[key] = mem[key]}) + else + -- without specified 'key' + clbk(pos, node, mem) + end end end end diff --git a/tubelib2/tube_api.lua b/tubelib2/tube_api.lua index 48293cd..5358e54 100644 --- a/tubelib2/tube_api.lua +++ b/tubelib2/tube_api.lua @@ -16,12 +16,11 @@ tubelib2.version = 2.2 -- for lazy programmers -local S = function(pos) if pos then return minetest.pos_to_string(pos) end end +local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end local M = minetest.get_meta --- Load support for intllib. -local MP = minetest.get_modpath("tubelib2") -local I,_ = dofile(MP.."/intllib.lua") +-- Load support for I18n. +local S = tubelib2.S -- Cardinal directions, regardless of orientation local Dir2Str = {"north", "east", "south", "west", "down", "up"} @@ -119,8 +118,8 @@ local function update2(self, pos1, dir1, pos2, dir2) -- reset next tube(s) to head tube(s) again local param2 = self:encode_param2(dir1, dir2, 2) self:update_after_dig_tube(pos1, param2) - M(get_pos(pos1, dir1)):set_string("infotext", I("Maximum length reached!")) - M(get_pos(pos1, dir2)):set_string("infotext", I("Maximum length reached!")) + M(get_pos(pos1, dir1)):set_string("infotext", S("Maximum length reached!")) + M(get_pos(pos1, dir2)):set_string("infotext", S("Maximum length reached!")) return false end self:infotext(fpos1, fpos2) @@ -399,7 +398,7 @@ end -- The returned pos is the destination position, dir -- is the direction into the destination node. function Tube:get_connected_node_pos(pos, dir) - local key = S(pos) + local key = P2S(pos) if self.connCache[key] and self.connCache[key][dir] then local item = self.connCache[key][dir] return item.pos2, Turn180Deg[item.dir2] @@ -457,10 +456,10 @@ function Tube:prepare_pairing(pos, tube_dir, sFormspec) elseif tube_dir then meta:set_int("tube_dir", tube_dir) meta:set_string("channel", nil) - meta:set_string("infotext", I("Pairing is missing")) + meta:set_string("infotext", S("Pairing is missing")) meta:set_string("formspec", sFormspec) else - meta:set_string("infotext", I("Connection to a tube is missing!")) + meta:set_string("infotext", S("Connection to a tube is missing!")) end end @@ -477,7 +476,7 @@ function Tube:pairing(pos, channel) self.pairingList[channel] = pos local meta = M(pos) meta:set_string("channel", channel) - meta:set_string("infotext", I("Pairing is missing").." ("..channel..")") + meta:set_string("infotext", S("Pairing is missing (@1)", channel)) return false end end @@ -493,7 +492,7 @@ function Tube:stop_pairing(pos, oldmetadata, sFormspec) peer_meta:set_string("channel", nil) peer_meta:set_string("tele_pos", nil) peer_meta:set_string("formspec", sFormspec) - peer_meta:set_string("infotext", I("Pairing is missing")) + peer_meta:set_string("infotext", S("Pairing is missing")) end elseif oldmetadata.fields.channel then self.pairingList[oldmetadata.fields.channel] = nil diff --git a/tubelib2/tube_test.lua b/tubelib2/tube_test.lua index b925ae7..57f5722 100644 --- a/tubelib2/tube_test.lua +++ b/tubelib2/tube_test.lua @@ -82,9 +82,9 @@ Tube:register_on_tube_update(function(node, pos, out_dir, peer_pos, peer_in_dir) print(P2S(pos).." to the "..sdir..": Not connected") elseif Tube:is_secondary_node(peer_pos) then local node = minetest.get_node(peer_pos) - print(P2S(pos).." to the "..sdir..": Connected with "..node.name.." at "..P2S(peer_pos).."/"..peer_in_dir) + print(P2S(pos).." to the "..sdir..": Connected to "..node.name.." at "..P2S(peer_pos).."/"..peer_in_dir) else - print(P2S(pos).." to the "..sdir..": Connected with "..P2S(peer_pos).."/"..peer_in_dir) + print(P2S(pos).." to the "..sdir..": Connected to "..P2S(peer_pos).."/"..peer_in_dir) for i, pos, node in Tube:get_tube_line(pos, out_dir) do print("walk", P2S(pos), node.name) end @@ -127,6 +127,7 @@ minetest.register_node("tubelib2:tubeS", { }, on_rotate = screwdriver.disallow, -- important! paramtype = "light", + use_texture_alpha = "clip", sunlight_propagates = true, is_ground_content = false, groups = {crumbly = 3, cracky = 3, snappy = 3}, @@ -159,6 +160,7 @@ minetest.register_node("tubelib2:tubeA", { }, on_rotate = screwdriver.disallow, -- important! paramtype = "light", + use_texture_alpha = "clip", sunlight_propagates = true, is_ground_content = false, groups = {crumbly = 3, cracky = 3, snappy = 3, not_in_creative_inventory=1}, @@ -222,8 +224,6 @@ minetest.register_node("tubelib2:source", { paramtype2 = "facedir", -- important! on_rotate = screwdriver.disallow, -- important! - paramtype = "light", - sunlight_propagates = true, is_ground_content = false, groups = {crumbly = 3, cracky = 3, snappy = 3}, sounds = default.node_sound_glass_defaults(), @@ -248,8 +248,6 @@ minetest.register_node("tubelib2:junction", { paramtype2 = "facedir", -- important! on_rotate = screwdriver.disallow, -- important! - paramtype = "light", - sunlight_propagates = true, is_ground_content = false, groups = {crumbly = 3, cracky = 3, snappy = 3}, sounds = default.node_sound_glass_defaults(), @@ -352,8 +350,6 @@ minetest.register_node("tubelib2:teleporter", { paramtype2 = "facedir", -- important! on_rotate = screwdriver.disallow, -- important! - paramtype = "light", - sunlight_propagates = true, is_ground_content = false, groups = {crumbly = 3, cracky = 3, snappy = 3}, sounds = default.node_sound_glass_defaults(), @@ -438,7 +434,7 @@ minetest.register_node("tubelib2:tool", { description = "Tubelib2 Tool", inventory_image = "tubelib2_tool.png", wield_image = "tubelib2_tool.png", - use_texture_alpha = true, + use_texture_alpha = "clip", groups = {cracky=1, book=1}, on_use = remove_tube, on_place = repair_tube, diff --git a/unified_inventory/api.lua b/unified_inventory/api.lua index 8cc5532..1609217 100644 --- a/unified_inventory/api.lua +++ b/unified_inventory/api.lua @@ -43,7 +43,7 @@ minetest.after(0.01, function() end table.sort(ui.items_list) ui.items_list_size = #ui.items_list - print("Unified Inventory. inventory size: "..ui.items_list_size) + print("Unified Inventory. Inventory size: "..ui.items_list_size) for _, name in ipairs(ui.items_list) do local def = minetest.registered_items[name] -- Simple drops @@ -133,19 +133,62 @@ minetest.after(0.01, function() end end end + + -- Step 1: group-indexed lookup table for items + local spec_matcher = {} + for _, name in ipairs(ui.items_list) do + -- we only need to care about groups, exact items are handled separately + for group, value in pairs(minetest.registered_items[name].groups) do + if value and value ~= 0 then + if not spec_matcher[group] then + spec_matcher[group] = {} + end + spec_matcher[group][name] = true + end + end + end + + -- Step 2: Find all matching items for the given spec (groups) + local function get_matching_spec_items(specname) + if specname:sub(1,6) ~= "group:" then + return { [specname] = true } + end + + local accepted = {} + for i, group in ipairs(specname:sub(7):split(",")) do + if i == 1 then + -- First step: Copy all possible item names in this group + for name, _ in pairs(spec_matcher[group] or {}) do + accepted[name] = true + end + else + -- Perform filtering + if spec_matcher[group] then + for name, _ in pairs(accepted) do + accepted[name] = spec_matcher[group][name] + end + else + -- No matching items + return {} + end + end + end + return accepted + end + for _, recipes in pairs(ui.crafts_for.recipe) do + -- List of crafts that return this item string (variable "_") for _, recipe in ipairs(recipes) do local ingredient_items = {} for _, spec in pairs(recipe.items) do - local matches_spec = ui.canonical_item_spec_matcher(spec) - for _, name in ipairs(ui.items_list) do - if matches_spec(name) then - ingredient_items[name] = true - end + -- Get items that fit into this spec (group or item name) + local specname = ItemStack(spec):get_name() + for item_name, _ in pairs(get_matching_spec_items(specname)) do + ingredient_items[item_name] = true end end for name, _ in pairs(ingredient_items) do - if ui.crafts_for.usage[name] == nil then + if not ui.crafts_for.usage[name] then ui.crafts_for.usage[name] = {} end table.insert(ui.crafts_for.usage[name], recipe) diff --git a/unified_inventory/callbacks.lua b/unified_inventory/callbacks.lua index af2c127..fa6d03a 100644 --- a/unified_inventory/callbacks.lua +++ b/unified_inventory/callbacks.lua @@ -14,19 +14,17 @@ end minetest.register_on_joinplayer(function(player) local player_name = player:get_player_name() unified_inventory.players[player_name] = {} - unified_inventory.current_index[player_name] = 1 + unified_inventory.current_index[player_name] = 1 -- Item (~page) index unified_inventory.filtered_items_list[player_name] = - unified_inventory.items_list + unified_inventory.items_list unified_inventory.activefilter[player_name] = "" unified_inventory.active_search_direction[player_name] = "nochange" - unified_inventory.apply_filter(player, "", "nochange") unified_inventory.current_searchbox[player_name] = "" unified_inventory.current_category[player_name] = "all" unified_inventory.current_category_scroll[player_name] = 0 unified_inventory.alternate[player_name] = 1 unified_inventory.current_item[player_name] = nil unified_inventory.current_craft_direction[player_name] = "recipe" - unified_inventory.set_inventory_formspec(player, unified_inventory.default) -- Refill slot local refill = minetest.create_detached_inventory(player_name.."refill", { @@ -48,6 +46,14 @@ minetest.register_on_joinplayer(function(player) refill:set_size("main", 1) end) +minetest.register_on_mods_loaded(function() + minetest.register_on_joinplayer(function(player) + -- After everything is initialized, set up the formspec + ui.apply_filter(player, "", "nochange") + ui.set_inventory_formspec(player, unified_inventory.default) + end) +end) + local function apply_new_filter(player, search_text, new_dir) local player_name = player:get_player_name() @@ -244,11 +250,8 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) unified_inventory.current_page[player_name]) end) -if minetest.delete_detached_inventory then - minetest.register_on_leaveplayer(function(player) - local player_name = player:get_player_name() - minetest.delete_detached_inventory(player_name.."_bags") - minetest.delete_detached_inventory(player_name.."craftrecipe") - minetest.delete_detached_inventory(player_name.."refill") - end) -end +minetest.register_on_leaveplayer(function(player) + local player_name = player:get_player_name() + minetest.remove_detached_inventory(player_name.."_bags") + minetest.remove_detached_inventory(player_name.."refill") +end) diff --git a/unified_inventory/group.lua b/unified_inventory/group.lua index 3864267..2bc8e2f 100644 --- a/unified_inventory/group.lua +++ b/unified_inventory/group.lua @@ -1,30 +1,5 @@ local S = minetest.get_translator("unified_inventory") -function unified_inventory.canonical_item_spec_matcher(spec) - local specname = ItemStack(spec):get_name() - if specname:sub(1, 6) ~= "group:" then - return function (itemname) - return itemname == specname - end - end - - local group_names = specname:sub(7):split(",") - return function (itemname) - local itemdef = minetest.registered_items[itemname] - for _, group_name in ipairs(group_names) do - if (itemdef.groups[group_name] or 0) == 0 then - return false - end - end - return true - end -end - -function unified_inventory.item_matches_spec(item, spec) - local itemname = ItemStack(item):get_name() - return unified_inventory.canonical_item_spec_matcher(spec)(itemname) -end - function unified_inventory.extract_groupnames(groupname) local specname = ItemStack(groupname):get_name() if specname:sub(1, 6) ~= "group:" then @@ -34,22 +9,6 @@ function unified_inventory.extract_groupnames(groupname) return table.concat(group_names, S(" and ")), #group_names end -unified_inventory.registered_group_items = { - mesecon_conductor_craftable = "mesecons:wire_00000000_off", - stone = "default:cobble", - wood = "default:wood", - book = "default:book", - sand = "default:sand", - leaves = "default:leaves", - tree = "default:tree", - vessel = "vessels:glass_bottle", - wool = "wool:white", -} - -function unified_inventory.register_group_item(groupname, itemname) - unified_inventory.registered_group_items[groupname] = itemname -end - -- This is used when displaying craft recipes, where an ingredient is -- specified by group rather than as a specific item. A single-item group diff --git a/unified_inventory/init.lua b/unified_inventory/init.lua index 98ee2e5..1b962da 100644 --- a/unified_inventory/init.lua +++ b/unified_inventory/init.lua @@ -1,5 +1,11 @@ -- Unified Inventory +if not minetest.features.formspec_version_element then + -- At least formspec_version[] is the minimal feature requirement + error("Unified Inventory requires Minetest version 5.4.0 or newer.\n" .. + " Please update Minetest or use an older version of Unified Inventory.") +end + local modpath = minetest.get_modpath(minetest.get_current_modname()) local worldpath = minetest.get_worldpath() @@ -44,9 +50,9 @@ unified_inventory = { trash_enabled = (minetest.settings:get_bool("unified_inventory_trash") ~= false), imgscale = 1.25, list_img_offset = 0.13, - standard_background = "background9[0,0;1,1;ui_formbg_9_sliced.png;true;16]", + standard_background = "bgcolor[#0000]background9[0,0;1,1;ui_formbg_9_sliced.png;true;16]", - version = 3 + version = 4 } local ui = unified_inventory @@ -59,10 +65,16 @@ ui.style_full = { formspec_y = 1, formw = 17.75, formh = 12.25, + -- Item browser size, pos pagecols = 8, pagerows = 9, page_x = 10.75, page_y = 2.30, + -- Item browser controls + page_buttons_x = 11.60, + page_buttons_y = 10.15, + searchwidth = 3.4, + -- Crafting grid positions craft_x = 2.8, craft_y = 1.15, craftresult_x = 7.8, @@ -74,13 +86,15 @@ ui.style_full = { craft_guide_resultstr_x = 0.3, craft_guide_resultstr_y = 0.6, give_btn_x = 0.25, + -- Tab switching buttons main_button_x = 0.4, main_button_y = 11.0, - page_buttons_x = 11.60, - page_buttons_y = 10.15, - searchwidth = 3.4, + main_button_cols = 12, + main_button_rows = 1, + -- Tab title position form_header_x = 0.4, form_header_y = 0.4, + -- Generic sizes btn_spc = 0.85, btn_size = 0.75, std_inv_x = 0.3, @@ -92,10 +106,16 @@ ui.style_lite = { formspec_y = 0.6, formw = 14, formh = 9.75, + -- Item browser size, pos pagecols = 4, pagerows = 5, page_x = 10.5, page_y = 2.15, + -- Item browser controls + page_buttons_x = 10.5, + page_buttons_y = 6.15, + searchwidth = 1.6, + -- Crafting grid positions craft_x = 2.6, craft_y = 0.75, craftresult_x = 5.75, @@ -107,13 +127,15 @@ ui.style_lite = { craft_guide_resultstr_x = 0.15, craft_guide_resultstr_y = 0.35, give_btn_x = 0.15, + -- Tab switching buttons main_button_x = 10.5, main_button_y = 8.15, - page_buttons_x = 10.5, - page_buttons_y = 6.15, - searchwidth = 1.6, + main_button_cols = 4, + main_button_rows = 2, + -- Tab title position form_header_x = 0.2, form_header_y = 0.2, + -- Generic sizes btn_spc = 0.8, btn_size = 0.7, std_inv_x = 0.1, @@ -170,3 +192,4 @@ end dofile(modpath.."/item_names.lua") dofile(modpath.."/waypoints.lua") +dofile(modpath.."/legacy.lua") -- mod compatibility diff --git a/unified_inventory/internal.lua b/unified_inventory/internal.lua index b49906e..938ca19 100644 --- a/unified_inventory/internal.lua +++ b/unified_inventory/internal.lua @@ -18,7 +18,7 @@ function ui.demangle_for_formspec(str) return string.gsub(str, "_([0-9]+)_", function (v) return string.char(v) end) end - +-- Get the player-specific unified_inventory style function ui.get_per_player_formspec(player_name) local draw_lite_mode = ui.lite_mode and not minetest.check_player_privs(player_name, {ui_full=true}) @@ -27,6 +27,7 @@ function ui.get_per_player_formspec(player_name) return style end +-- Creates an item image or regular image button with a tooltip local function formspec_button(ui_peruser, name, image, offset, pos, scale, label) local element = 'image_button' if minetest.registered_items[image] then @@ -43,9 +44,8 @@ local function formspec_button(ui_peruser, name, image, offset, pos, scale, labe string.format("tooltip[%s;%s]", name, F(label or name)) end -local function formspec_add_filters(player, formspec, style) - local button_row = 0 - local button_col = 0 +-- Add registered buttons (tabs) +local function formspec_tab_buttons(player, formspec, style) local n = #formspec + 1 -- Main buttons @@ -58,32 +58,50 @@ local function formspec_add_filters(player, formspec, style) end end + local needs_scrollbar = #filtered_inv_buttons > style.main_button_cols * style.main_button_rows + + formspec[n] = ("scroll_container[%g,%g;%g,%g;tabbtnscroll;vertical]"):format( + style.main_button_x, style.main_button_y, -- position + style.main_button_cols * style.btn_spc, style.main_button_rows -- size + ) + n = n + 1 + for i, def in pairs(filtered_inv_buttons) do - if style.is_lite_mode and i > 4 then - button_row = 1 - button_col = 1 - end + local pos_x = ((i - 1) % style.main_button_cols) * style.btn_spc + local pos_y = math.floor((i - 1) / style.main_button_cols) * style.btn_spc if def.type == "image" then - local pos_x = style.main_button_x + style.btn_spc * (i - 1) - button_col * style.btn_spc * 4 - local pos_y = style.main_button_y + button_row * style.btn_spc if (def.condition == nil or def.condition(player) == true) then - formspec[n] = string.format("image_button[%f,%f;%f,%f;%s;%s;]", + formspec[n] = string.format("image_button[%g,%g;%g,%g;%s;%s;]", pos_x, pos_y, style.btn_size, style.btn_size, F(def.image), F(def.name)) formspec[n+1] = "tooltip["..F(def.name)..";"..(def.tooltip or "").."]" n = n+2 else - formspec[n] = string.format("image[%f,%f;%f,%f;%s^[colorize:#808080:alpha]", + formspec[n] = string.format("image[%g,%g;%g,%g;%s^[colorize:#808080:alpha]", pos_x, pos_y, style.btn_size, style.btn_size, def.image) n = n+1 end end end + formspec[n] = "scroll_container_end[]" + if needs_scrollbar then + formspec[n+1] = ("scrollbaroptions[max=%i;arrows=hide]"):format( + -- This calculation is not 100% accurate but "good enough" + math.ceil((#filtered_inv_buttons - 1) / style.main_button_cols) * style.btn_spc * 5 + ) + formspec[n+2] = ("scrollbar[%g,%g;0.4,%g;vertical;tabbtnscroll;0]"):format( + style.main_button_x + style.main_button_cols * style.btn_spc - 0.1, -- x pos + style.main_button_y, -- y pos + style.main_button_rows * style.btn_spc -- height + ) + formspec[n+3] = "scrollbaroptions[max=1000;arrows=default]" + end end +-- Add category GUI elements (top right) local function formspec_add_categories(player, formspec, ui_peruser) local player_name = player:get_player_name() local n = #formspec + 1 @@ -97,9 +115,9 @@ local function formspec_add_categories(player, formspec, ui_peruser) ui_peruser.form_header_y - (ui_peruser.is_lite_mode and 0 or 0.2) } - formspec[n] = string.format("background9[%f,%f;%f,%f;%s;false;3]", - ui_peruser.page_x-0.1, categories_scroll_pos[2], - (ui_peruser.btn_spc * ui_peruser.pagecols) + 0.13, 1.4 + (ui_peruser.is_lite_mode and 0 or 0.2), + formspec[n] = string.format("background9[%f,%f;%f,%f;%s;false;16]", + ui_peruser.page_x-0.15, categories_scroll_pos[2], + (ui_peruser.btn_spc * ui_peruser.pagecols) + 0.2, 1.4 + (ui_peruser.is_lite_mode and 0 or 0.2), "ui_smallbg_9_sliced.png") n = n + 1 @@ -238,8 +256,14 @@ local function formspec_add_item_browser(player, formspec, ui_peruser) ui_peruser.btn_size, ui_peruser.btn_size, name, button_name ) + local tooltip = item.description + if item.mod_origin then + -- "mod_origin" may not be specified for items that were + -- registered in a callback (during or before ServerEnv init) + tooltip = tooltip .. " [" .. item.mod_origin .. "]" + end formspec[n + 1] = ("tooltip[%s;%s]"):format( - button_name, minetest.formspec_escape(item.description) + button_name, minetest.formspec_escape(tooltip) ) n = n + 2 list_index = list_index + 1 @@ -280,7 +304,7 @@ function ui.get_formspec(player, page) fs[#fs + 1] = fsdata.formspec - formspec_add_filters(player, fs, ui_peruser) + formspec_tab_buttons(player, fs, ui_peruser) if fsdata.draw_inventory ~= false then -- Player inventory @@ -378,3 +402,13 @@ function ui.apply_filter(player, filter, search_dir) ui.active_search_direction[player_name] = search_dir ui.set_inventory_formspec(player, ui.current_page[player_name]) end + +-- Inform players about potential visual issues +minetest.register_on_joinplayer(function(player) + local player_name = player:get_player_name() + local info = minetest.get_player_information(player_name) + if info and (info.formspec_version or 0) < 4 then + minetest.chat_send_player(player_name, S("Unified Inventory: Your game version is too old" + .. " and does not support the GUI requirements. You might experience visual issues.")) + end +end) diff --git a/unified_inventory/legacy.lua b/unified_inventory/legacy.lua new file mode 100644 index 0000000..5b62894 --- /dev/null +++ b/unified_inventory/legacy.lua @@ -0,0 +1,55 @@ +-- Inefficient pattern matching + +local warned_funcs = {} +local function LOG_ONCE(funcname) + if warned_funcs[funcname] then return end + warned_funcs[funcname] = true + minetest.log("error", "Call to undocumented, deprecated API '" .. funcname .. "'." + .. " In a future version of Unified Inventory this will result in a real error.") +end + +function unified_inventory.canonical_item_spec_matcher(spec) + LOG_ONCE("canonical_item_spec_matcher") + local specname = ItemStack(spec):get_name() + if specname:sub(1, 6) ~= "group:" then + return function (itemname) + return itemname == specname + end + end + + local group_names = specname:sub(7):split(",") + return function (itemname) + local itemdef = minetest.registered_items[itemname] + for _, group_name in ipairs(group_names) do + if (itemdef.groups[group_name] or 0) == 0 then + return false + end + end + return true + end +end + +function unified_inventory.item_matches_spec(item, spec) + LOG_ONCE("item_matches_spec") + local itemname = ItemStack(item):get_name() + return unified_inventory.canonical_item_spec_matcher(spec)(itemname) +end + + +unified_inventory.registered_group_items = { + mesecon_conductor_craftable = "mesecons:wire_00000000_off", + stone = "default:cobble", + wood = "default:wood", + book = "default:book", + sand = "default:sand", + leaves = "default:leaves", + tree = "default:tree", + vessel = "vessels:glass_bottle", + wool = "wool:white", +} + +function unified_inventory.register_group_item(groupname, itemname) + LOG_ONCE("register_group_item") + unified_inventory.registered_group_items[groupname] = itemname +end + diff --git a/unified_inventory/screenshot.png b/unified_inventory/screenshot.png index 972cbb4..bf9e6be 100644 Binary files a/unified_inventory/screenshot.png and b/unified_inventory/screenshot.png differ diff --git a/unified_inventory/textures/ui_formbg_9_sliced.png b/unified_inventory/textures/ui_formbg_9_sliced.png index 0b8463c..817ced5 100644 Binary files a/unified_inventory/textures/ui_formbg_9_sliced.png and b/unified_inventory/textures/ui_formbg_9_sliced.png differ diff --git a/unified_inventory/textures/ui_smallbg_9_sliced.png b/unified_inventory/textures/ui_smallbg_9_sliced.png index 865e0c9..916b146 100644 Binary files a/unified_inventory/textures/ui_smallbg_9_sliced.png and b/unified_inventory/textures/ui_smallbg_9_sliced.png differ