diff --git a/lcdlib/init.lua b/lcdlib/init.lua index 058ce7e..cbbc200 100644 --- a/lcdlib/init.lua +++ b/lcdlib/init.lua @@ -24,7 +24,7 @@ lcdlib = {} lcdlib.registered_fonts = {} -- Version for compatibility checks -lcdlib.version = 1.0 +lcdlib.version = 1.01 -- Local functions ------------------ @@ -180,7 +180,7 @@ end -- @return Texture string function lcdlib.make_multiline_texture(font_name, text, width, height, - maxlines, valign, color) + maxlines, valign, color, y_offs) local texture = "" local lines = {} local textheight = 0 @@ -199,7 +199,7 @@ function lcdlib.make_multiline_texture(font_name, text, width, height, if #lines then if valign == "top" then - y = 0 + y = y_offs or 0 elseif valign == "bottom" then y = height - textheight else diff --git a/minecart/README.md b/minecart/README.md index cb4fd96..f2f8747 100644 --- a/minecart/README.md +++ b/minecart/README.md @@ -149,6 +149,7 @@ History 2020-07-24 V1.08 Adapted to new techage ICTA style 2020-08-14 V1.09 Hopper support for digtron, protector:chest and default:furnace added 2020-11-12 V1.10 Make carts more robust against server lag -2021-04-10 V2.00 Complete revision to make carts robust against server load/lag, - Speed limit signs and cart terminal added -2021-09-02 V2.01 Chat command /stopcart added \ No newline at end of file +2021-04-10 V2.00 Complete revision to make carts robust against server load/lag, + Speed limit signs and cart terminal added +2021-09-02 V2.01 Chat command /stopcart added +2021-10-18 V2.02 Cart reproduction bug fixed diff --git a/minecart/baselib.lua b/minecart/baselib.lua index 505f242..06b96b6 100644 --- a/minecart/baselib.lua +++ b/minecart/baselib.lua @@ -257,9 +257,6 @@ function minecart.add_nodecart(pos, node_name, param2, cargo, owner, userID) pos2 = minetest.find_node_near(pos, 1, minecart.lRails) if not pos2 or not minecart.is_rail(pos2) then pos2 = minetest.find_node_near(pos, 2, minecart.lRails) - if not pos2 or not minecart.is_rail(pos2) then - pos2 = minetest.find_node_near(pos, 2, {"air"}) - end end else pos2 = vector.new(pos) @@ -282,8 +279,6 @@ function minecart.add_nodecart(pos, node_name, param2, cargo, owner, userID) ndef.after_place_node(pos2) end return pos2 - else - minetest.add_item(pos, ItemStack({name = node_name})) end end end @@ -363,9 +358,13 @@ function minecart.entity_to_node(pos, entity) local dir = minetest.yaw_to_dir(rot.y) local facedir = minetest.dir_to_facedir(dir) minecart.stop_recording(entity, pos) - entity.object:remove() local pos2 = minecart.add_nodecart(pos, entity.node_name, facedir, entity.cargo, entity.owner, entity.userID) - minecart.stop_monitoring(entity.owner, entity.userID, pos2) + if pos2 then + minecart.stop_monitoring(entity.owner, entity.userID, pos2) + entity.object:remove() + else + minecart.start_entitycart(entity, pos, facedir) + end end function minecart.add_node_to_player_inventory(pos, player, node_name) @@ -388,9 +387,10 @@ function minecart.remove_entity(self, pos, player) minetest.sound_stop(self.sound_handle) self.sound_handle = nil end - minecart.add_node_to_player_inventory(pos, player, self.node_name or "minecart:cart") + if player then + minecart.add_node_to_player_inventory(pos, player, self.node_name or "minecart:cart") + end minecart.stop_monitoring(self.owner, self.userID, pos) minecart.stop_recording(self, pos) - minecart.monitoring_remove_cart(self.owner, self.userID) self.object:remove() end diff --git a/minecart/buffer.lua b/minecart/buffer.lua index eb83091..d871046 100644 --- a/minecart/buffer.lua +++ b/minecart/buffer.lua @@ -159,13 +159,16 @@ minetest.register_craft({ }) minetest.register_lbm({ - label = "Delete waiting times", - name = "minecart:del_time", + label = "Delete metadata", + name = "minecart:metadata", nodenames = {"minecart:buffer"}, - run_at_every_load = false, + run_at_every_load = true, action = function(pos, node) - -- delete old data - minecart.get_route(pos) - M(pos):set_string("formspec", formspec(pos)) + -- delete old metadata around the buffer (bugfix) + local pos1 = {x = pos.x - 2, y = pos.y - 2, z = pos.z - 2} + local pos2 = {x = pos.x + 2, y = pos.y + 2, z = pos.z + 2} + for _, pos in ipairs(minetest.find_nodes_with_meta(pos1, pos2)) do + minecart.del_metadata(pos) + end end, }) diff --git a/minecart/entitylib.lua b/minecart/entitylib.lua index 5c48443..94c99c1 100644 --- a/minecart/entitylib.lua +++ b/minecart/entitylib.lua @@ -186,7 +186,7 @@ local function play_sound(self) if self.object then self.sound_handle = minetest.sound_play( "carts_cart_moving", { - object = self.object, + pos = self.object:get_pos(), gain = (self.curr_speed or 0) / MAX_SPEED, }) end diff --git a/minecart/init.lua b/minecart/init.lua index 3785e99..77b140d 100644 --- a/minecart/init.lua +++ b/minecart/init.lua @@ -13,7 +13,7 @@ minecart = {} -- Version for compatibility checks, see readme.md/history -minecart.version = 2.01 +minecart.version = 2.02 minecart.hopper_enabled = minetest.settings:get_bool("minecart_hopper_enabled") ~= false minecart.teleport_enabled = minetest.settings:get_bool("minecart_teleport_enabled") == true @@ -35,7 +35,7 @@ dofile(MP .. "/api.lua") dofile(MP .. "/minecart.lua") dofile(MP .. "/buffer.lua") dofile(MP .. "/protection.lua") ---dofile(MP .. "/tool.lua") # for debugging only +--dofile(MP .. "/tool.lua") -- for debugging only dofile(MP .. "/signs.lua") dofile(MP .. "/terminal.lua") dofile(MP .. "/pusher.lua") diff --git a/minecart/monitoring.lua b/minecart/monitoring.lua index c25f231..2956f88 100644 --- a/minecart/monitoring.lua +++ b/minecart/monitoring.lua @@ -68,9 +68,6 @@ local function get_checkpoint(cart) cp = cart.checkpoints[cart.idx] end local pos = H2P(cp[1]) --- if M(pos):contains("waypoints") then --- print("get_checkpoint", P2S(H2P(cp[1])), P2S(H2P(cp[2]))) --- end return cp, cart.idx == #cart.checkpoints end @@ -81,13 +78,15 @@ local function get_cart_state_and_loc(name, userID, query_pos) if tCartsOnRail[name] and tCartsOnRail[name][userID] then local cart = tCartsOnRail[name][userID] local pos = cart.last_pos or cart.pos - local loc = minecart.get_buffer_name(cart.pos) or - math.floor(vector.distance(pos, query_pos)) - if cart.objID == 0 then - return "stopped", minecart.get_buffer_name(cart.pos) or - math.floor(vector.distance(pos, query_pos)), cart.node_name - else - return "running", math.floor(vector.distance(pos, query_pos)), cart.node_name + if pos then + local loc = minecart.get_buffer_name(cart.pos) or + math.floor(vector.distance(pos, query_pos)) + if cart.objID == 0 then + return "stopped", minecart.get_buffer_name(cart.pos) or + math.floor(vector.distance(pos, query_pos)), cart.node_name + else + return "running", math.floor(vector.distance(pos, query_pos)), cart.node_name + end end end return "unknown", 0, "unknown" @@ -103,21 +102,41 @@ local function get_cart_info(owner, userID, query_pos) end end +local function logging(cart, err) + local s = string.format("[Minecart] Cart %s/%u %s!", cart.owner, cart.userID, err) + minetest.log("warning", s) +end + +-- check cart data +local function valid_cart(cart) + if cart.objID == nil or cart.objID == 0 then + return false + end + if tCartsOnRail[cart.owner] and tCartsOnRail[cart.owner][cart.userID] then + return true + end + logging(cart, "with invalid data") + local entity = minetest.luaentities[cart.objID] + if entity then + entity.object:remove() + end + return false +end + local function monitoring(cycle) local cart = pop(cycle) + -- All running cars while cart do - -- All running cars - if cart.objID and cart.objID ~= 0 then + if valid_cart(cart) then cart.idx = cart.idx + 1 local entity = minetest.luaentities[cart.objID] if entity then -- cart entity running local pos = entity.object:get_pos() if pos then cart.last_pos = vector.round(pos) - --print("entity card " .. cart.userID .. " at " .. P2S(cart.last_pos)) else - minetest.log("warning", "[Minecart] entity card without pos!") + logging(cart, "without pos") end push(cycle, cart) elseif cart.checkpoints then @@ -130,16 +149,15 @@ local function monitoring(cycle) end push(cycle, cart) else - minetest.log("warning", "[Minecart] zombie got lost") + logging(cart, "as zombie got lost") end else local pos = cart.last_pos or cart.pos pos = minecart.add_nodecart(pos, cart.node_name, 0, cart.cargo, cart.owner, cart.userID) - cart.objID = 0 - cart.pos = pos - --print("cart to node", cycle, cart.userID, P2S(pos)) + minecart.stop_monitoring(cart.owner, cart.userID, pos) + logging(cart, "stopped at " .. (P2S(pos) or "unknown")) end - elseif cart and not cart.objID and tCartsOnRail[cart.owner] then + elseif not cart.objID and tCartsOnRail[cart.owner] then -- Delete carts marked as "to be deleted" tCartsOnRail[cart.owner][cart.userID] = nil end @@ -184,6 +202,7 @@ function minecart.stop_monitoring(owner, userID, pos) --print("stop_monitoring", owner, userID) if tCartsOnRail[owner] and tCartsOnRail[owner][userID] then tCartsOnRail[owner][userID].pos = pos + -- Mark as "stopped" tCartsOnRail[owner][userID].objID = 0 minecart.store_carts() end @@ -192,14 +211,20 @@ end function minecart.monitoring_remove_cart(owner, userID) --print("monitoring_remove_cart", owner, userID) if tCartsOnRail[owner] and tCartsOnRail[owner][userID] then - tCartsOnRail[owner][userID].objID = nil - tCartsOnRail[owner][userID] = nil + -- Cart stopped? + if tCartsOnRail[owner][userID].objID == 0 then + -- Can directly be deleted + tCartsOnRail[owner][userID] = nil + else -- Cart running + -- Mark as "to be deleted" by monitoring + tCartsOnRail[owner][userID].objID = nil + end minecart.store_carts() end end function minecart.monitoring_valid_cart(owner, userID, pos, node_name) - if tCartsOnRail[owner] and tCartsOnRail[owner][userID] then + if tCartsOnRail[owner] and tCartsOnRail[owner][userID] and tCartsOnRail[owner][userID].pos then return vector.equals(tCartsOnRail[owner][userID].pos, pos) and tCartsOnRail[owner][userID].node_name == node_name end @@ -245,29 +270,38 @@ minetest.register_chatcommand("mycart", { minetest.register_chatcommand("stopcart", { params = "", - description = S("Stop amd return a missing/running cart."), + description = S("Stop and return/drop a missing/running cart."), func = function(owner, param) local userID = tonumber(param) local player_pos = minetest.get_player_by_name(owner):get_pos() if userID then local data = minecart.get_cart_monitoring_data(owner, userID) - if data then - if data.objID and data.objID ~= 0 then - local entity = minetest.luaentities[data.objID] - if entity then -- cart entity running - minecart.entity_to_node(player_pos, entity) - minecart.monitoring_remove_cart(owner, userID) + if data and data.objID then + local entity = minetest.luaentities[data.objID] + --print("stopcart", userID, data.pos, data.objID, entity) + if data.objID == 0 then + -- Cart as node + if data.pos then + local meta = M(data.pos) + if owner == meta:get_string("owner") and userID == meta:get_int("userID") then + minecart.remove_nodecart(data.pos) + end end + elseif entity then + -- Cart as entity + minecart.remove_entity(entity, data.pos) else - local pos = data.last_pos or data.pos - local cargo, _, _ = minecart.remove_nodecart(pos) - minecart.add_nodecart(player_pos, data.node_name, 0, cargo, owner, userID) - minecart.monitoring_remove_cart(owner, userID) + -- Cart as zombie/invalid/corrupted + -- nothing to do end - return true, S("Cart") .. " " .. userID .. " " .. S("stopped") + minetest.add_item(player_pos, ItemStack({name = data.node_name})) + minecart.monitoring_remove_cart(owner, userID) + return true, S("Cart") .. " " .. userID .. " " .. S("dropped") else return false, S("Cart") .. " " .. userID .. " " .. S("is not existing!") end + else + return false end end }) diff --git a/minecart/rails.lua b/minecart/rails.lua index 0448bd7..0162531 100644 --- a/minecart/rails.lua +++ b/minecart/rails.lua @@ -585,6 +585,9 @@ end -- minecart.get_next_buffer(pos, facedir) minecart.get_next_buffer = get_next_buffer +-- minecart.del_metadata(pos) +minecart.del_metadata = del_metadata + --minetest.register_lbm({ -- label = "Delete waypoints", -- name = "minecart:del_meta", diff --git a/minecart/storage.lua b/minecart/storage.lua index 2db6028..54f7a48 100644 --- a/minecart/storage.lua +++ b/minecart/storage.lua @@ -50,30 +50,15 @@ minetest.register_on_mods_loaded(function() else local t = minetest.deserialize(storage:get_string("CartsOnRail")) or {} for owner, carts in pairs(t) do - minecart.CartsOnRail[owner] = {} + minecart.CartsOnRail[owner] = minecart.CartsOnRail[owner] or {} for userID, cart in pairs(carts) do - print("reload cart", owner, userID, cart.objID) - minecart.CartsOnRail[owner][userID] = cart - -- mark all entity carts as zombified - if cart.objID and cart.objID ~= 0 then - cart.objID = -1 - minecart.push(1, cart) - end - end - end - end -end) - -minetest.after(10, function() - for owner, carts in pairs(minecart.CartsOnRail) do - for userID, cart in pairs(carts) do - -- Remove node carts that are not available anymore - if cart.pos and (cart.objID == 0 or not cart.objID) then - local node = minecart.get_node_lvm(cart.pos) - if not minecart.tNodeNames[node.name] then - -- Mark as "to be deleted" - print("Node cart deleted", owner, userID) - minecart.CartsOnRail[owner][userID] = nil + if cart.objID then + minecart.CartsOnRail[owner][userID] = cart + -- mark all entity carts as zombified + if cart.objID ~= 0 then + cart.objID = -1 + minecart.push(1, cart) + end end end end diff --git a/minecart/tool.lua b/minecart/tool.lua index bc8d297..593d3de 100644 --- a/minecart/tool.lua +++ b/minecart/tool.lua @@ -78,7 +78,8 @@ local function click_left(itemstack, placer, pointed_thing) if pointed_thing.type == "node" then local pos = pointed_thing.under if minecart.is_rail(pos) then - test_get_buffer(pos, placer) + --test_get_buffer(pos, placer) + minecart.delete_waypoint(pos) end end end diff --git a/signs_bot/README.md b/signs_bot/README.md index 7f04f87..05f711e 100644 --- a/signs_bot/README.md +++ b/signs_bot/README.md @@ -183,4 +183,5 @@ optional: farming redo, node_io, doc, techage, minecart, xdecor, compost - 2021-04-24 v1.07 * Adapted to minecart v2.0 - 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 diff --git a/signs_bot/changer.lua b/signs_bot/changer.lua index 543d13c..979f747 100644 --- a/signs_bot/changer.lua +++ b/signs_bot/changer.lua @@ -8,7 +8,7 @@ GPL v3 See LICENSE.txt for more information - Signgs Changer/Control Unit for Bot Control + Signs Changer/Control Unit for Bot Control ]]-- diff --git a/signs_bot/cmd_flowers.lua b/signs_bot/cmd_flowers.lua index d2e30d8..cc575d9 100644 --- a/signs_bot/cmd_flowers.lua +++ b/signs_bot/cmd_flowers.lua @@ -61,12 +61,29 @@ local function harvesting(base_pos, mem) if pos and lib.not_protected(base_pos, pos) then local node = minetest.get_node_or_nil(pos) - local drop = Flowers[node.name] or is_tree(node) - if drop then - minetest.remove_node(pos) - local leftover = bot_inv_put_item(base_pos, 0, ItemStack(drop)) - if leftover and leftover:get_count() > 0 then - signs_bot.lib.drop_items(mem.robot_pos, leftover) + if node.name ~= "default:papyrus" then + local drop = Flowers[node.name] or is_tree(node) + if drop then + minetest.remove_node(pos) + local leftover = bot_inv_put_item(base_pos, 0, ItemStack(drop)) + if leftover and leftover:get_count() > 0 then + signs_bot.lib.drop_items(mem.robot_pos, leftover) + end + end + else + -- papyrus is a special plant that is collected upwards when cut + local count = 0 + while node.name == "default:papyrus" and lib.not_protected(base_pos, pos) do + minetest.remove_node(pos) + pos = { x = pos.x, y = pos.y + 1, z = pos.z } + count = count + 1 + node = minetest.get_node(pos) + end + if count > 0 then + local leftover = bot_inv_put_item(base_pos, 0, ItemStack("default:papyrus " .. count)) + if leftover and leftover:get_count() > 0 then + signs_bot.lib.drop_items(mem.robot_pos, leftover) + end end end end @@ -76,7 +93,7 @@ signs_bot.register_botcommand("cutting", { mod = "farming", params = "", num_param = 0, - description = S("Cutting flowers, leaves and tree blocks\nin front of the robot\non a 3x3 field."), + description = S("Cutting flowers, papyrus,\nleaves and tree blocks\nin front of the robot\non a 3x3 field."), cmnd = function(base_pos, mem) if not mem.steps then mem.pos_tbl = signs_bot.lib.gen_position_table(mem.robot_pos, mem.robot_param2, 3, 3, 0) diff --git a/ta4_jetpack/init.lua b/ta4_jetpack/init.lua index cc29bd0..53eb16b 100644 --- a/ta4_jetpack/init.lua +++ b/ta4_jetpack/init.lua @@ -551,3 +551,5 @@ techage.add_manual_items({ 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 diff --git a/techage/README.md b/techage/README.md index 74d0888..024dba7 100644 --- a/techage/README.md +++ b/techage/README.md @@ -81,6 +81,13 @@ Available worlds will be converted to 'lsqlite3', but there is no way back, so: ### History +**2021-10-24 V1.03** +- Add TA4 Sequencer for time controlled command sequences +- Add TA4 Move Controller for moving blocks +- Add techage command counting function to be able to limit the amount of commands/min. +- Pull request #67: Add switch mode for 4x Button (by realmicu) +- Pull request #69: Add option to keep assignment for TA4 Tank (by Thomas-S) + **2021-09-18 V1.02** - TA4 Chest: Fix items disappearing (PR #64 by Thomas--S) - Add support for colored cables (PR #63 by Thomas--S) diff --git a/techage/basic_machines/consumer.lua b/techage/basic_machines/consumer.lua index e37daaa..d132ce5 100644 --- a/techage/basic_machines/consumer.lua +++ b/techage/basic_machines/consumer.lua @@ -152,6 +152,7 @@ function techage.register_consumer(base_name, inv_name, tiles, tNode, validState formspec_func = tNode.formspec, on_state_change = tNode.on_state_change, can_start = tNode.can_start, + quick_start = tNode.quick_start, has_power = tNode.has_power or power_used and has_power or nil, start_node = power_used and start_node or nil, stop_node = power_used and stop_node or nil, diff --git a/techage/basic_machines/ta4_chest.lua b/techage/basic_machines/ta4_chest.lua index 725035d..62b0551 100644 --- a/techage/basic_machines/ta4_chest.lua +++ b/techage/basic_machines/ta4_chest.lua @@ -350,11 +350,27 @@ local function search_chest_in_front(pos, node) end if node.name == "techage:ta4_chest" then minetest.after(1, count_number_of_chests, pos1) + local nvm = techage.get_nvm(pos) + nvm.front_chest_pos = pos1 return true end return false end +local function get_front_chest_pos(pos) + local nvm = techage.get_nvm(pos) + if nvm.front_chest_pos then + return nvm.front_chest_pos + end + + local node = techage.get_node_lvm(pos) + if search_chest_in_front(pos, node) then + return nvm.front_chest_pos + end + + return pos +end + local function convert_to_chest_again(pos, node, player) local dir = techage.side_to_outdir("B", node.param2) local pos1 = tubelib2.get_pos(pos, dir) @@ -594,6 +610,33 @@ techage.register_node({"techage:ta4_chest"}, { end, }) +techage.register_node({"techage:ta4_chest_dummy"}, { + on_pull_item = function(pos, in_dir, num, item_name) + local fc_pos = get_front_chest_pos(pos) + local res = tube_take_from_chest(fc_pos, item_name, num) + if techage.is_activeformspec(fc_pos) then + M(fc_pos):set_string("formspec", formspec(fc_pos)) + end + return res + end, + on_push_item = function(pos, in_dir, stack) + local fc_pos = get_front_chest_pos(pos) + local res = tube_add_to_chest(fc_pos, stack) + if techage.is_activeformspec(fc_pos) then + M(fc_pos):set_string("formspec", formspec(fc_pos)) + end + return res + end, + on_unpull_item = function(pos, in_dir, stack) + local fc_pos = get_front_chest_pos(pos) + local res = tube_add_to_chest(fc_pos, stack) + if techage.is_activeformspec(fc_pos) then + M(fc_pos):set_string("formspec", formspec(fc_pos)) + end + return res + end +}) + minetest.register_craft({ type = "shapeless", output = "techage:ta4_chest", diff --git a/techage/basic_machines/ta4_injector.lua b/techage/basic_machines/ta4_injector.lua index 919926d..15e6a02 100644 --- a/techage/basic_machines/ta4_injector.lua +++ b/techage/basic_machines/ta4_injector.lua @@ -175,7 +175,7 @@ local function pushing(pos, crd, meta, nvm) end end -local function keep_running(pos, elapsed) +local function node_timer(pos, elapsed) local nvm = techage.get_nvm(pos) local crd = CRD(pos) pushing(pos, crd, M(pos), nvm) @@ -253,6 +253,7 @@ local _, node_name_ta3, node_name_ta4 = standby_ticks = STANDBY_TICKS, formspec = formspec, tubing = tubing, + quick_start = node_timer, after_place_node = function(pos, placer) local meta = M(pos) local node = minetest.get_node(pos) @@ -268,7 +269,7 @@ local _, node_name_ta3, node_name_ta4 = allow_metadata_inventory_take = allow_metadata_inventory_take, allow_metadata_inventory_move = function() return 0 end, on_receive_fields = on_receive_fields, - node_timer = keep_running, + node_timer = node_timer, on_rotate = screwdriver.disallow, groups = {choppy=2, cracky=2, crumbly=2}, diff --git a/techage/basis/command.lua b/techage/basis/command.lua index 301cf3b..f09fe94 100644 --- a/techage/basis/command.lua +++ b/techage/basis/command.lua @@ -27,6 +27,7 @@ local string_split = string.split local NodeDef = techage.NodeDef local Tube = techage.Tube local is_cart_available = minecart.is_nodecart_available +local techage_counting_hit = techage.counting_hit ------------------------------------------------------------------- -- Database @@ -253,6 +254,14 @@ function techage.remove_node(pos, oldnode, oldmetadata) end end +-- Repairs the node number after it was erased by `backend.delete_invalid_entries` +function techage.repair_number(pos) + local number = techage.get_node_number(pos) + if number then + backend.set_nodepos(number, pos) + end +end + ------------------------------------------------------------------- -- Node register function @@ -324,6 +333,7 @@ function techage.send_multi(src, numbers, topic, payload) if ninfo and ninfo.name and ninfo.pos then local ndef = NodeDef[ninfo.name] if ndef and ndef.on_recv_message then + techage_counting_hit() ndef.on_recv_message(ninfo.pos, src, topic, payload) end end @@ -336,6 +346,7 @@ function techage.send_single(src, number, topic, payload) if ninfo and ninfo.name and ninfo.pos then local ndef = NodeDef[ninfo.name] if ndef and ndef.on_recv_message then + techage_counting_hit() return ndef.on_recv_message(ninfo.pos, src, topic, payload) end end diff --git a/techage/basis/counting.lua b/techage/basis/counting.lua new file mode 100644 index 0000000..265b048 --- /dev/null +++ b/techage/basis/counting.lua @@ -0,0 +1,68 @@ +--[[ + + TechAge + ======= + + Copyright (C) 2019-2021 Joachim Stolberg + + AGPL v3 + See LICENSE.txt for more information + + Count techage commands player related + +]]-- + +local PlayerName +local PlayerPoints = {} +local LastPlayerPoints = {} +local S = techage.S + +local MAX_POINTS = tonumber(minetest.settings:get("techage_command_limit")) or 1200 + +function techage.counting_start(player_name) + PlayerName = player_name + PlayerPoints[PlayerName] = PlayerPoints[PlayerName] or 0 +end + +function techage.counting_stop() + PlayerName = nil +end + +function techage.counting_hit() + if PlayerName then + PlayerPoints[PlayerName] = PlayerPoints[PlayerName] + 1 + end +end + +local function output() + for name, val in pairs(PlayerPoints) do + if val > MAX_POINTS then + local obj = minetest.get_player_by_name(name) + if obj then + minetest.chat_send_player(name, + S("[techage] The limit for 'number of commands per minute' has been exceeded.") .. + " " .. string.format(MAX_POINTS .. " " .. S("is allowed. Current value is") .. " " .. val)); + minetest.log("action", "[techage] " .. name .. + " exceeds the limit for commands per minute. value = " .. val) + local factor = 100 / (obj:get_armor_groups().fleshy or 100) + obj:punch(obj, 1.0, {full_punch_interval=1.0, damage_groups = {fleshy=factor * 5}}) + end + end + end + LastPlayerPoints = table.copy(PlayerPoints) + PlayerPoints = {} + minetest.after(60, output) +end + +minetest.after(60, output) + + +minetest.register_chatcommand("ta_limit", { + description = "Get your current techage command limit value", + func = function(name) + local num = LastPlayerPoints[name] or 0 + return true, S("Your current value is") .. " " .. num .. " " .. S("per minute") .. ". " .. + MAX_POINTS .. " " .. S("is allowed") + end +}) + diff --git a/techage/basis/laser_lib.lua b/techage/basis/laser_lib.lua index 9df03cb..802b3c3 100644 --- a/techage/basis/laser_lib.lua +++ b/techage/basis/laser_lib.lua @@ -102,7 +102,7 @@ for _, size in ipairs(SIZES) do physical = false, collide_with_objects = false, pointable = false, - static_save = true, + static_save = false, visual_size = {x = size, y = 0.05, z = 0.05}, glow = 14, shaded = true, diff --git a/techage/basis/liquid_lib.lua b/techage/basis/liquid_lib.lua index 5b51440..bf1c395 100644 --- a/techage/basis/liquid_lib.lua +++ b/techage/basis/liquid_lib.lua @@ -38,21 +38,18 @@ function techage.liquid.formspec(pos, nvm) end local name = minetest.get_node(pos).name if name == "techage:ta4_tank" then - local public = dump((M(pos):get_int("public") or 0) == 1) - return "size[5,3]".. - default.gui_bg.. - default.gui_bg_img.. - default.gui_slots.. + local meta = M(pos) + local public = dump((meta:get_int("public") or 0) == 1) + local keep_assignment = dump((meta:get_int("keep_assignment") or 0) == 1) + return "size[5,3.5]".. "box[0,-0.1;4.8,0.5;#c6e8ff]".. "label[1.5,-0.1;"..minetest.colorize("#000000", title).."]".. help(4.4, -0.1).. techage.item_image(2, 1, itemname).. - "checkbox[0.1,2.5;public;"..S("Allow public access to the tank")..";"..public.."]" + "checkbox[0.1,2.5;public;"..S("Allow public access to the tank")..";"..public.."]".. + "checkbox[0.1,3;keep_assignment;"..S("keep assignment")..";"..keep_assignment.."]" else return "size[4,2]".. - default.gui_bg.. - default.gui_bg_img.. - default.gui_slots.. "box[0,-0.1;3.8,0.5;#c6e8ff]".. "label[1,-0.1;"..minetest.colorize("#000000", title).."]".. help(3.4, -0.1).. diff --git a/techage/basis/node_states.lua b/techage/basis/node_states.lua index 0071893..9e76c89 100644 --- a/techage/basis/node_states.lua +++ b/techage/basis/node_states.lua @@ -183,6 +183,7 @@ function NodeStates:new(attr) stop_node = attr.stop_node, formspec_func = attr.formspec_func, on_state_change = attr.on_state_change, + quick_start = attr.quick_start, } setmetatable(o, self) self.__index = self @@ -272,6 +273,10 @@ function NodeStates:start(pos, nvm) self.on_state_change(pos, state, RUNNING) end start_timer_delayed(pos, self.cycle_time) + + if self.quick_start and state == STOPPED then + self.quick_start(pos, 0) + end return true end return false diff --git a/techage/basis/recipe_lib.lua b/techage/basis/recipe_lib.lua index 309a3b4..95ecddc 100644 --- a/techage/basis/recipe_lib.lua +++ b/techage/basis/recipe_lib.lua @@ -136,4 +136,4 @@ end function techage.recipes.get_recipe(name) return NormalizedRecipes[name] end - \ No newline at end of file + diff --git a/techage/carts/tank_cart.lua b/techage/carts/tank_cart.lua index c7391c3..d3654ac 100644 --- a/techage/carts/tank_cart.lua +++ b/techage/carts/tank_cart.lua @@ -118,6 +118,9 @@ minetest.register_node("techage:tank_cart", { local nvm = techage.get_nvm(pos) nvm.liquid = nvm.liquid or {} M(pos):set_string("formspec", techage.liquid.formspec(pos, nvm)) + -- Delete the network between pump and cart + Pipe:after_dig_node(pos) + Pipe:after_place_node(pos) end, set_cargo = function(pos, data) diff --git a/techage/doc/items.lua b/techage/doc/items.lua index f3e7161..bf4dc37 100644 --- a/techage/doc/items.lua +++ b/techage/doc/items.lua @@ -191,6 +191,9 @@ techage.Items = { ta4_electricmeter = "techage:ta4_electricmeter", ta4_transformer = "techage:ta4_transformer", power_reduction = "techage_power_reduction.png", + ta4_button_4x = "techage:ta4_button_4x", + ta4_sequencer = "techage:ta4_sequencer", + ta4_movecontroller = "techage:ta4_movecontroller", --ta4_ "", } diff --git a/techage/doc/manual_DE.lua b/techage/doc/manual_DE.lua index 83b2414..4fc8946 100644 --- a/techage/doc/manual_DE.lua +++ b/techage/doc/manual_DE.lua @@ -183,9 +183,12 @@ techage.manual_DE.aTitel = { "3,TA4 Lua Controller Terminal", "2,TA4 Logik-/Schalt-Module", "3,TA4 Taster/Schalter / Button/Switch", + "3,TA4 4x Taster / 4x Button", "3,TA4 Spieler Detektor / Player Detector", "3,TA4 Zustandssammler / State Collector", "3,TA4 Detektor / Detector", + "3,TA4 Move Controller", + "3,TA4 Sequenzer", "2,TA4 Lampen", "3,TA4 LED Pflanzenlampe / TA4 LED Grow Light", "3,TA4 LED Straßenlampe / TA4 LED Street Lamp", @@ -1126,6 +1129,7 @@ techage.manual_DE.aText = { "Der Detektor ist eine spezieller Röhrenblock\\, der erkennt\\, wenn Items über die Röhre weitergegeben werden. Es muss dazu auf beiden Seiten mit der Röhre verbunden sein. Werden Items mit einem Schieber in den Detektor geschoben\\, gibt er diese automatisch weiter.\n".. "Er sendet ein 'on'\\, wenn ein Item erkannt wird\\, gefolgt von einem 'off' eine Sekunde später.\n".. "Danach werden weitere Kommando für 8 Sekunden blockiert.\n".. + "Die Wartezeit\\, sowie die Items\\, die ein Kommando auslösen sollen\\, können über das Gabelschlüssel-Menü konfiguriert werden.\n".. "\n".. "\n".. "\n", @@ -1558,6 +1562,10 @@ techage.manual_DE.aText = { "\n".. "\n".. "\n", + "Dieser Block hat vier Taster\\, die über das Schraubenschlüssel-Menü individuell konfiguriert werden können. Für jeden Taster kann die Beschriftung und die Zielblockadresse konfiguriert werden. Zusätzlich kann für jeden Taster das Kommando konfiguriert werden\\, welches gesendet werden soll.\n".. + "\n".. + "\n".. + "\n", "Beim TA4 Spieler Detektor hat sich nur das Aussehen geändert. Die Funktionalität ist gleich wie beim TA3 Spieler Detektor.\n".. "\n".. "\n".. @@ -1571,6 +1579,50 @@ techage.manual_DE.aText = { "\n".. "\n".. "\n", + "Der TA4 Move Controller ist ähnlich zum \"Door Controller 2\"\\, aber die ausgewählten Blöcke werden nicht entfernt\\, sondern können bewegt werden.\n".. + "Da die bewegten Blöcke Spieler und Mobs mitnehmen können\\, die auf dem Block stehen\\, können damit Fahrstühle und ähnliche Transportsysteme gebaut werden.\n".. + "\n".. + "Anleitung:\n".. + "\n".. + " - Controller setzen und die Blöcke\\, die bewegt werden sollen\\, über das Menü an-trainieren (Es können bis zu 16 Blöcke an-trainiert werden)\n".. + " - die \"Flugstrecke\" muss über eine x\\,y\\,z Angabe (relativ) eingegeben werden (die maximale Distanz beträgt 100 m)\n".. + " - mit den Menü-Tasten \"Bewege A-B\" sowie \"Bewege B-A\" kann die Bewegung getestet werden\n".. + " - man kann auch durch Wände oder andere Blöcke fliegen\n".. + " - auch die Zielposition für die Blöcke kann belegt sein. Die Blöcke werden in diesem Falle \"unsichtbar\" gespeichert. Dies ist für Schiebetüren und ähnliches gedacht\n".. + " - Über das Gabelschlüssel-Menü kann im Controller auch ein \"handover\" programmiert werden. Durch Eingabe einer Blocknummer werden die Blöcke dann an den nächsten Move Controller übergeben. So lassen sich auch zusammenhängende Bewegungen über mehrere Move Controller realisieren.\n".. + "\n".. + "Der Move Controller unterstützt folgende techage Kommandos:\n".. + "\n".. + " - 'a2b' Bewege Block von A nach B\n".. + " - 'b2a' Bewege Block von B nach A\n".. + " - 'move' Bewege Block auf die andere Seite\n".. + "\n".. + "\n".. + "\n", + "über den TA4 Sequenzer können ganze Abläufe programmiert werden. Hier ein Beispiel:\n".. + "\n".. + " -- this is a comment\n".. + " \\[1\\] send 1234 a2b\n".. + " \\[30\\] send 1234 b2a\n".. + " \\[60\\] goto 1\n".. + "\n".. + " - Jede Zeile beginnt mit einem Nummer\\, welche einem Zeitpunkt entspricht '\\[\\]'\n".. + " - Für Zeitpunkte sind Werte von 1 bis 50000 zulässig\n".. + " - 1 entspricht 100 ms\\, 50000 entspricht in etwa 4 Spieltagen\n".. + " - Leerzeilen oder Kommentare sind erlaubt ('-- comment')\n".. + " - Mit 'send ' kann man ein Kommando an einen Block senden\n".. + " - Mit 'goto ' kann man an eine andere Zeile/Zeitpunkt springen\n".. + " - Mit 'stop' kann man den Sequenzer verzögert stoppen\\, so dass er kein neues Kommando\nvon einem Taster oder anderem Block annimmt (um eine Bewegung abzuschließen)\nOhne 'stop' geht der Sequenzer sofort nach dem letzten Kommando in den stopped Modus.\n".. + "\n".. + "Der TA4 Sequenzer unterstützt folgende techage Kommandos:\n".. + "\n".. + " - 'goto ' Zu einer Kommandozeile springen und damit den Sequenzer starten\n".. + " - 'stop' Den Sequenzer anhalten\n".. + "\n".. + "Das 'goto' Kommando wird nur angenommen\\, wenn der Sequenzer gestoppt ist.\n".. + "\n".. + "\n".. + "\n", "TA4 beinhaltet eine Reihe von leistungsstarken Lampen\\, die eine bessere Ausleuchtung ermöglichen oder Spezialaufgaben übernehmen.\n".. "\n", "Die TA4 LED Pflanzenlampe ermöglicht ein schnelles und kräftiges Wachstum aller Pflanzen aus der 'farming' Mod. Die Lampe beleuchtet ein 3x3 großes Feld\\, so dass sich damit auch Pflanzen unter Tage anbauen lassen.\n".. @@ -1932,9 +1984,12 @@ techage.manual_DE.aItemName = { "ta4_terminal", "", "ta4_button", + "ta4_button_4x", "ta4_playerdetector", "ta4_collector", "ta4_detector", + "ta4_movecontroller", + "ta4_sequencer", "", "ta4_growlight", "ta4_streetlamp", @@ -2154,6 +2209,9 @@ techage.manual_DE.aPlanTable = { "", "", "", + "", + "", + "", "ta4_liquid_filter_base", "ta4_liquid_filter_gravel", "ta4_liquid_filter_top", diff --git a/techage/doc/manual_EN.lua b/techage/doc/manual_EN.lua index c545f12..9a8d062 100644 --- a/techage/doc/manual_EN.lua +++ b/techage/doc/manual_EN.lua @@ -183,9 +183,12 @@ techage.manual_EN.aTitel = { "3,TA4 Lua Controller Terminal", "2,TA4 Logic/Switching Modules", "3,TA4 Button/Switch", + "3,TA4 4x Button", "3,TA4 Player Detector", "3,TA4 State Collector", "3,TA4 Detector", + "3,TA4 Move Controller", + "3,TA4 Sequencer", "2,TA4 Lamps", "3,TA4 LED Grow Light", "3,TA4 Street Lamp", @@ -1125,6 +1128,7 @@ techage.manual_EN.aText = { "The detector is a special tube block that detects when items are passed on through the tube. To do this\\, it must be connected to tubes on both sides. If items are pushed into the detector with a pusher\\, they are automatically passed on.\n".. "It sends an 'on' when an item is recognized\\, followed by an 'off' a second later.\n".. "Then further commands are blocked for 8 seconds.\n".. + "The waiting time and the items that should trigger a command can be configured using the open-ended wrench menu. \n".. "\n".. "\n".. "\n", @@ -1200,7 +1204,7 @@ techage.manual_EN.aText = { "\n".. "\n", "", - "The Techage Info Tool (wrench) has several functions. It shows the time\\, position\\, temperature and biome when an unknown block is clicked on.\n".. + "The Techage Info Tool (open-ended wrench) has several functions. It shows the time\\, position\\, temperature and biome when an unknown block is clicked on.\n".. "If you click on a TechAge block with command interface\\, all available data will be shown (see also \"Logic / switching blocks\").\n".. "\n".. "With Shift + right click an extended menu can be opened for some blocks. Depending on the block\\, further data can be called up or special settings can be made here. In the case of a generator\\, for example\\, the charging curve/switch-off can be programmed. \n".. @@ -1556,6 +1560,10 @@ techage.manual_EN.aText = { "\n".. "\n".. "\n", + "This block has four buttons that can be individually configured using the wrench menu. The labeling and the target block address can be configured for each button. In addition\\, the command that is to be sent can be configured for each button. \n".. + "\n".. + "\n".. + "\n", "Only the appearance of the TA4 player detector has changed. The functionality is the same as with the TA3 player detector.\n".. "\n".. "\n".. @@ -1569,6 +1577,50 @@ techage.manual_EN.aText = { "\n".. "\n".. "\n", + "The TA4 Move Controller is similar to \"Door Controller 2\"\\, but the selected blocks are not removed\\, but can be moved.\n".. + "Since the moving blocks can take players and mobs standing on the block with them\\, elevators and similar transport systems can be built with them.\n".. + "\n".. + "Instructions:\n".. + "\n".. + " - Set the controller and train the blocks to be moved via the menu (up to 16 blocks can be trained)\n".. + " - the \"flight route\" must be entered via an x\\, y\\, z specification (relative) (the maximum distance is 100 m)\n".. + " - The movement can be tested with the menu buttons \"Move A-B\" and \"Move B-A\"\n".. + " - you can also fly through walls or other blocks\n".. + " - The target position for the blocks can also be occupied. In this case\\, the blocks are saved \"invisibly\". This is intended for sliding doors and the like\n".. + " - A \"handover\" can also be programmed in the controller via the open-ended wrench menu. By entering a block number\\, the blocks are then transferred to the next move controller. In this way\\, connected movements can also be implemented using several Move Controllers.\n".. + "\n".. + "The Move Controller supports the following techage commands:\n".. + "\n".. + " - 'a2b' Move block from A to B.\n".. + " - 'b2a' Move block from B to A.\n".. + " - 'move' Move block to the other side\n".. + "\n".. + "\n".. + "\n", + "Entire processes can be programmed using the TA4 sequencer. Here's an example:\n".. + "\n".. + " -- this is a comment\n".. + " \\[1\\] send 1234 a2b\n".. + " \\[30\\] send 1234 b2a\n".. + " \\[60\\] goto 1\n".. + "\n".. + " - Each line begins with a number which corresponds to a point in time '\\[\\]'\n".. + " - Values from 1 to 50000 are permitted for times\n".. + " - 1 corresponds to 100 ms\\, 50000 corresponds to about 4 game days\n".. + " - Empty lines or comments are allowed ('-- comment')\n".. + " - With 'send ' you can send a command to a block\n".. + " - With 'goto ' you can jump to another line / point in time\n".. + " - With 'stop' you can stop the sequencer with a delay so that it does not receive a new command\naccepts from a button or other block (to complete a movement)\nWithout 'stop'\\, the sequencer goes into stopped mode immediately after the last command.\n".. + "\n".. + "The TA4 sequencer supports the following techage commands:\n".. + "\n".. + " - 'goto ' Jump to a command line and start the sequencer\n".. + " - 'stop' Stop the sequencer\n".. + "\n".. + "The 'goto' command is only accepted when the sequencer is stopped.\n".. + "\n".. + "\n".. + "\n", "TA4 contains a series of powerful lamps that enable better illumination or take on special tasks.\n".. "\n", "The TA4 LED grow light enables fast and vigorous growth of all plants from the 'farming' mod. The lamp illuminates a 3x3 field\\, so that plants can also be grown underground.\n".. @@ -1931,9 +1983,12 @@ techage.manual_EN.aItemName = { "ta4_terminal", "", "ta4_button", + "ta4_button_4x", "ta4_playerdetector", "ta4_collector", "ta4_detector", + "ta4_movecontroller", + "ta4_sequencer", "", "ta4_growlight", "ta4_streetlamp", @@ -2153,6 +2208,9 @@ techage.manual_EN.aPlanTable = { "", "", "", + "", + "", + "", "ta4_liquid_filter_base", "ta4_liquid_filter_gravel", "ta4_liquid_filter_top", diff --git a/techage/icta_controller/display.lua b/techage/icta_controller/display.lua index adbeabb..fa01b42 100644 --- a/techage/icta_controller/display.lua +++ b/techage/icta_controller/display.lua @@ -43,7 +43,7 @@ function techage.display.display_update(pos, objref) "default", text, 70, 70, NUM_ROWS, "top", "#000") objref:set_properties({ textures = {texture}, - visual_size = {x=0.94, y=0.94} }) + visual_size = {x=0.94, y=0.94} }) end function techage.display.display_updateXL(pos, objref) @@ -54,7 +54,7 @@ function techage.display.display_updateXL(pos, objref) "default", text, 126, 70, NUM_ROWS, "top", "#000") objref:set_properties({ textures = {texture}, - visual_size = {x=0.94*1.9, y=0.94} }) + visual_size = {x=0.94*1.9, y=0.94} }) end function techage.display.on_timer(pos) diff --git a/techage/images/watermill.png b/techage/images/watermill.png new file mode 100644 index 0000000..8c3a8e2 Binary files /dev/null and b/techage/images/watermill.png differ diff --git a/techage/init.lua b/techage/init.lua index f6414b5..a53ea37 100644 --- a/techage/init.lua +++ b/techage/init.lua @@ -13,7 +13,7 @@ techage = {} -- Version for compatibility checks, see readme.md/history -techage.version = 1.02 +techage.version = 1.03 if minetest.global_exists("tubelib") then minetest.log("error", "[techage] Techage can't be used together with the mod tubelib!") @@ -30,8 +30,8 @@ elseif minetest.global_exists("tubelib2") and tubelib2.version < 1.9 then elseif minetest.global_exists("minecart") and minecart.version < 1.08 then minetest.log("error", "[techage] Techage requires minecart version 1.08 or newer!") return -elseif minetest.global_exists("lcdlib") and lcdlib.version < 1.0 then - minetest.log("error", "[techage] Techage requires lcdlib version 1.0 or newer!") +elseif minetest.global_exists("lcdlib") and lcdlib.version < 1.01 then + minetest.log("error", "[techage] Techage requires lcdlib version 1.01 or newer!") return elseif minetest.global_exists("safer_lua") and safer_lua.version < 1.0 then minetest.log("error", "[techage] Techage requires safer_lua version 1.0 or newer!") @@ -73,6 +73,7 @@ end -- Basis features local MP = minetest.get_modpath("techage") dofile(MP.."/basis/lib.lua") -- helper functions +dofile(MP.."/basis/counting.lua") -- command counting dofile(MP.."/basis/fake_player.lua") -- dummy player object dofile(MP.."/basis/node_store.lua") dofile(MP.."/basis/gravel_lib.lua") -- ore probability @@ -263,6 +264,7 @@ dofile(MP.."/logic/repeater.lua") dofile(MP.."/logic/programmer.lua") dofile(MP.."/logic/signallamp.lua") dofile(MP.."/logic/sequencer.lua") +dofile(MP.."/logic/sequencer2.lua") dofile(MP.."/logic/timer.lua") dofile(MP.."/logic/lua_logic.lua") -- old dofile(MP.."/logic/logic_block.lua") -- new @@ -274,6 +276,8 @@ dofile(MP.."/logic/doorblock.lua") dofile(MP.."/logic/doorcontroller.lua") -- old dofile(MP.."/logic/doorcontroller2.lua") -- new dofile(MP.."/logic/collector.lua") +dofile(MP.."/logic/button_4x.lua") +dofile(MP.."/logic/movecontroller.lua") if minetest.global_exists("mesecon") then dofile(MP.."/logic/mesecons_converter.lua") end diff --git a/techage/liquids/filler.lua b/techage/liquids/filler.lua index 842bd90..2ff3aca 100644 --- a/techage/liquids/filler.lua +++ b/techage/liquids/filler.lua @@ -74,12 +74,12 @@ local function node_timer(pos, elapsed) if not inv:is_empty("src") then local taken = techage.get_items(pos, inv, "src", 1) if liquid.is_container_empty(taken:get_name()) then - return liquid.fill_container({x = pos.x, y = pos.y+1, z = pos.z}, inv, taken:get_name()) + liquid.fill_container({x = pos.x, y = pos.y+1, z = pos.z}, inv, taken:get_name()) else - return liquid.empty_container({x = pos.x, y = pos.y-1, z = pos.z}, inv, taken:get_name()) + liquid.empty_container({x = pos.x, y = pos.y-1, z = pos.z}, inv, taken:get_name()) end end - return false + return true end minetest.register_node("techage:filler", { @@ -124,7 +124,7 @@ minetest.register_node("techage:filler", { on_rotate = screwdriver.disallow, -- important! paramtype = "light", sunlight_propagates = true, - use_texture_alpha = techage.CLIP, + use_texture_alpha = techage.CLIP, is_ground_content = false, groups = {cracky=2, crumbly=2, choppy=2}, sounds = default.node_sound_defaults(), diff --git a/techage/liquids/pump.lua b/techage/liquids/pump.lua index 2762e78..54dc680 100644 --- a/techage/liquids/pump.lua +++ b/techage/liquids/pump.lua @@ -45,7 +45,6 @@ local function pumping(pos, nvm, state, capa) local mem = techage.get_mem(pos) mem.dbg_cycles = (mem.dbg_cycles or 0) - 1 local outdir = M(pos):get_int("outdir") - --print("pumping", outdir, Flip[outdir]) local taken, name = liquid.take(pos, Pipe, Flip[outdir], nil, capa, mem.dbg_cycles > 0) if taken > 0 then local leftover = liquid.put(pos, Pipe, outdir, name, taken, mem.dbg_cycles > 0) diff --git a/techage/liquids/tank.lua b/techage/liquids/tank.lua index a2aab49..51dc523 100644 --- a/techage/liquids/tank.lua +++ b/techage/liquids/tank.lua @@ -53,6 +53,9 @@ end local function take_liquid(pos, indir, name, amount) local nvm = techage.get_nvm(pos) + if (M(pos):get_int("keep_assignment") or 0) == 1 then + amount = math.max(math.min(amount, ((nvm.liquid or {}).amount or 0) - 1), 0) + end amount, name = liquid.srv_take(nvm, name, amount) if techage.is_activeformspec(pos) then M(pos):set_string("formspec", techage.liquid.formspec(pos, nvm)) @@ -219,6 +222,9 @@ minetest.register_node("techage:ta4_tank", { if fields.public then M(pos):set_int("public", fields.public == "true" and 1 or 0) end + if fields.keep_assignment then + M(pos):set_int("keep_assignment", fields.keep_assignment == "true" and 1 or 0) + end end, on_timer = node_timer, on_punch = techage.liquid.on_punch, diff --git a/techage/liquids/valve.lua b/techage/liquids/valve.lua index afea000..40406aa 100644 --- a/techage/liquids/valve.lua +++ b/techage/liquids/valve.lua @@ -43,6 +43,9 @@ minetest.register_node("techage:ta3_valve_open", { return false end, on_rightclick = function(pos, node, clicker) + if minetest.is_protected(pos, clicker:get_player_name()) then + return + end if liquid.turn_valve_off(pos, Pipe, "techage:ta3_valve_closed", "techage:ta3_valve_open") then minetest.sound_play("techage_valve", { pos = pos, @@ -84,6 +87,9 @@ minetest.register_node("techage:ta3_valve_closed", { }, on_rightclick = function(pos, node, clicker) + if minetest.is_protected(pos, clicker:get_player_name()) then + return + end if liquid.turn_valve_on(pos, Pipe, "techage:ta3_valve_closed", "techage:ta3_valve_open") then minetest.sound_play("techage_valve", { pos = pos, diff --git a/techage/locale/techage.de.tr b/techage/locale/techage.de.tr index 61684c3..b81fdd3 100644 --- a/techage/locale/techage.de.tr +++ b/techage/locale/techage.de.tr @@ -113,6 +113,12 @@ Access:=Zugriff: TA3 Button/Switch=TA3 Taster/Schalter TA4 Button/Switch=TA4 Schalter/Taster +### button.lua ### +### button_4x.lua ### +### signallamp_4x.lua ### + +Command=Kommando + ### button.lua ### ### cart_detector.lua ### ### detector.lua ### @@ -130,10 +136,33 @@ Insert destination node number(s)=Gebe Zielnummer(n) ein ### doorcontroller.lua ### ### mesecons_converter.lua ### ### repeater.lua ### +### sequencer2.lua ### ### submenu.lua ### Save=Speichern +### button.lua ### +### signallamp_4x.lua ### + +Command to be sent=Zu sendender Befehl + +### button_4x.lua ### + +Command to be sent (ignored for switches)=Zu sendender Befehl (wird für Schalter ignoriert) +Label=Beschriftung +Label for the button=Beschriftung für die Taste +Momentary button or on/off switch=Taster oder Ein-/Ausschalter +TA4 4x Button=TA4 4x Taster +Type=Typ + +### button_4x.lua ### +### signallamp_4x.lua ### + +Access=Zugriff +Button protection=Tastenschutz +Destination block number=Zielblocknummer +Number=Nummer + ### cart_detector.lua ### TA3 Cart Detector=TA3 Wagen Detektor @@ -204,14 +233,32 @@ TA3 Melting=TA3 Schmelzen TA3 Cooler=TA3 Kühler +### counting.lua ### + +Your current value is=Der aktuelle Wert ist +[techage] The limit for 'number of commands per minute' has been exceeded.=[techage] Das Limit für 'Anzahl Befehle pro Minute' wurde überschritten. +is allowed=ist erlaubt +is allowed. Current value is=ist erlaubt. Aktueller Wert ist +per minute=pro Minute + ### cylinder.lua ### TA2 Cylinder=TA2 Zylinder ### detector.lua ### +Configured Items=Konfigurierte Gegenstände +Items which generate an 'on' command.@nIf empty, all passed items generate an 'on' command.=Items, die einen 'on'-Kommando generieren.@nWenn leer, generieren alle übergebenen Items einen 'on'-Befehl. +On Time=ON Zeit TA3 Detector=TA3 Detektor TA4 Detector=TA4 Detektor +The time after the 'off' command@nuntil the next 'on' command is accepted.=Die Zeit nach dem 'off' Kommando,@nbis das nächste 'on' Kommando akzeptiert wird. +The time between the 'on' and 'off' commands.=Die Zeit zwischen den 'on' und 'off' Kommandos. + +### detector.lua ### +### logic_block.lua ### + +Blocking Time=Sperrzeit ### display.lua ### @@ -250,15 +297,19 @@ Blocks are back=Blöcke sind wieder da Blocks are disappeared=Blöcke sind verschwunden Click on all the blocks that are part of the door/gate=Klicke auf alle Blöcke, die Teil des Tores sind Ctrl,Inv=Ctrl,Inv -Done=Fertig -Record=Aufzeichnen -Recording...=Aufzeichnung... Remove=Entfernen Set=Setzen TA3 Door Controller II=TA3 Tür Controller II -block positions are stored.=Block Positionen gespeichert. with door sound=mit Türgeräusch +### doorcontroller2.lua ### +### movecontroller.lua ### + +Done=Fertig +Record=Aufzeichnen +Recording...=Aufzeichnung... +block positions are stored.=Block Positionen gespeichert. + ### drillbox.lua ### Build derrick=Errichte Ölturm @@ -370,6 +421,7 @@ loaded=geladen ### formspecs.lua ### +Block has a wrench menu=Block hat ein Gabelschlüssel-Menü Charge termination=Ladebegrenzung Current output [ku]=Aktueller Ausgabewert Maximum output [ku]=Maximaler Ausgabewert @@ -570,6 +622,11 @@ Allow public access to the tank=Erlaube öffentlichen Zugriff auf den Tank Liquid Tank=Flüssigkeitstank To add liquids punch@nthe tank@nwith a liquid container=Um Flüssigkeit nachzufüllen,@nschlage mit einem Flüssigkeitsbehälter@nauf den Block +### liquid_lib.lua ### +### ta4_chest.lua ### + +keep assignment=Zuordnung beibehalten + ### liquid_pipe.lua ### TA Junction Pipe=TA Leitungskupplung @@ -595,8 +652,8 @@ no usable water=Kein brauchbares Wasser @nRule:@n @= on/off if is true@n=@nRegel:@n @= on/off if is true@n @nThe internal processing time for all@ncommands is 100 ms.=@nDie interne Durchlaufzeit für alle@nKommandos beträgt 100 ms. @nValid operators:@nand or on off me @=@= ~@= ( )@n=@nGültige Operatoren:@nand or on off @=@= ~@= ( )@n -Blocking Time=Sperrzeit -Help=Hilfe +Clear=Löschen +Debug=Debug Inputs=Eingänge Outputs=Ausgänge Rules=Regeln @@ -606,10 +663,20 @@ Syntax=Syntax ### logic_block.lua ### ### lua_logic.lua ### -Store=Speichern TA3 Logic Block=TA3 Logikblock Update=Update +### logic_block.lua ### +### lua_logic.lua ### +### movecontroller.lua ### + +Store=Speichern + +### logic_block.lua ### +### sequencer2.lua ### + +Help=Hilfe + ### lye.lua ### Lye=Lauge @@ -667,6 +734,28 @@ TA1 Pine Wood Board=TA1 Kiefernholzbrett TA4 Streetlamp Solar Cell=TA4 Straßenlampen-Solarzelle +### movecontroller.lua ### + +Click on all blocks that shall be moved=Klicke auf alle Blöcke, die verschoben werden sollen +Destination position is protected=Zielposition ist geschützt +Error: Distance > 100 m !!=Fehler: Distanz > 100 m !! +Handover to A=Übergabe an A +Handover to B=Übergabe an B +Maximum Speed=Maximalgeschwindigkeit +Maximum speed for the moving block.=Maximale Geschwindigkeit für den beweglichen Block. +Move A-B=Bewege A-B +Move B-A=Bewege B-A +Move block height=Move Block Höhe +Move distance (A to B)=Entfernung (A nach B) +No valid destination position=Keine gültige Zielposition +No valid node at the start position=Kein gültiger Block an der Startposition +Number of the next movecontroller.=Nummer des nächsten Move Controllers. +Number of the previous movecontroller.=Nummer des vorherigen Move Controllers. +Position list error=Positionslistenfehler +Start position is protected=Startposition ist geschützt +TA4 Move Controller=TA4 Move Controller +Value in the range of 0.0 to 1.0=Wert im Bereich von 0.0 bis 1.0 + ### node_detector.lua ### Send signal if nodes have been:=Sende ein Signal falls Blöcke: @@ -750,7 +839,7 @@ TA Power Pole Top 2 (for landlines)=TA Strommastkopf 2 (für Überlandleitungen) ### power_terminal2.lua ### -Commands@nhelp . . . print this text@ncls . . . . . clear screen@ngen . . . . print all generators@nsto . . . . . print all storage systems@n=Kommandos@nhelp . . . diesen Text ausgeben@ncls . . . . . Bildschirm löschen@ngen . . . . Alle Generatoren ausgeben@nsto . . . . . Alle Speichersysteme ausgeben@n +Commands@nhelp . . . print this text@ncls . . . . . clear screen@ngen . . . . print all generators@nsto . . . . . print all storage systems@ncon . . . . . print main consumers@n=Kommandos@nhelp . . . diesen Text ausgeben@ncls . . . . . Bildschirm löschen@ngen . . . . Alle Generatoren ausgeben@nsto . . . . . Alle Speichersysteme ausgeben@ncon . . . . . Hauptverbraucher ausgeben@n Consumer=Verbraucher Network Data=Netzwerkdaten Number of consumers:=Anzahl der Verbraucher @@ -877,14 +966,48 @@ not connected=nicht verbunden ### sequencer.lua ### TA3 Sequencer=TA3 Sequenzer + +### sequencer.lua ### +### sequencer2.lua ### + stopped=gestoppt +### sequencer2.lua ### + + - 'goto ' (jump to another line)@n= - 'goto ' (springe zu einer anderen Zeile)@n + - 'send ' (techage command)@n= - 'send ' (techage Kommando)@n + - 'stop' (stop the execution)@n= - 'stop' (stoppe die Ausführung)@n + - 1 corresponds to 100 ms@n= - 1 entspricht 100 ms@n + - 50000 corresponds to 4 game days@n= - 50000 entspricht 4 Spieltagen@n +'[] '@n='[] '@n + is one of the following:@n= ist eines der folgenden:@n + is a number from 1 to 50000 and is@n= ist eine Nummer von 1 bis 50000 und ist@n +@n=@n +Commands=Kommandos +Example:@n=Beispiel: +Invalid command!=Ungültiges Kommando! +Start=Start +Stop=Stopp +Syntax:@n=Syntax:@n +TA4 Sequencer=TA4 Sequenzer +running=läuft +the timeslot when the command is executed.@n=der Zeitpunkt, wenn der Befehl ausgeführt wird.@n + +### sequencer2.lua ### +### submenu.lua ### + +Cancel=Abbruch + ### signallamp.lua ### TA4 Wind Turbine Signal Lamp=TA4 Windkraftanlagenlampe TechAge Signal Lamp=TechAge Signallampe TechAge Signal Lamp (can be colored)=TechAge Signallampe (kann gefärbt werden) +### signallamp_4x.lua ### + +TA4 4x Signal Lamp= + ### silicon.lua ### TA4 Silicon Wafer=TA4 Silizium-Wafer @@ -902,7 +1025,6 @@ TA Lamp=TA Lampe TA1 Sluice Gate=TA1 Schleusenschieber TA1 Sluice Handle=TA1 Schleusengriff -Your pond is too small!=Der Teich ist zu klein! ### solarcell.lua ### @@ -948,7 +1070,6 @@ TA4 LED Street Lamp Pole=TA4 LED Lampenmast ### submenu.lua ### -Cancel=Abbruch Note: You can't change any values while the block is running!=Hinweis: Während der Block läuft, kann kein Wert geändert werden! Refresh=Aktualisieren @@ -982,7 +1103,6 @@ Size=Größe TA4 8x2000 Chest=TA4 8x2000 Kiste Unlock=Entsperren Unlock connected chest@nif all slots are below 2000=Nachfolgende Kiste entsperren,@nsofern alle Speicherplätze <= 2000 -keep assignment=Zuordnung beibehalten right to left=von rechts nach links ### ta4_doser.lua ### @@ -1099,11 +1219,6 @@ Usmium Powder=Usmium Pulver TA Valve=TA Ventil TA3 Valve=TA3 Ventil -### water.lua ### - -Flowing Water=Fließendes Wasser -Water Source=Wasserquelle - ### waterinlet.lua ### Error: No natural water!=Fehler: Kein natürliches Wasser! @@ -1132,3 +1247,8 @@ This is not the surface of the ocean!=Das ist nicht die Meeresoberfläche! [TA4 Wind Turbine]=[TA4 Windkraftanlage] biome and no ocean!=Biom und keine Meer (ocean)! is a suitable place for a wind turbine!=ist ein geeigneter Ort für eine Windkraftanlage! + + +##### not used anymore ##### + +[techage] The limit for commands per minute has been exceeded.=[techage] Das Limit für Befehle pro Minute wurde überschritten. diff --git a/techage/locale/template.txt b/techage/locale/template.txt index 4b9d436..ead7e30 100644 --- a/techage/locale/template.txt +++ b/techage/locale/template.txt @@ -113,6 +113,12 @@ Access:= TA3 Button/Switch= TA4 Button/Switch= +### button.lua ### +### button_4x.lua ### +### signallamp_4x.lua ### + +Command= + ### button.lua ### ### cart_detector.lua ### ### detector.lua ### @@ -130,10 +136,33 @@ Insert destination node number(s)= ### doorcontroller.lua ### ### mesecons_converter.lua ### ### repeater.lua ### +### sequencer2.lua ### ### submenu.lua ### Save= +### button.lua ### +### signallamp_4x.lua ### + +Command to be sent= + +### button_4x.lua ### + +Command to be sent (ignored for switches)= +Label= +Label for the button= +Momentary button or on/off switch= +TA4 4x Button= +Type= + +### button_4x.lua ### +### signallamp_4x.lua ### + +Access= +Button protection= +Destination block number= +Number= + ### cart_detector.lua ### TA3 Cart Detector= @@ -204,14 +233,32 @@ TA3 Melting= TA3 Cooler= +### counting.lua ### + +Your current value is= +[techage] The limit for 'number of commands per minute' has been exceeded.= +is allowed= +is allowed. Current value is= +per minute= + ### cylinder.lua ### TA2 Cylinder= ### detector.lua ### +Configured Items= +Items which generate an 'on' command.@nIf empty, all passed items generate an 'on' command.= +On Time= TA3 Detector= TA4 Detector= +The time after the 'off' command@nuntil the next 'on' command is accepted.= +The time between the 'on' and 'off' commands.= + +### detector.lua ### +### logic_block.lua ### + +Blocking Time= ### display.lua ### @@ -250,15 +297,19 @@ Blocks are back= Blocks are disappeared= Click on all the blocks that are part of the door/gate= Ctrl,Inv= -Done= -Record= -Recording...= Remove= Set= TA3 Door Controller II= -block positions are stored.= with door sound= +### doorcontroller2.lua ### +### movecontroller.lua ### + +Done= +Record= +Recording...= +block positions are stored.= + ### drillbox.lua ### Build derrick= @@ -370,6 +421,7 @@ loaded= ### formspecs.lua ### +Block has a wrench menu= Charge termination= Current output [ku]= Maximum output [ku]= @@ -570,6 +622,11 @@ Allow public access to the tank= Liquid Tank= To add liquids punch@nthe tank@nwith a liquid container= +### liquid_lib.lua ### +### ta4_chest.lua ### + +keep assignment= + ### liquid_pipe.lua ### TA Junction Pipe= @@ -595,8 +652,8 @@ no usable water= @nRule:@n @= on/off if is true@n= @nThe internal processing time for all@ncommands is 100 ms.= @nValid operators:@nand or on off me @=@= ~@= ( )@n= -Blocking Time= -Help= +Clear= +Debug= Inputs= Outputs= Rules= @@ -606,10 +663,20 @@ Syntax= ### logic_block.lua ### ### lua_logic.lua ### -Store= TA3 Logic Block= Update= +### logic_block.lua ### +### lua_logic.lua ### +### movecontroller.lua ### + +Store= + +### logic_block.lua ### +### sequencer2.lua ### + +Help= + ### lye.lua ### Lye= @@ -667,6 +734,28 @@ TA1 Pine Wood Board= TA4 Streetlamp Solar Cell= +### movecontroller.lua ### + +Click on all blocks that shall be moved= +Destination position is protected= +Error: Distance > 100 m !!= +Handover to A= +Handover to B= +Maximum Speed= +Maximum speed for the moving block.= +Move A-B= +Move B-A= +Move block height= +Move distance (A to B)= +No valid destination position= +No valid node at the start position= +Number of the next movecontroller.= +Number of the previous movecontroller.= +Position list error= +Start position is protected= +TA4 Move Controller= +Value in the range of 0.0 to 1.0= + ### node_detector.lua ### Send signal if nodes have been:= @@ -750,7 +839,7 @@ TA Power Pole Top 2 (for landlines)= ### power_terminal2.lua ### -Commands@nhelp . . . print this text@ncls . . . . . clear screen@ngen . . . . print all generators@nsto . . . . . print all storage systems@n= +Commands@nhelp . . . print this text@ncls . . . . . clear screen@ngen . . . . print all generators@nsto . . . . . print all storage systems@ncon . . . . . print main consumers@n= Consumer= Network Data= Number of consumers:= @@ -877,14 +966,48 @@ not connected= ### sequencer.lua ### TA3 Sequencer= + +### sequencer.lua ### +### sequencer2.lua ### + stopped= +### sequencer2.lua ### + + - 'goto ' (jump to another line)@n= + - 'send ' (techage command)@n= + - 'stop' (stop the execution)@n= + - 1 corresponds to 100 ms@n= + - 50000 corresponds to 4 game days@n= +'[] '@n= + is one of the following:@n= + is a number from 1 to 50000 and is@n= +@n= +Commands= +Example:@n= +Invalid command!= +Start= +Stop= +Syntax:@n= +TA4 Sequencer= +running= +the timeslot when the command is executed.@n= + +### sequencer2.lua ### +### submenu.lua ### + +Cancel= + ### signallamp.lua ### TA4 Wind Turbine Signal Lamp= TechAge Signal Lamp= TechAge Signal Lamp (can be colored)= +### signallamp_4x.lua ### + +TA4 4x Signal Lamp= + ### silicon.lua ### TA4 Silicon Wafer= @@ -902,7 +1025,6 @@ TA Lamp= TA1 Sluice Gate= TA1 Sluice Handle= -Your pond is too small!= ### solarcell.lua ### @@ -948,7 +1070,6 @@ TA4 LED Street Lamp Pole= ### submenu.lua ### -Cancel= Note: You can't change any values while the block is running!= Refresh= @@ -982,7 +1103,6 @@ Size= TA4 8x2000 Chest= Unlock= Unlock connected chest@nif all slots are below 2000= -keep assignment= right to left= ### ta4_doser.lua ### @@ -1099,11 +1219,6 @@ Usmium Powder= TA Valve= TA3 Valve= -### water.lua ### - -Flowing Water= -Water Source= - ### waterinlet.lua ### Error: No natural water!= diff --git a/techage/logic/button.lua b/techage/logic/button.lua index eac8d1b..7840d8c 100644 --- a/techage/logic/button.lua +++ b/techage/logic/button.lua @@ -19,6 +19,16 @@ local NDEF = function(pos) return (minetest.registered_nodes[techage.get_node_lv local logic = techage.logic +local WRENCH_MENU = { + { + type = "ascii", + name = "command", + label = S("Command"), + tooltip = S("Command to be sent"), + default = "on", + }, +} + local function switch_on(pos) local cycle_time = M(pos):get_int("cycle_time") local name = techage.get_node_lvm(pos).name @@ -27,7 +37,10 @@ local function switch_on(pos) elseif name == "techage:ta4_button_off" then logic.swap_node(pos, "techage:ta4_button_on") end - logic.send_on(pos, M(pos), cycle_time) + local meta = M(pos) + local s = meta:contains("command") and meta:get_string("command") or "on" + local command, payload = unpack(string.split(s, " ", false, 1)) + logic.send_cmnd(pos, M(pos), command, payload, cycle_time) minetest.sound_play("techage_button", { pos = pos, gain = 0.5, @@ -249,6 +262,7 @@ minetest.register_node("techage:ta4_button_off", { meta:set_int("cycle_time", 0) end, + ta4_formspec = WRENCH_MENU, on_receive_fields = on_receive_fields, on_rightclick = on_rightclick_on, techage_set_numbers = techage_set_numbers, diff --git a/techage/logic/button_4x.lua b/techage/logic/button_4x.lua new file mode 100644 index 0000000..56ef4ea --- /dev/null +++ b/techage/logic/button_4x.lua @@ -0,0 +1,297 @@ +--[[ + + TechAge + ======= + + Copyright (C) 2017-2021 Joachim Stolberg + + AGPL v3 + See LICENSE.txt for more information + + TA4 Logic fourfold button + +]]-- + +-- for lazy programmers +local M = minetest.get_meta +local S = techage.S + +local function get_button_num(pos, clicker, pointed_thing) + -- use the node behind the button to get better results + if clicker and pointed_thing then + local offs = vector.subtract(pointed_thing.under, pointed_thing.above) + pointed_thing.under = vector.add(pointed_thing.under, offs) + pointed_thing.above = vector.add(pointed_thing.above, offs) + local pos1 = minetest.pointed_thing_to_face_pos(clicker, pointed_thing) + local y = pos1.y - pos.y + + if y < -0.3 then + return 4 + elseif y < -0.03 and y > -0.22 then + return 3 + elseif y > 0.03 and y < 0.22 then + return 2 + elseif y > 0.3 then + return 1 + end + end +end + +local WRENCH_MENU = { + { + type = "dropdown", + choices = "button,switch", + name = "type", + label = S("Type"), + tooltip = S("Momentary button or on/off switch"), + default = "1", + }, + { + type = "ascii", + name = "label1", + label = S("Label") .. " 1", + tooltip = S("Label for the button"), + default = "1", + }, + { + type = "numbers", + name = "dest_number1", + label = S("Number") .. " 1", + tooltip = S("Destination block number"), + default = "", + }, + { + type = "ascii", + name = "command1", + label = S("Command") .. " 1", + tooltip = S("Command to be sent (ignored for switches)"), + default = "1", + }, + { + type = "ascii", + name = "label2", + label = S("Label") .. " 2", + tooltip = S("Label for the button"), + default = "1", + }, + { + type = "numbers", + name = "dest_number2", + label = S("Number") .. " 2", + tooltip = S("Destination block number"), + default = "", + }, + { + type = "ascii", + name = "command2", + label = S("Command") .. " 2", + tooltip = S("Command to be sent (ignored for switches)"), + default = "2", + }, + { + type = "ascii", + name = "label3", + label = S("Label") .. " 3", + tooltip = S("Label for the button"), + default = "1", + }, + { + type = "numbers", + name = "dest_number3", + label = S("Number") .. " 3", + tooltip = S("Destination block number"), + default = "", + }, + { + type = "ascii", + name = "command3", + label = S("Command") .. " 3", + tooltip = S("Command to be sent (ignored for switches)"), + default = "3", + }, + { + type = "ascii", + name = "label4", + label = S("Label") .. " 4", + tooltip = S("Label for the button"), + default = "1", + }, + { + type = "numbers", + name = "dest_number4", + label = S("Number") .. " 4", + tooltip = S("Destination block number"), + default = "", + }, + { + type = "ascii", + name = "command4", + label = S("Command") .. " 4", + tooltip = S("Command to be sent (ignored for switches)"), + default = "4", + }, + { + type = "dropdown", + choices = "private,protected,public", + name = "access", + label = S("Access"), + tooltip = S("Button protection"), + default = "8", + }, +} + +local function send_cmnd(pos, num, cmd) + local meta = M(pos) + local own_num = meta:get_string("node_number") + local dest = meta:get_string("dest_number" .. num) + local command, payload = cmd, nil + if not cmd then + local s = meta:get_string("command" .. num) + command, payload = unpack(string.split(s, " ", false, 1)) + end + local owner = meta:get_string("owner") + if techage.check_numbers(dest, owner) then + techage.send_multi(own_num, dest, command, payload) + end +end + +local function button_update(pos, objref) + local meta = M(pos) + pos = vector.round(pos) + local nvm = techage.get_nvm(pos) + nvm.button = nvm.button or {} + local tbl = {meta:get_string("label1"), " ", meta:get_string("label2"), " ", meta:get_string("label3"), " ", meta:get_string("label4")} + local text = "< " .. table.concat(tbl, "\n< ") + local texture = lcdlib.make_multiline_texture("default", text, 96, 96, 7, "top", "#000", 6) + + if nvm.button[1] then + texture = texture .. "^techage_smartline_button_4x_on1.png" + end + if nvm.button[2] then + texture = texture .. "^techage_smartline_button_4x_on2.png" + end + if nvm.button[3] then + texture = texture .. "^techage_smartline_button_4x_on3.png" + end + if nvm.button[4] then + texture = texture .. "^techage_smartline_button_4x_on4.png" + end + objref:set_properties({ textures = {texture}, visual_size = {x=1, y=1} }) +end + +local function switch_off(pos, num) + local nvm = techage.get_nvm(pos) + nvm.button = nvm.button or {} + nvm.button[num] = nil + lcdlib.update_entities(pos) +end + +local function switch_on(pos, num) + local nvm = techage.get_nvm(pos) + nvm.button = nvm.button or {} + nvm.button[num] = true + lcdlib.update_entities(pos) +end + +local lcd_box = {-8/16, -8/16, 7.75/16, 8/16, 8/16, 8/16} + +minetest.register_node("techage:ta4_button_4x", { + description = S("TA4 4x Button"), + inventory_image = 'techage_smartline_button_4x.png', + tiles = {'techage_smartline_button_4x.png'}, + drawtype = "nodebox", + paramtype = "light", + use_texture_alpha = "clip", + sunlight_propagates = true, + paramtype2 = "facedir", + node_box = { + type = "fixed", + fixed = lcd_box, + }, + light_source = 6, + + display_entities = { + ["techage:display_entity"] = { depth = 0.48, + on_display_update = button_update}, + }, + + after_place_node = function(pos, placer) + local number = techage.add_node(pos, "techage:ta4_button_4x") + local meta = minetest.get_meta(pos) + meta:set_string("node_number", number) + meta:set_string("owner", placer:get_player_name()) + meta:set_string("infotext", "TA4 4x Button " .. number) + meta:set_string("type", "button") + meta:set_string("label1", "B1") + meta:set_string("label2", "B2") + meta:set_string("label3", "B3") + meta:set_string("label4", "B4") + lcdlib.update_entities(pos) + end, + + on_rightclick = function(pos, node, clicker, itemstack, pointed_thing) + if clicker and clicker:is_player() then + local playername = clicker:get_player_name() + if minetest.is_protected(pos, playername) then + return + end + -- Check node settings in addition + local access = M(pos):get_string("access") + local owner = M(pos):get_string("owner") + if access == "private" and playername ~= owner then + return + end + + local num = get_button_num(pos, clicker, pointed_thing) + if num then + local typ = M(pos):get_string("type") + if typ == "switch" then + local nvm = techage.get_nvm(pos) + nvm.button = nvm.button or {} + if nvm.button[num] then + switch_off(pos, num) + send_cmnd(pos, num, "off") + else + switch_on(pos, num) + send_cmnd(pos, num, "on") + end + else + switch_on(pos, num) + send_cmnd(pos, num) + minetest.after(0.5, switch_off, pos, num) + end + minetest.sound_play("techage_button", { + pos = pos, + gain = 0.5, + max_hear_distance = 5, + }) + end + end + end, + + ta_after_formspec = function(pos, fields, playername) + lcdlib.update_entities(pos) + end, + + after_dig_node = function(pos, oldnode, oldmetadata) + techage.remove_node(pos, oldnode, oldmetadata) + end, + + ta3_formspec = WRENCH_MENU, + on_place = lcdlib.on_place, + on_construct = lcdlib.on_construct, + on_destruct = lcdlib.on_destruct, + on_rotate = lcdlib.on_rotate, + groups = {cracky=2, crumbly=2}, + is_ground_content = false, + sounds = default.node_sound_glass_defaults(), +}) + +minetest.register_craft({ + output = "techage:ta4_button_4x", + recipe = { + {"", "techage:ta4_button_off", "techage:ta4_button_off"}, + {"", "techage:ta4_button_off", "techage:ta4_button_off"}, + {"", "", ""}, + }, +}) diff --git a/techage/logic/collector.lua b/techage/logic/collector.lua index e03e391..414b491 100644 --- a/techage/logic/collector.lua +++ b/techage/logic/collector.lua @@ -86,8 +86,8 @@ local function on_timer(pos,elapsed) if nvm.idx > #nvm.poll_numbers then nvm.idx = 1 - send_event(nvm, meta) if nvm.stored_state ~= nvm.common_state then + send_event(nvm, meta) local own_number = meta:get_string("own_number") meta:set_string("infotext", S("TA4 State Collector").." "..own_number..': "'..lStates[nvm.common_state]..'"') nvm.stored_state = nvm.common_state diff --git a/techage/logic/detector.lua b/techage/logic/detector.lua index d9b9ab0..b89816e 100644 --- a/techage/logic/detector.lua +++ b/techage/logic/detector.lua @@ -19,6 +19,33 @@ local NDEF = function(pos) return (minetest.registered_nodes[techage.get_node_lv local logic = techage.logic local BLOCKING_TIME = 8 -- seconds +local ON_TIME = 1 + +local WRENCH_MENU = { + { + type = "dropdown", + choices = "1,2,4,6,8,12,16", + name = "ontime", + label = S("On Time") .. " [s]", + tooltip = S("The time between the 'on' and 'off' commands."), + default = "1", + }, + { + type = "dropdown", + choices = "2,4,6,8,12,16,20", + name = "blockingtime", + label = S("Blocking Time") .. " [s]", + tooltip = S("The time after the 'off' command\nuntil the next 'on' command is accepted."), + default = "8", + }, + { + type = "items", + name = "config", + label = S("Configured Items"), + tooltip = S("Items which generate an 'on' command.\nIf empty, all passed items generate an 'on' command."), + size = 4, + } +} local function switch_on(pos) local mem = techage.get_mem(pos) @@ -30,8 +57,11 @@ local function switch_on(pos) else logic.swap_node(pos, "techage:ta4_detector_on") end - logic.send_on(pos, M(pos), 1) - mem.time = t + BLOCKING_TIME + local meta = M(pos) + local on_time = math.max(meta:get_int("ontime"), ON_TIME) + local blocking_time = tonumber(meta:get_string("blockingtime")) or BLOCKING_TIME + logic.send_on(pos, meta, on_time) + mem.time = t + blocking_time + on_time end end @@ -48,12 +78,15 @@ end local function formspec(meta) local numbers = meta:get_string("numbers") or "" return "size[7.5,3]".. + techage.wrench_image(7, -0.1) .. "field[0.5,1;7,1;numbers;"..S("Insert destination node number(s)")..";"..numbers.."]" .. "button_exit[2,2;3,1;exit;"..S("Save").."]" end local function after_place_node(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) meta:set_string("formspec", formspec(meta)) @@ -97,6 +130,7 @@ minetest.register_node("techage:ta3_detector_off", { on_receive_fields = on_receive_fields, techage_set_numbers = techage_set_numbers, after_dig_node = after_dig_node, + ta3_formspec = WRENCH_MENU, on_rotate = screwdriver.disallow, paramtype = "light", @@ -124,6 +158,7 @@ minetest.register_node("techage:ta3_detector_on", { on_rotate = screwdriver.disallow, techage_set_numbers = techage_set_numbers, after_dig_node = after_dig_node, + ta3_formspec = WRENCH_MENU, paramtype2 = "facedir", groups = {choppy=2, cracky=2, crumbly=2, not_in_creative_inventory=1}, @@ -148,6 +183,7 @@ minetest.register_node("techage:ta4_detector_off", { on_receive_fields = on_receive_fields, techage_set_numbers = techage_set_numbers, after_dig_node = after_dig_node, + ta3_formspec = WRENCH_MENU, on_rotate = screwdriver.disallow, paramtype = "light", @@ -175,6 +211,7 @@ minetest.register_node("techage:ta4_detector_on", { on_rotate = screwdriver.disallow, techage_set_numbers = techage_set_numbers, after_dig_node = after_dig_node, + ta3_formspec = WRENCH_MENU, paramtype2 = "facedir", groups = {choppy=2, cracky=2, crumbly=2, not_in_creative_inventory=1}, @@ -204,7 +241,10 @@ minetest.register_craft({ techage.register_node({"techage:ta3_detector_off", "techage:ta3_detector_on"}, { on_push_item = function(pos, in_dir, stack) if techage.safe_push_items(pos, in_dir, stack) then - switch_on(pos) + local inv = minetest.get_inventory({type = "node", pos = pos}) + if not inv or inv:is_empty("cfg") or inv:contains_item("cfg", ItemStack(stack:get_name())) then + switch_on(pos) + end return true end return false diff --git a/techage/logic/doorcontroller2.lua b/techage/logic/doorcontroller2.lua index d8c2f76..9b3e916 100644 --- a/techage/logic/doorcontroller2.lua +++ b/techage/logic/doorcontroller2.lua @@ -230,7 +230,7 @@ minetest.register_node("techage:ta3_doorcontroller2", { local meta = M(pos) local inv = meta:get_inventory() inv:set_size('main', 16) - logic.after_place_node(pos, placer, "techage:ta3_doorcontroller", S("TA3 Door Controller II")) + logic.after_place_node(pos, placer, "techage:ta3_doorcontroller2", S("TA3 Door Controller II")) logic.infotext(meta, S("TA3 Door Controller II")) local nvm = techage.get_nvm(pos) meta:set_string("formspec", formspec1(nvm, meta)) @@ -321,7 +321,9 @@ minetest.register_node("techage:ta3_doorcontroller2", { return inv:is_empty("main") end, - after_dig_node = function(pos, oldnode, oldmetadata) + after_dig_node = function(pos, oldnode, oldmetadata, digger) + local name = digger:get_player_name() + unmark_all(name) techage.remove_node(pos, oldnode, oldmetadata) end, @@ -423,3 +425,5 @@ for _, name in ipairs(ProtectorDoors) do logic.register_doorcontroller_nodes({name .. "_" .. postfix}) end end + +logic.SimpleNodes = RegisteredNodes diff --git a/techage/logic/lib.lua b/techage/logic/lib.lua index 7feb550..86a99fe 100644 --- a/techage/logic/lib.lua +++ b/techage/logic/lib.lua @@ -67,6 +67,15 @@ function techage.logic.send_on(pos, meta, time) return own_num == numbers end +function techage.logic.send_cmnd(pos, meta, cmnd, payload, time) + local own_num = meta:get_string("node_number") or "" + local numbers = meta:get_string("numbers") or "" + if time and time > 0 then + minetest.get_node_timer(pos):start(time) + end + techage.send_multi(own_num, numbers, cmnd, payload) +end + function techage.logic.send_off(pos, meta) local own_num = meta:get_string("node_number") or "" local numbers = meta:get_string("numbers") or "" diff --git a/techage/logic/movecontroller.lua b/techage/logic/movecontroller.lua new file mode 100644 index 0000000..55939ee --- /dev/null +++ b/techage/logic/movecontroller.lua @@ -0,0 +1,812 @@ +--[[ + + TechAge + ======= + + Copyright (C) 2020-2021 Joachim Stolberg + + AGPL v3 + See LICENSE.txt for more information + + TA4 Move Controller + +]]-- + +-- for lazy programmers +local M = minetest.get_meta +local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end +local S2P = minetest.string_to_pos +local S = techage.S + +------------------------------------------------------------------------------- +-- Entity / Move / Attach / Detach +------------------------------------------------------------------------------- +local MIN_SPEED = 0.4 +local MAX_SPEED = 8 + +local function to_vector(s) + local x,y,z = unpack(string.split(s, ",")) + if x and y and z then + return { + x=tonumber(x) or 0, + y=tonumber(y) or 0, + z=tonumber(z) or 0, + } + end + return {x=0, y=0, z=0} +end + +-- Only the ID ist stored, not the object +local function get_object_id(object) + for id, entity in pairs(minetest.luaentities) do + if entity.object == object then + return id + end + end +end + +-- determine exact position of attached entities +local function obj_pos(obj) + local _, _, pos = obj:get_attach() + pos = vector.divide(pos, 29) + return vector.add(obj:get_pos(), pos) +end + +-- Check access conflicts with other mods +local function lock_player(player) + local meta = player:get_meta() + if meta:get_int("player_physics_locked") == 0 then + meta:set_int("player_physics_locked", 1) + meta:set_string("player_physics_locked_by", "ta_movecontroller") + return true + end + return false +end + +local function unlock_player(player) + local meta = player:get_meta() + if meta:get_int("player_physics_locked") == 1 then + if meta:get_string("player_physics_locked_by") == "ta_movecontroller" then + meta:set_int("player_physics_locked", 0) + meta:set_string("player_physics_locked_by", "") + return true + end + end + return false +end + +local function detach_player(player) + local pos = obj_pos(player) + player:set_detach() + player:set_properties({visual_size = {x=1, y=1}}) + player:set_pos(pos) + -- TODO: move to save position +end + + +-- Attach player/mob to given parent object (block) +local function attach_single_object(parent, obj, dir) + local self = parent:get_luaentity() + local rot = obj:get_rotation() + local res = obj:get_attach() + if not res then + local offs = table.copy(dir) + dir = vector.multiply(dir, 29) + obj:set_attach(parent, "", dir, rot, true) + obj:set_properties({visual_size = {x=2.9, y=2.9}}) + if obj:is_player() then + if lock_player(obj) then + table.insert(self.players, {name = obj:get_player_name(), offs = offs}) + end + else + table.insert(self.entities, {objID = get_object_id(obj), offs = offs}) + end + end +end + +-- Attach all objects around to the parent object +-- offs is the search/attach position offset +local function attach_objects(pos, offs, parent) + local pos1 = vector.add(pos, offs) + for _, obj in pairs(minetest.get_objects_inside_radius(pos1, 0.9)) do + local dir = vector.subtract(obj:get_pos(), pos) + local entity = obj:get_luaentity() + if entity then + if entity.name == "__builtin:item" then -- dropped items + --obj:set_attach(objref, "", {x=0, y=0, z=0}, {x=0, y=0, z=0}, true) -- hier kracht es + elseif entity.name ~= "techage:move_item" then + attach_single_object(parent, obj, dir) + end + elseif obj:is_player() then + attach_single_object(parent, obj, dir) + end + end +end + +-- Detach all attached objects from the parent object +local function detach_objects(pos, self) + for _, item in ipairs(self.entities or {}) do + local entity = minetest.luaentities[item.objID] + if entity then + local obj = entity.object + obj:set_detach() + obj:set_properties({visual_size = {x=1, y=1}}) + local pos1 = vector.add(pos, item.offs) + obj:set_pos(pos1) + end + end + for _, item in ipairs(self.players or {}) do + local obj = minetest.get_player_by_name(item.name) + if obj then + obj:set_detach() + obj:set_properties({visual_size = {x=1, y=1}}) + local pos1 = vector.add(pos, item.offs) + obj:set_pos(pos1) + unlock_player(obj) + end + end + self.entities = {} + self.players = {} +end + +local function entity_to_node(pos, obj) + local self = obj:get_luaentity() + if self then + local name = self.item or "air" + local metadata = self.metadata or {} + local rot = obj:get_rotation() + detach_objects(pos, self) + obj:remove() + + pos = vector.round(pos) + local dir = minetest.yaw_to_dir(rot.y or 0) + local param2 = minetest.dir_to_facedir(dir) or 0 + local node = minetest.get_node(pos) + local ndef1 = minetest.registered_nodes[name] + local ndef2 = minetest.registered_nodes[node.name] + if ndef1 and ndef2 then + if ndef2.buildable_to then + local meta = M(pos) + minetest.set_node(pos, {name=name, param2=param2}) + meta:from_table(metadata) + meta:set_string("ta_move_block", "") + return + end + local meta = M(pos) + if not meta:contains("ta_move_block") then + meta:set_string("ta_move_block", minetest.serialize({name=name, param2=param2})) + return + end + minetest.add_item(pos, ItemStack(name)) + elseif ndef1 then + minetest.add_item(pos, ItemStack(name)) + end + end +end + +local function node_to_entity(pos, handover) + local meta = M(pos) + local node, metadata + + if meta:contains("ta_move_block") then + node = minetest.deserialize(meta:get_string("ta_move_block")) + metadata = {} + meta:set_string("ta_move_block", "") + else + node = minetest.get_node(pos) + meta:set_string("ta_move_block", "") + metadata = meta:to_table() + minetest.remove_node(pos) + end + local dir = minetest.facedir_to_dir(node.param2) + local yaw = minetest.dir_to_yaw(dir) + local obj = minetest.add_entity(pos, "techage:move_item") + if obj then + local self = obj:get_luaentity() + obj:set_rotation({x=0, y=yaw, z=0}) + obj:set_properties({wield_item=node.name}) + obj:set_armor_groups({immortal=1}) + self.item = node.name + self.metadata = metadata or {} + self.handover = handover + self.start_pos = table.copy(pos) + return obj + end +end + +local function capture_entity(pos) + local l = minetest.get_objects_in_area(pos, pos) + for _, obj in ipairs(l) do + local self = obj:get_luaentity() + if self and self.name == "techage:move_item" then + return obj + end + end +end + +-- move block direction +local function determine_dir(pos1, pos2) + local vdist = vector.subtract(pos2, pos1) + local ndist = vector.length(vdist) + return vector.divide(vdist, ndist) +end + +local function move_entity(obj, pos2, dir, max_speed) + local self = obj:get_luaentity() + self.max_speed = max_speed + self.dest_pos = table.copy(pos2) + self.dir = dir + local acc = vector.multiply(dir, max_speed / 2) + obj:set_acceleration(acc) +end + +-- Handover the entity to the next movecontroller +local function handover_to(pos, self) + local info = techage.get_node_info(self.handover) + if info and info.name == "techage:ta4_movecontroller" then + local mem = techage.get_mem(info.pos) + if not mem.entities_are_there then + mem.entities_are_there = true + -- copy move direction + --print("techage.get_nvm(pos).pos_2to1", techage.get_nvm(pos).pos_2to1) + techage.get_nvm(info.pos).pos_2to1 = techage.get_nvm(pos).pos_2to1 + minetest.after(0.2, techage.send_single, "0", self.handover, "handover") + end + return true + end +end + +minetest.register_entity("techage:move_item", { + initial_properties = { + pointable = true, + makes_footstep_sound = true, + static_save = true, + collide_with_objects = false, + physical = false, + visual = "wielditem", + wield_item = "default:dirt", + visual_size = {x=0.67, y=0.67, z=0.67}, + selectionbox = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5}, + }, + + get_staticdata = function(self) + return minetest.serialize({ + item = self.item, + max_speed = self.max_speed, + dest_pos = self.dest_pos, + start_pos = self.start_pos, + dir = self.dir, + metadata = self.metadata, + respawn = true, + }) + end, + + on_activate = function(self, staticdata) + if staticdata then + local tbl = minetest.deserialize(staticdata) or {} + self.item = tbl.item or "air" + self.max_speed = tbl.max_speed or MAX_SPEED + self.dest_pos = tbl.dest_pos or self.object:get_pos() + self.start_pos = tbl.start_pos or self.object:get_pos() + self.dir = tbl.dir or {x=0, y=0, z=0} + self.metadata = tbl.metadata or {} + self.object:set_properties({wield_item = self.item}) + if tbl.respawn then + entity_to_node(self.start_pos, self.object) + end + end + end, + + on_step = function(self, dtime, moveresult) + if self.dest_pos then + local obj = self.object + local pos = obj:get_pos() + local dist = vector.distance(pos, self.dest_pos) + local speed = vector.length(obj:get_velocity()) + + -- Landing + if dist < 0.05 then + obj:move_to(self.dest_pos, true) + obj:set_acceleration({x=0, y=0, z=0}) + obj:set_velocity({x=0, y=0, z=0}) + self.dest_pos = nil + if not self.handover or not handover_to(pos, self) then + minetest.after(0.5, entity_to_node, pos, obj) + end + self.ttl = 2 + return + end + + -- Braking or limit max speed + if speed > (dist * 2) or speed > self.max_speed then + local speed = math.min(speed, math.max(dist * 2, MIN_SPEED)) + local vel = vector.multiply(self.dir,speed) + obj:set_velocity(vel) + obj:set_acceleration({x=0, y=0, z=0}) + end + elseif self.ttl then + self.ttl = self.ttl - dtime + if self.ttl < 0 then + local obj = self.object + local pos = obj:get_pos() + entity_to_node(pos, obj) + end + end + end, + +}) + +------------------------------------------------------------------------------- +-- Marker / Record +------------------------------------------------------------------------------- +local MarkedNodes = {} -- t[player] = {{entity, pos},...} +local CurrentPos -- to mark punched entities +local SimpleNodes = techage.logic.SimpleNodes + +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 + return true + end + if not M(pos):contains("ta_move_block") then + return true + end + return false +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 +end + +local function table_add(tbl, offs) + if not tbl or not offs then return end + + local tbl2 = {} + for _, v in ipairs(tbl) do + tbl2[#tbl2 + 1] = vector.add(v, offs) + end + return tbl2 +end + +local function unmark_position(name, pos) + pos = vector.round(pos) + for idx,item in ipairs(MarkedNodes[name] or {}) do + if vector.equals(pos, item.pos) then + item.entity:remove() + table.remove(MarkedNodes[name], idx) + CurrentPos = pos + return + end + end +end + +local function unmark_all(name) + for _,item in ipairs(MarkedNodes[name] or {}) do + item.entity:remove() + end + MarkedNodes[name] = nil +end + +local function mark_position(name, pos) + MarkedNodes[name] = MarkedNodes[name] or {} + pos = vector.round(pos) + if not CurrentPos or not vector.equals(pos, CurrentPos) then -- entity not punched? + local entity = minetest.add_entity(pos, "techage:moveblock_marker") + if entity ~= nil then + entity:get_luaentity().player_name = name + table.insert(MarkedNodes[name], {pos = pos, entity = entity}) + end + CurrentPos = nil + return true + end + CurrentPos = nil +end + +local function get_poslist(name) + local idx = 0 + local lst = {} + for _,item in ipairs(MarkedNodes[name] or {}) do + table.insert(lst, item.pos) + idx = idx + 1 + if idx >= 16 then break end + end + return lst +end + +minetest.register_on_punchnode(function(pos, node, puncher, pointed_thing) + if puncher and puncher:is_player() then + local name = puncher:get_player_name() + + if not MarkedNodes[name] then + return + end + + mark_position(name, pointed_thing.under) + end +end) + + +minetest.register_entity(":techage:moveblock_marker", { + initial_properties = { + visual = "cube", + textures = { + "techage_cube_mark.png", + "techage_cube_mark.png", + "techage_cube_mark.png", + "techage_cube_mark.png", + "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}, + glow = 8, + }, + on_step = function(self, dtime) + self.ttl = (self.ttl or 2400) - 1 + if self.ttl <= 0 then + local pos = self.object:get_pos() + unmark_position(self.player_name, pos) + end + end, + on_punch = function(self, hitter) + local pos = self.object:get_pos() + local name = hitter:get_player_name() + if name == self.player_name then + unmark_position(name, pos) + end + end, +}) + +------------------------------------------------------------------------------- +-- TA4 Move Controller +------------------------------------------------------------------------------- +local WRENCH_MENU = { + { + type = "dropdown", + choices = "0.5,1,2,4,6,8", + name = "max_speed", + label = S("Maximum Speed"), + tooltip = S("Maximum speed for the moving block."), + default = "8", + }, + { + type = "number", + name = "handoverB", + label = S("Handover to B"), + tooltip = S("Number of the next movecontroller."), + default = "", + }, + { + type = "number", + name = "handoverA", + label = S("Handover to A"), + tooltip = S("Number of the previous movecontroller."), + default = "", + }, + { + type = "float", + name = "height", + label = S("Move block height"), + tooltip = S("Value in the range of 0.0 to 1.0"), + default = "1.0", + }, +} + +local function formspec(nvm, meta) + local status = meta:get_string("status") + local distance = meta:contains("distance") and meta:get_string("distance") or "0,3,0" + return "size[8,5]" .. + default.gui_bg .. + default.gui_bg_img .. + default.gui_slots .. + "box[0,-0.1;7.2,0.5;#c6e8ff]" .. + "label[0.2,-0.1;" .. minetest.colorize( "#000000", S("TA4 Move Controller")) .. "]" .. + 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;ready;" .. S("Done") .. "]" .. + "field[0.4,2.5;3.8,1;distance;" .. S("Move distance (A to B)") .. ";" .. distance .. "]" .. + "button[4.1,2.2;3.8,1;store;" .. S("Store") .. "]" .. + "button[0.1,3.3;3.8,1;moveAB;" .. S("Move A-B") .. "]" .. + "button[4.1,3.3;3.8,1;moveBA;" .. S("Move B-A") .. "]" .. + "label[0.3,4.3;" .. status .. "]" +end + +local function move_node(pos, pos1, pos2, max_speed, handover, height) + local meta = M(pos) + local dir = determine_dir(pos1, pos2) + local obj = node_to_entity(pos1, handover) + local self = obj:get_luaentity() + self.players = {} + self.entities = {} + + if obj then + local offs = {x=0, y=height or 1, z=0} + attach_objects(pos1, offs, obj) + if dir.y == 0 then + if (dir.x ~= 0 and dir.z == 0) or (dir.x == 0 and dir.z ~= 0) then + attach_objects(pos1, dir, obj) + end + end + move_entity(obj, pos2, dir, max_speed) + end +end + +local function move_nodes(pos, lpos1, lpos2, handover) + local meta = M(pos) + local owner = meta:get_string("owner") + local max_speed = meta:contains("max_speed") and meta:get_int("max_speed") or MAX_SPEED + local height = meta:contains("height") and meta:get_float("height") or 1 + height = techage.in_range(height, 0, 1) + + if #lpos1 == #lpos2 then + for idx = 1, #lpos1 do + local pos1 = lpos1[idx] + local pos2 = lpos2[idx] + 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, pos1, pos2, max_speed, handover, height) + 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 + end + end + else + meta:set_string("status", S("Position list error")) + return false + end + local info = techage.get_node_info(handover) + if info and info.name == "techage:ta4_movecontroller" then + local mem = techage.get_mem(info.pos) + mem.num_entities = #lpos1 + end + return true +end + +local function moveon_nodes(pos, lpos1, lpos2, handover) + local meta = M(pos) + local owner = meta:get_string("owner") + local max_speed = meta:contains("max_speed") and meta:get_int("max_speed") or MAX_SPEED + + if #lpos1 == #lpos2 then + for idx = 1, #lpos1 do + local pos1 = lpos1[idx] + local pos2 = lpos2[idx] + if not minetest.is_protected(pos1, owner) and not minetest.is_protected(pos2, owner) then + if is_valid_dest(pos2) then + local dir = determine_dir(pos1, pos2) + local obj = capture_entity(pos1) + if obj then + obj:get_luaentity().handover = handover + move_entity(obj, pos2, dir, max_speed) + end + 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 + end + end + else + meta:set_string("status", S("Position list error")) + return false + end + local info = techage.get_node_info(handover) + if info and info.name == "techage:ta4_movecontroller" then + local mem = techage.get_mem(info.pos) + mem.num_entities = #lpos1 + end + return true +end + +local function move_to_other_pos(pos) + local meta = M(pos) + local nvm = techage.get_nvm(pos) + + if nvm.pos_2to1 then + local lpos1 = nvm.lpos1 or {} + local lpos2 = nvm.lpos2 or {} + nvm.pos_2to1 = false + local handover = meta:contains("handoverA") and meta:get_string("handoverA") + return move_nodes(pos, lpos2, lpos1, handover) + else + local lpos1 = nvm.lpos1 or {} + local lpos2 = nvm.lpos2 or {} + nvm.pos_2to1 = true + local handover = meta:contains("handoverB") and meta:get_string("handoverB") + return move_nodes(pos, lpos1, lpos2, handover) + end +end + +local function takeover(pos) + local meta = M(pos) + local nvm = techage.get_nvm(pos) + local mem = techage.get_mem(pos) + mem.entities_are_there = nil + + if nvm.pos_2to1 then + local lpos1 = nvm.lpos1 or {} + local lpos2 = nvm.lpos2 or {} + nvm.pos_2to1 = false + local handover = meta:contains("handoverA") and meta:get_string("handoverA") + return moveon_nodes(pos, lpos2, lpos1, handover) + else + local lpos1 = nvm.lpos1 or {} + local lpos2 = nvm.lpos2 or {} + nvm.pos_2to1 = true + local handover = meta:contains("handoverB") and meta:get_string("handoverB") + return moveon_nodes(pos, lpos1, lpos2, handover) + end +end + +minetest.register_node("techage:ta4_movecontroller", { + description = S("TA4 Move Controller"), + tiles = { + -- up, down, right, left, back, front + "techage_filling_ta4.png^techage_frame_ta4_top.png", + "techage_filling_ta4.png^techage_frame_ta4_top.png", + "techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_movecontroller.png", + }, + + after_place_node = function(pos, placer, itemstack) + local meta = M(pos) + techage.logic.after_place_node(pos, placer, "techage:ta4_movecontroller", S("TA4 Move Controller")) + techage.logic.infotext(meta, S("TA4 Move Controller")) + local nvm = techage.get_nvm(pos) + meta:set_string("formspec", formspec(nvm, meta)) + end, + + on_receive_fields = function(pos, formname, fields, player) + if minetest.is_protected(pos, player:get_player_name()) then + return + end + + local meta = M(pos) + local nvm = techage.get_nvm(pos) + + if fields.record then + nvm.lpos1 = nil + nvm.lpos2 = nil + nvm.pos_2to1 = false + meta:set_string("status", S("Recording...")) + local name = player:get_player_name() + minetest.chat_send_player(name, S("Click on all blocks that shall be moved")) + MarkedNodes[name] = {} + meta:set_string("formspec", formspec(nvm, meta)) + elseif fields.ready then + local name = player:get_player_name() + local pos_list = get_poslist(name) + local text = #pos_list.." "..S("block positions are stored.") + meta:set_string("status", text) + meta:set_string("distance", fields.distance) + nvm.lpos1 = pos_list + nvm.lpos2 = table_add(pos_list, to_vector(fields.distance)) + nvm.pos_2to1 = false + unmark_all(name) + meta:set_string("formspec", formspec(nvm, meta)) + elseif fields.store then + local dist = to_vector(fields.distance) + local l = math.hypot(dist.x, math.hypot(dist.y, dist.z)) + if l <= 100 then + meta:set_string("distance", fields.distance) + nvm.lpos2 = table_add(nvm.lpos1, to_vector(fields.distance)) + nvm.pos_2to1 = false + else + meta:set_string("status", S("Error: Distance > 100 m !!")) + end + meta:set_string("formspec", formspec(nvm, meta)) + elseif fields.moveAB then + meta:set_string("status", "") + nvm.pos_2to1 = false + if move_to_other_pos(pos) then + meta:set_string("formspec", formspec(nvm, meta)) + local name = player:get_player_name() + MarkedNodes[name] = nil + end + elseif fields.moveBA then + meta:set_string("status", "") + nvm.pos_2to1 = true + if move_to_other_pos(pos) then + meta:set_string("formspec", formspec(nvm, meta)) + local name = player:get_player_name() + MarkedNodes[name] = nil + end + end + end, + + + after_dig_node = function(pos, oldnode, oldmetadata, digger) + local name = digger:get_player_name() + unmark_all(name) + techage.remove_node(pos, oldnode, oldmetadata) + end, + + ta4_formspec = WRENCH_MENU, + paramtype2 = "facedir", + groups = {choppy=2, cracky=2, crumbly=2}, + is_ground_content = false, + sounds = default.node_sound_wood_defaults(), +}) + +local INFO = [[Commands: 'a2b', 'b2a', 'move']] + +techage.register_node({"techage:ta4_movecontroller"}, { + on_recv_message = function(pos, src, topic, payload) + if topic == "info" then + return INFO + elseif topic == "a2b" then + local nvm = techage.get_nvm(pos) + nvm.pos_2to1 = false + return move_to_other_pos(pos) + elseif topic == "b2a" then + local nvm = techage.get_nvm(pos) + nvm.pos_2to1 = true + return move_to_other_pos(pos) + elseif topic == "move" then + return move_to_other_pos(pos) + elseif topic == "handover" then + return takeover(pos) + end + return false + end, +}) + +minetest.register_craft({ + output = "techage:ta4_movecontroller", + recipe = { + {"default:steel_ingot", "dye:blue", "default:steel_ingot"}, + {"default:mese_crystal_fragment", "techage:ta4_wlanchip", "default:mese_crystal_fragment"}, + {"group:wood", "basic_materials:gear_steel", "group:wood"}, + }, +}) + +minetest.register_on_joinplayer(function(player) + unlock_player(player) +end) + +minetest.register_on_leaveplayer(function(player) + if unlock_player(player) then + detach_player(player) + end +end) + +minetest.register_on_dieplayer(function(player) + if unlock_player(player) then + detach_player(player) + end +end) diff --git a/techage/logic/repeater.lua b/techage/logic/repeater.lua index 2617490..8de4e50 100644 --- a/techage/logic/repeater.lua +++ b/techage/logic/repeater.lua @@ -103,7 +103,9 @@ techage.register_node({"techage:ta3_repeater"}, { return false else local numbers = M(pos):get_string("numbers") or "" + techage.counting_start(M(pos):get_string("owner")) techage.send_multi(src, numbers, topic, payload) + techage.counting_stop() end end, on_node_load = function(pos) diff --git a/techage/logic/sequencer.lua b/techage/logic/sequencer.lua index 1ad89bc..2784c11 100644 --- a/techage/logic/sequencer.lua +++ b/techage/logic/sequencer.lua @@ -60,7 +60,7 @@ local function formspec_help() "label[0,1;Define a sequence of commands\nto control other machines.]".. "label[0,2.2;Numbers(s) are the node numbers,\nthe command shall sent to.]".. "label[0,3.4;The commands 'on'/'off' are used\n for machines and other nodes.]".. - "label[0,4.6;Offset is the time to the\nnext line in seconds (1..999).]".. + "label[0,4.6;Offset is the time to the\nnext line in seconds (0.2 to 999).]".. "label[0,5.8;If endless is set, the Sequencer\nrestarts again and again.]".. "label[0,7;The command ' ' does nothing,\nonly consuming the offset time.]".. "button[3,8;2,1;exit;close]" @@ -106,6 +106,7 @@ local function check_rules(pos, elapsed) nvm.running = nvm.running or false nvm.index = nvm.index or 1 nvm.endless = nvm.endless or false + techage.counting_start(M(pos):get_string("owner")) while true do -- process all rules as long as offs == 0 local rule = nvm.rules[nvm.index] local offs = tonumber(nvm.rules[nvm.index].offs or 1) @@ -119,12 +120,15 @@ local function check_rules(pos, elapsed) if offs > 0 then -- we can't restart the timer within the function om_timer minetest.after(0, restart_timer, pos, offs) + techage.counting_stop() return false end else + techage.counting_stop() return stop_the_sequencer(pos) end end + techage.counting_stop() return false end diff --git a/techage/logic/sequencer2.lua b/techage/logic/sequencer2.lua new file mode 100644 index 0000000..0b717c7 --- /dev/null +++ b/techage/logic/sequencer2.lua @@ -0,0 +1,318 @@ +--[[ + + TechAge + ======= + + Copyright (C) 2017-2021 Joachim Stolberg + + AGPL v3 + See LICENSE.txt for more information + + TA4 Sequencer + +]]-- + +-- for lazy programmers +local M = minetest.get_meta +local S = techage.S + +local logic = techage.logic + +local HELP = S("Syntax:\n") .. + S("'[] '\n") .. + S("\n") .. + S(" is a number from 1 to 50000 and is\n") .. + S("the timeslot when the command is executed.\n") .. + S(" - 1 corresponds to 100 ms\n") .. + S(" - 50000 corresponds to 4 game days\n") .. + S("\n") .. + S(" is one of the following:\n") .. + S(" - 'send ' (techage command)\n") .. + S(" - 'goto ' (jump to another line)\n") .. + S(" - 'stop' (stop the execution)\n") .. + S("\n") .. + S("Example:\n") .. + " -- move controller commands\n" .. + " [1] send 1234 a2b\n" .. + " [30] send 1234 b2a\n" .. + " [60] goto 1 -- keep going" + +local function strsplit(text) + text = text:gsub("\r\n", "\n") + text = text:gsub("\r", "\n") + return string.split(text, "\n", true) +end + +local function trim(s) + return (s:gsub("^%s*(.-)%s*$", "%1")) +end + +local function command(s) + local num, cmd, pld = unpack(string.split(s, " ", false, 2)) + if not num or not cmd then + return S("Invalid command!") + end + return {number = num, cmnd = cmd, payload = pld} +end + +local function add_error(text, line_num) + local tbl = {} + for idx, line in ipairs(strsplit(text)) do + if idx == line_num and not string.find(line, '--<<== error') then + tbl[#tbl+1] = line.." --<<== error" + else + tbl[#tbl+1] = line + end + end + return table.concat(tbl, "\n") +end + +local function exception(tRes, line, s) + if tRes then + tRes.line = line + tRes.error = s + end +end + +local function compile(s, tRes) + local tCode = {} + local old_idx = 0 + local start_idx + + for i, line in ipairs(strsplit(s)) do + line = trim(line) + line = string.split(line, "--", true, 1)[1] or "" + if line ~= "" then + local idx, cmnd1, cmnd2 = unpack(string.split(line, " ", false, 2)) + idx = tonumber(string.match(idx, "^%[(%d+)%]$")) + if not idx then + return exception(tRes, i, "Syntax error!") + end + if idx > 50000 then + return exception(tRes, i, "Order error!") + end + if idx <= old_idx then + return exception(tRes, i, "Order error!") + end + start_idx = start_idx or idx + if old_idx ~= 0 and not tCode[old_idx].next_idx then + tCode[old_idx].next_idx = idx + end + if cmnd1 == "send" then + local res = command(cmnd2) + if type(res) == "string" then + return exception(tRes, i, res) + end + tCode[idx] = res + elseif cmnd1 == "goto" then + tCode[idx] = {next_idx = tonumber(cmnd2) or 1} + elseif cmnd1 == "stop" then + tCode[idx] = false + elseif cmnd1 == nil then + tCode[idx] = {} + end + old_idx = idx + end + end + -- Returns: + -- { + -- start_idx = 1, + -- tCode = { + -- = {number = , cmnd = , payload = , next_idx = }, + -- ... + -- }, + -- } + return {start_idx=start_idx, tCode=tCode} +end + +local function check_syntax(meta) + local tRes = {} + local res = compile(meta:get_string("text"), tRes) + if not res then + meta:set_string("err_msg", tRes.error) + meta:set_string("text", add_error(meta:get_string("text"), tRes.line)) + return false + else + meta:set_string("err_msg", "") + return true + end +end + +local function formspec(nvm, meta) + local text = meta:get_string("text") + text = minetest.formspec_escape(text) + local bttn = nvm.running and ("stop;" .. S("Stop")) or ("start;" .. S("Start")) + local style = nvm.running and "style_type[textarea;font=mono;textcolor=#888888;border=false]" or + "style_type[textarea;font=mono;textcolor=#FFFFFF;border=false]" + local textarea = nvm.running and "textarea[0.3,0.2;10,8.3;;;"..text.."]" or + "textarea[0.3,0.2;10,8.3;text;;"..text.."]" + + return "size[10,8]" .. + style .. + "tabheader[0,0;tab;edit,help;1;;true]" .. + "label[0.1,-0.2;" .. S("Commands") .. ":]" .. + textarea .. + "background[0.1,0.3;9.8,7.0;techage_form_mask.png]" .. + "label[0.1,7.5;" .. meta:get_string("err_msg") .. "]" .. + "button_exit[3.4,7.5;2.2,1;cancel;" .. S("Cancel") .. "]" .. + "button[5.6,7.5;2.2,1;save;" .. S("Save") .. "]" .. + "button[7.8,7.5;2.2,1;" .. bttn .. "]" +end + +local function formspec_help(meta) + local text = "" --minetest.formspec_escape("hepl") + return "size[10,8]".. + "style_type[textarea;font=mono;textcolor=#FFFFFF;border=false]".. + "tabheader[0,0;tab;edit,help;2;;true]".. + "textarea[0.3,0.3;10,9;;" .. S("Help") .. ":;"..minetest.formspec_escape(HELP).."]" .. + "background[0.1,0.3;9.8,8.0;techage_form_mask.png]" +end + +local function restart_timer(pos, time) + local timer = minetest.get_node_timer(pos) + if timer:is_started() then + timer:stop() + end + timer:start(time / 10) +end + +local function node_timer(pos, elapsed) + local nvm = techage.get_nvm(pos) + if nvm.running then + local mem = techage.get_mem(pos) + mem.code = mem.code or compile(M(pos):get_string("text")) + if mem.code then + mem.idx = mem.idx or mem.code.start_idx + local code = mem.code.tCode[mem.idx] + if code and code.cmnd then + local src = M(pos):get_string("node_number") + techage.counting_start(M(pos):get_string("owner")) + techage.send_single(src, code.number, code.cmnd, code.payload) + techage.counting_stop() + end + if code and code.next_idx then + local offs = code.next_idx - mem.idx + minetest.after(0, restart_timer, pos, math.max(offs, 1)) + mem.idx = code.next_idx + else + nvm.running = false + local meta = M(pos) + meta:set_string("formspec", formspec(nvm, meta)) + logic.infotext(meta, S("TA4 Sequencer"), S("stopped")) + end + end + end + return false +end + +local function on_receive_fields(pos, formname, fields, player) + if minetest.is_protected(pos, player:get_player_name()) then + return + end + + local meta = M(pos) + local nvm = techage.get_nvm(pos) + local mem = techage.get_mem(pos) + nvm.running = nvm.running or false + + print(1, dump(fields)) + if fields.stop then + nvm.running = false + minetest.get_node_timer(pos):stop() + logic.infotext(meta, S("TA4 Sequencer"), S("stopped")) + elseif not nvm.running then + print(2) + if fields.tab == "2" then + print(3) + meta:set_string("formspec", formspec_help(meta)) + return + elseif fields.tab == "1" then + meta:set_string("formspec", formspec(nvm, meta)) + return + end + + if fields.save then + nvm.running = false + meta:set_string("text", fields.text or "") + mem.code = nil + mem.idx = nil + elseif fields.start then + if check_syntax(meta) then + nvm.running = true + meta:set_string("text", fields.text or "") + mem.code = nil + mem.idx = nil + minetest.get_node_timer(pos):start(0.5) + logic.infotext(meta, S("TA4 Sequencer"), S("running")) + end + end + end + meta:set_string("formspec", formspec(nvm, meta)) +end + +minetest.register_node("techage:ta4_sequencer", { + description = S("TA4 Sequencer"), + tiles = { + -- up, down, right, left, back, front + "techage_filling_ta4.png^techage_frame_ta4_top.png", + "techage_filling_ta4.png^techage_frame_ta4_top.png", + "techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_sequencer.png", + }, + + after_place_node = function(pos, placer) + local meta = M(pos) + local nvm = techage.get_nvm(pos) + logic.after_place_node(pos, placer, "techage:ta4_sequencer", S("TA4 Sequencer")) + logic.infotext(meta, S("TA4 Sequencer"), S("stopped")) + nvm.running = false + meta:set_string("formspec", formspec(nvm, meta)) + end, + + on_receive_fields = on_receive_fields, + + after_dig_node = function(pos, oldnode, oldmetadata) + techage.remove_node(pos, oldnode, oldmetadata) + techage.del_mem(pos) + end, + + on_timer = node_timer, + + paramtype2 = "facedir", + groups = {choppy=2, cracky=2, crumbly=2}, + is_ground_content = false, + sounds = default.node_sound_stone_defaults(), +}) + + +minetest.register_craft({ + output = "techage:ta4_sequencer", + recipe = { + {"default:steel_ingot", "dye:blue", "default:steel_ingot"}, + {"techage:ta4_ramchip", "default:mese_crystal", "techage:ta4_wlanchip"}, + {"techage:aluminum", "group:wood", "techage:aluminum"}, + }, +}) + +local INFO = [[Commands: 'goto ', 'stop']] + +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 + 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 + nvm.running = false + minetest.get_node_timer(pos):stop() + logic.infotext(M(pos), S("TA4 Sequencer"), S("stopped")) + elseif topic == "info" then + return INFO + else + return "unsupported" + end + end, +}) + diff --git a/techage/logic/terminal.lua b/techage/logic/terminal.lua index 212356c..7bf483f 100644 --- a/techage/logic/terminal.lua +++ b/techage/logic/terminal.lua @@ -201,6 +201,7 @@ local function register_terminal(num, tiles, node_box, selection_box) meta:set_string("command", S("commands like: help")) meta:set_string("formspec", formspec2(meta)) meta:set_string("owner", placer:get_player_name()) + meta:set_string("infotext", S("TA3 Terminal") .. " " .. number) end, on_receive_fields = function(pos, formname, fields, player) diff --git a/techage/lua_controller/controller.lua b/techage/lua_controller/controller.lua index 6c6cd43..6857b1e 100644 --- a/techage/lua_controller/controller.lua +++ b/techage/lua_controller/controller.lua @@ -403,7 +403,8 @@ local function call_loop(pos, meta, elapsed) local code = Cache[number].code local res = safer_lua.run_loop(pos, elapsed, code, error) if res then - t = minetest.get_us_time() - t + -- Don't count thread changes + t = math.min(minetest.get_us_time() - t, 1000) cpu = math.floor(((cpu * 20) + t) / 21) meta:set_int("cpu", cpu) meta:set_string("infotext", "Controller "..number..": running ("..cpu.."us)") diff --git a/techage/manuals/manual_ta3_DE.md b/techage/manuals/manual_ta3_DE.md index a02fca6..1f49a38 100644 --- a/techage/manuals/manual_ta3_DE.md +++ b/techage/manuals/manual_ta3_DE.md @@ -695,6 +695,7 @@ Detektoren scannen ihre Umgebung ab und senden ein `on`-Kommando, wenn das Gesuc Der Detektor ist eine spezieller Röhrenblock, der erkennt, wenn Items über die Röhre weitergegeben werden. Es muss dazu auf beiden Seiten mit der Röhre verbunden sein. Werden Items mit einem Schieber in den Detektor geschoben, gibt er diese automatisch weiter. Er sendet ein `on`, wenn ein Item erkannt wird, gefolgt von einem `off` eine Sekunde später. Danach werden weitere Kommando für 8 Sekunden blockiert. +Die Wartezeit, sowie die Items, die ein Kommando auslösen sollen, können über das Gabelschlüssel-Menü konfiguriert werden. [ta3_detector|image] diff --git a/techage/manuals/manual_ta3_EN.md b/techage/manuals/manual_ta3_EN.md index 3f96e33..983fa7b 100644 --- a/techage/manuals/manual_ta3_EN.md +++ b/techage/manuals/manual_ta3_EN.md @@ -690,6 +690,7 @@ Detectors scan their surroundings and send an `on` command when the search is re The detector is a special tube block that detects when items are passed on through the tube. To do this, it must be connected to tubes on both sides. If items are pushed into the detector with a pusher, they are automatically passed on. It sends an `on` when an item is recognized, followed by an `off` a second later. Then further commands are blocked for 8 seconds. +The waiting time and the items that should trigger a command can be configured using the open-ended wrench menu. [ta3_detector|image] @@ -810,7 +811,7 @@ The processing power is up to 8 times one item every 4 seconds. ### Techage Info Tool -The Techage Info Tool (wrench) has several functions. It shows the time, position, temperature and biome when an unknown block is clicked on. +The Techage Info Tool (open-ended wrench) has several functions. It shows the time, position, temperature and biome when an unknown block is clicked on. If you click on a TechAge block with command interface, all available data will be shown (see also "Logic / switching blocks"). With Shift + right click an extended menu can be opened for some blocks. Depending on the block, further data can be called up or special settings can be made here. In the case of a generator, for example, the charging curve/switch-off can be programmed. diff --git a/techage/manuals/manual_ta4_DE.md b/techage/manuals/manual_ta4_DE.md index 5294279..6ee4f31 100644 --- a/techage/manuals/manual_ta4_DE.md +++ b/techage/manuals/manual_ta4_DE.md @@ -470,6 +470,12 @@ Beim TA4 Taster/Schalter hat sich nur das Aussehen geändert. Die Funktionalitä [ta4_button|image] +### TA4 4x Taster / 4x Button + +Dieser Block hat vier Taster, die über das Schraubenschlüssel-Menü individuell konfiguriert werden können. Für jeden Taster kann die Beschriftung und die Zielblockadresse konfiguriert werden. Zusätzlich kann für jeden Taster das Kommando konfiguriert werden, welches gesendet werden soll. + +[ta4_button_4x|image] + ### TA4 Spieler Detektor / Player Detector Beim TA4 Spieler Detektor hat sich nur das Aussehen geändert. Die Funktionalität ist gleich wie beim TA3 Spieler Detektor. @@ -489,6 +495,60 @@ Diesen Zähler kann man über das Kommando 'count' abfragen und über 'reset' zu [ta4_detector|image] +### TA4 Move Controller + +Der TA4 Move Controller ist ähnlich zum "Door Controller 2", aber die ausgewählten Blöcke werden nicht entfernt, sondern können bewegt werden. +Da die bewegten Blöcke Spieler und Mobs mitnehmen können, die auf dem Block stehen, können damit Fahrstühle und ähnliche Transportsysteme gebaut werden. + +Anleitung: + +- Controller setzen und die Blöcke, die bewegt werden sollen, über das Menü an-trainieren (Es können bis zu 16 Blöcke an-trainiert werden) +- die "Flugstrecke" muss über eine x,y,z Angabe (relativ) eingegeben werden (die maximale Distanz beträgt 100 m) +- mit den Menü-Tasten "Bewege A-B" sowie "Bewege B-A" kann die Bewegung getestet werden +- man kann auch durch Wände oder andere Blöcke fliegen +- auch die Zielposition für die Blöcke kann belegt sein. Die Blöcke werden in diesem Falle "unsichtbar" gespeichert. Dies ist für Schiebetüren und ähnliches gedacht +- Über das Gabelschlüssel-Menü kann im Controller auch ein "handover" programmiert werden. Durch Eingabe einer Blocknummer werden die Blöcke dann an den nächsten Move Controller übergeben. So lassen sich auch zusammenhängende Bewegungen über mehrere Move Controller realisieren. + +Der Move Controller unterstützt folgende techage Kommandos: + +- `a2b` Bewege Block von A nach B +- `b2a` Bewege Block von B nach A +- `move` Bewege Block auf die andere Seite + +[ta4_movecontroller|image] + + +### TA4 Sequenzer + +über den TA4 Sequenzer können ganze Abläufe programmiert werden. Hier ein Beispiel: + +``` +-- this is a comment +[1] send 1234 a2b +[30] send 1234 b2a +[60] goto 1 +``` + +- Jede Zeile beginnt mit einem Nummer, welche einem Zeitpunkt entspricht `[]` +- Für Zeitpunkte sind Werte von 1 bis 50000 zulässig +- 1 entspricht 100 ms, 50000 entspricht in etwa 4 Spieltagen +- Leerzeilen oder Kommentare sind erlaubt (`-- comment`) +- Mit `send ` kann man ein Kommando an einen Block senden +- Mit `goto ` kann man an eine andere Zeile/Zeitpunkt springen +- Mit `stop` kann man den Sequenzer verzögert stoppen, so dass er kein neues Kommando + von einem Taster oder anderem Block annimmt (um eine Bewegung abzuschließen) + Ohne `stop` geht der Sequenzer sofort nach dem letzten Kommando in den stopped Modus. + +Der TA4 Sequenzer unterstützt folgende techage Kommandos: + +- `goto ` Zu einer Kommandozeile springen und damit den Sequenzer starten +- `stop` Den Sequenzer anhalten + +Das `goto` Kommando wird nur angenommen, wenn der Sequenzer gestoppt ist. + +[ta4_sequencer|image] + + ## TA4 Lampen diff --git a/techage/manuals/manual_ta4_EN.md b/techage/manuals/manual_ta4_EN.md index 6f5698d..388cd30 100644 --- a/techage/manuals/manual_ta4_EN.md +++ b/techage/manuals/manual_ta4_EN.md @@ -463,6 +463,12 @@ Only the appearance of the TA4 button/switch has changed. The functionality is t [ta4_button|image] +### TA4 4x Button + +This block has four buttons that can be individually configured using the wrench menu. The labeling and the target block address can be configured for each button. In addition, the command that is to be sent can be configured for each button. + +[ta4_button_4x|image] + ### TA4 Player Detector Only the appearance of the TA4 player detector has changed. The functionality is the same as with the TA3 player detector. @@ -482,6 +488,60 @@ This counter can be queried with the 'count' command and reset with 'reset'. [ta4_detector|image] +### TA4 Move Controller + +The TA4 Move Controller is similar to "Door Controller 2", but the selected blocks are not removed, but can be moved. +Since the moving blocks can take players and mobs standing on the block with them, elevators and similar transport systems can be built with them. + +Instructions: + +- Set the controller and train the blocks to be moved via the menu (up to 16 blocks can be trained) +- the "flight route" must be entered via an x, y, z specification (relative) (the maximum distance is 100 m) +- The movement can be tested with the menu buttons "Move A-B" and "Move B-A" +- you can also fly through walls or other blocks +- The target position for the blocks can also be occupied. In this case, the blocks are saved "invisibly". This is intended for sliding doors and the like +- A "handover" can also be programmed in the controller via the open-ended wrench menu. By entering a block number, the blocks are then transferred to the next move controller. In this way, connected movements can also be implemented using several Move Controllers. + +The Move Controller supports the following techage commands: + +- `a2b` Move block from A to B. +- `b2a` Move block from B to A. +- `move` Move block to the other side + +[ta4_movecontroller|image] + +### TA4 Sequencer + +Entire processes can be programmed using the TA4 sequencer. Here's an example: + +``` +-- this is a comment +[1] send 1234 a2b +[30] send 1234 b2a +[60] goto 1 +``` + +- Each line begins with a number which corresponds to a point in time `[]` +- Values from 1 to 50000 are permitted for times +- 1 corresponds to 100 ms, 50000 corresponds to about 4 game days +- Empty lines or comments are allowed (`-- comment`) +- With `send ` you can send a command to a block +- With `goto ` you can jump to another line / point in time +- With `stop` you can stop the sequencer with a delay so that it does not receive a new command + accepts from a button or other block (to complete a movement) + Without `stop`, the sequencer goes into stopped mode immediately after the last command. + +The TA4 sequencer supports the following techage commands: + +- `goto ` Jump to a command line and start the sequencer +- `stop` Stop the sequencer + +The `goto` command is only accepted when the sequencer is stopped. + +[ta4_sequencer|image] + + + ## TA4 Lamps diff --git a/techage/manuals/toc_DE.md b/techage/manuals/toc_DE.md index 6f95b60..2f0702c 100644 --- a/techage/manuals/toc_DE.md +++ b/techage/manuals/toc_DE.md @@ -182,9 +182,12 @@ - [TA4 Lua Controller Terminal](./manual_ta4_DE.md#ta4-lua-controller-terminal) - [TA4 Logik-/Schalt-Module](./manual_ta4_DE.md#ta4-logik-schalt-module) - [TA4 Taster/Schalter / Button/Switch](./manual_ta4_DE.md#ta4-tasterschalter--buttonswitch) + - [TA4 4x Taster / 4x Button](./manual_ta4_DE.md#ta4-4x-taster--4x-button) - [TA4 Spieler Detektor / Player Detector](./manual_ta4_DE.md#ta4-spieler-detektor--player-detector) - [TA4 Zustandssammler / State Collector](./manual_ta4_DE.md#ta4-zustandssammler--state-collector) - [TA4 Detektor / Detector](./manual_ta4_DE.md#ta4-detektor--detector) + - [TA4 Move Controller](./manual_ta4_DE.md#ta4-move-controller) + - [TA4 Sequenzer](./manual_ta4_DE.md#ta4-sequenzer) - [TA4 Lampen](./manual_ta4_DE.md#ta4-lampen) - [TA4 LED Pflanzenlampe / TA4 LED Grow Light](./manual_ta4_DE.md#ta4-led-pflanzenlampe--ta4-led-grow-light) - [TA4 LED Straßenlampe / TA4 LED Street Lamp](./manual_ta4_DE.md#ta4-led-straßenlampe--ta4-led-street-lamp) diff --git a/techage/manuals/toc_EN.md b/techage/manuals/toc_EN.md index 6c27745..be1c999 100644 --- a/techage/manuals/toc_EN.md +++ b/techage/manuals/toc_EN.md @@ -182,9 +182,12 @@ - [TA4 Lua Controller Terminal](./manual_ta4_EN.md#ta4-lua-controller-terminal) - [TA4 Logic/Switching Modules](./manual_ta4_EN.md#ta4-logicswitching-modules) - [TA4 Button/Switch](./manual_ta4_EN.md#ta4-buttonswitch) + - [TA4 4x Button](./manual_ta4_EN.md#ta4-4x-button) - [TA4 Player Detector](./manual_ta4_EN.md#ta4-player-detector) - [TA4 State Collector](./manual_ta4_EN.md#ta4-state-collector) - [TA4 Detector](./manual_ta4_EN.md#ta4-detector) + - [TA4 Move Controller](./manual_ta4_EN.md#ta4-move-controller) + - [TA4 Sequencer](./manual_ta4_EN.md#ta4-sequencer) - [TA4 Lamps](./manual_ta4_EN.md#ta4-lamps) - [TA4 LED Grow Light](./manual_ta4_EN.md#ta4-led-grow-light) - [TA4 Street Lamp](./manual_ta4_EN.md#ta4-street-lamp) diff --git a/techage/oil/explore.lua b/techage/oil/explore.lua index c7f6e2c..afddfca 100644 --- a/techage/oil/explore.lua +++ b/techage/oil/explore.lua @@ -253,6 +253,12 @@ minetest.register_node("techage:oilexplorer", { end, after_dig_node = function(pos, oldnode, oldmetadata, digger) techage.unmark_region(digger:get_player_name()) + local xpos = (math.floor(pos.x / 16) * 16) + local ypos = (math.floor(pos.y / 16) * 16) + local zpos = (math.floor(pos.z / 16) * 16) + local pos1 = {x=xpos, y=ypos, z=zpos} + local pos2 = {x=xpos+15, y=ypos+15, z=zpos+15} + techage.mark_region(digger:get_player_name(), pos1, pos2) end, is_ground_content = false, groups = {snappy=2,cracky=2,oddly_breakable_by_hand=2}, diff --git a/techage/power/electric_cable.lua b/techage/power/electric_cable.lua index 05cccb5..7840982 100644 --- a/techage/power/electric_cable.lua +++ b/techage/power/electric_cable.lua @@ -178,7 +178,7 @@ minetest.register_craft({ }) techage.ElectricCable = Cable -techage.ELE1_MAX_CABLE_LENGTH = ELE1_MAX_CABLE_LENGTH +techage.ELE1_MAX_CABLE_LENGTH = ELE1_MAX_CABLE_LENGHT for idx, color in ipairs({ "white", "grey", "black", "brown", "yellow", "red", "dark_green", "blue" }) do diff --git a/techage/power/formspecs.lua b/techage/power/formspecs.lua index 81fb87b..c413c00 100644 --- a/techage/power/formspecs.lua +++ b/techage/power/formspecs.lua @@ -165,6 +165,11 @@ end ------------------------------------------------------------------------------- -- API formspec functions ------------------------------------------------------------------------------- +function techage.wrench_image(x, y) + return "image["..x.."," .. y .. ";0.5,0.5;techage_inv_wrench.png]" .. + "tooltip["..x.."," .. y .. ";0.5,0.5;" .. S("Block has a wrench menu") .. ";#0C3D32;#FFFFFF]" +end + function techage.storage_formspec(self, pos, nvm, label, netw_data, curr_load, max_load) return "size[6.3,4]" .. default.gui_bg .. diff --git a/techage/settingtypes.txt b/techage/settingtypes.txt index aaeab97..ac0117b 100644 --- a/techage/settingtypes.txt +++ b/techage/settingtypes.txt @@ -26,3 +26,7 @@ techage_use_marshal (use lua-marshal as serialize/deserialize functions) bool fa # Use the external library 'lsqlite3' for for faster storing of data. # See also 'README.md'. techage_use_sqlite (use sqlite database) bool false + +# To reduce the server CPU load, the number of sent techage commands +# per player and minute can be limited. +techage_command_limit (Max. number of commands sent per minute) int 1200 \ No newline at end of file diff --git a/techage/ta3_power/akkubox.lua b/techage/ta3_power/akkubox.lua index debf025..0b3bb40 100644 --- a/techage/ta3_power/akkubox.lua +++ b/techage/ta3_power/akkubox.lua @@ -130,6 +130,7 @@ end local function after_dig_node(pos, oldnode, oldmetadata, digger) local outdir = tonumber(oldmetadata.fields.outdir or 0) Cable:after_dig_node(pos, {outdir}) + techage.remove_node(pos, oldnode, oldmetadata) techage.del_mem(pos) end diff --git a/techage/textures/techage_appl_movecontroller.png b/techage/textures/techage_appl_movecontroller.png new file mode 100644 index 0000000..4938ab1 Binary files /dev/null and b/techage/textures/techage_appl_movecontroller.png differ diff --git a/techage/textures/techage_inv_wrench.png b/techage/textures/techage_inv_wrench.png new file mode 100644 index 0000000..f95cc55 Binary files /dev/null and b/techage/textures/techage_inv_wrench.png differ diff --git a/techage/textures/techage_smartline_button_4x.png b/techage/textures/techage_smartline_button_4x.png new file mode 100644 index 0000000..5bc5286 Binary files /dev/null and b/techage/textures/techage_smartline_button_4x.png differ diff --git a/techage/textures/techage_smartline_button_4x_on1.png b/techage/textures/techage_smartline_button_4x_on1.png new file mode 100644 index 0000000..95d27e3 Binary files /dev/null and b/techage/textures/techage_smartline_button_4x_on1.png differ diff --git a/techage/textures/techage_smartline_button_4x_on2.png b/techage/textures/techage_smartline_button_4x_on2.png new file mode 100644 index 0000000..34cad03 Binary files /dev/null and b/techage/textures/techage_smartline_button_4x_on2.png differ diff --git a/techage/textures/techage_smartline_button_4x_on3.png b/techage/textures/techage_smartline_button_4x_on3.png new file mode 100644 index 0000000..e587ed6 Binary files /dev/null and b/techage/textures/techage_smartline_button_4x_on3.png differ diff --git a/techage/textures/techage_smartline_button_4x_on4.png b/techage/textures/techage_smartline_button_4x_on4.png new file mode 100644 index 0000000..1f6c6c2 Binary files /dev/null and b/techage/textures/techage_smartline_button_4x_on4.png differ diff --git a/techage/tools/repairkit.lua b/techage/tools/repairkit.lua index 9a5d2bb..5ea2092 100644 --- a/techage/tools/repairkit.lua +++ b/techage/tools/repairkit.lua @@ -76,7 +76,7 @@ local function read_state(itemstack, user, pointed_thing) if ndef and ndef.description then local info = techage.send_single("0", number, "info", nil) if info and info ~= "" and info ~= "unsupported" then - info = dump(info) + info = tostring(info) minetest.chat_send_player(user:get_player_name(), ndef.description.." "..number..":\n"..info.." ") end local state = techage.send_single("0", number, "state", nil) @@ -136,6 +136,16 @@ end local context = {} local function settings_menu(pos, playername) + if minetest.is_protected(pos, playername) then + return + end + -- Check node settings in addition + local access = M(pos):get_string("access") + local owner = M(pos):get_string("owner") + if access == "private" and playername ~= owner then + return + end + local number = techage.get_node_number(pos) local node = minetest.get_node(pos) local ndef = minetest.registered_nodes[node.name] @@ -143,15 +153,16 @@ local function settings_menu(pos, playername) context[playername] = pos if form_def then - minetest.show_formspec(playername, "techage:ta_formspec", menu.generate_formspec(pos, ndef, form_def)) + minetest.show_formspec(playername, "techage:ta_formspec", + menu.generate_formspec(pos, ndef, form_def, playername)) end end minetest.register_on_player_receive_fields(function(player, formname, fields) - if formname ~= "techage:ta_formspec" then - return false - end - + if formname ~= "techage:ta_formspec" then + return false + end + local playername = player:get_player_name() local pos = context[playername] if pos then @@ -162,11 +173,15 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) local form_def = ndef and (ndef.ta3_formspec or ndef.ta4_formspec) if form_def then - if menu.eval_input(pos, ndef, form_def, fields) then + if menu.eval_input(pos, form_def, fields, playername) then --context[playername] = pos minetest.after(0.2, function() - minetest.show_formspec(playername, "techage:ta_formspec", menu.generate_formspec(pos, ndef, form_def)) + minetest.show_formspec(playername, "techage:ta_formspec", + menu.generate_formspec(pos, ndef, form_def, playername)) end) + if ndef.ta_after_formspec then + ndef.ta_after_formspec(pos, fields, playername) + end end end end diff --git a/techage/tools/submenu.lua b/techage/tools/submenu.lua index 1e273f6..a06ad7d 100644 --- a/techage/tools/submenu.lua +++ b/techage/tools/submenu.lua @@ -22,10 +22,25 @@ local function index(list, x) return nil end +local function allow_put(inv, listname, index, stack, player) + local list = inv:get_list(listname) + stack:set_count(1) + inv:set_stack(listname, index, stack) + return 0 +end + +local function allow_take(inv, listname, index, stack, player) + local list = inv:get_list(listname) + stack:set_count(0) + inv:set_stack(listname, index, stack) + return 0 +end + -- generate the formspec string to be placed into a container frame -local function generate_formspec_substring(pos, meta, form_def) +local function generate_formspec_substring(pos, meta, form_def, player_name) local tbl = {} + local player_inv_needed = false if meta and form_def then local nvm = techage.get_nvm(pos) @@ -97,6 +112,9 @@ local function generate_formspec_substring(pos, meta, form_def) local idx = index(l, val) or 1 tbl[#tbl+1] = "dropdown[4.72," .. (offs) .. ";5.5,1.4;" .. elem.name .. ";" .. elem.choices .. ";" .. idx .. "]" end + elseif elem.type == "items" then + tbl[#tbl+1] = "list[detached:" .. minetest.formspec_escape(player_name) .. "_techage_wrench_menu;cfg;4.75," .. offs .. ";" .. elem.size .. ",1;]" + player_inv_needed = true end end if nvm.running or techage.is_running(nvm) then @@ -104,17 +122,18 @@ local function generate_formspec_substring(pos, meta, form_def) tbl[#tbl+1] = "label[0," .. offs .. ";" .. S("Note: You can't change any values while the block is running!") .. "]" end end - return table.concat(tbl, "") + + return player_inv_needed, table.concat(tbl, "") end local function value_check(elem, value) if elem.check then return elem.check(value) end - return true + return value ~= nil end -local function evaluate_data(pos, meta, form_def, fields) +local function evaluate_data(pos, meta, form_def, fields, player_name) local res = true if meta and form_def then @@ -125,7 +144,9 @@ local function evaluate_data(pos, meta, form_def, fields) for idx,elem in ipairs(form_def) do if elem.type == "number" then if fields[elem.name] then - if fields[elem.name]:find("^[%d ]+$") then + if fields[elem.name] == "" then + meta:set_string(elem.name, "") + elseif fields[elem.name]:find("^[%d ]+$") then local val = tonumber(fields[elem.name]) if value_check(elem, val) then meta:set_int(elem.name, val) @@ -139,14 +160,18 @@ local function evaluate_data(pos, meta, form_def, fields) end elseif elem.type == "numbers" then if fields[elem.name] then - if fields[elem.name]:find("^[%d ]+$") and value_check(elem, fields[elem.name]) then + if fields[elem.name] == "" then + meta:set_string(elem.name, "") + elseif fields[elem.name]:find("^[%d ]+$") and value_check(elem, fields[elem.name]) then meta:set_string(elem.name, fields[elem.name]) else res = false end end elseif elem.type == "float" then - if fields[elem.name] then + if fields[elem.name] == ""then + meta:set_string(elem.name, "") + elseif fields[elem.name] then local val = tonumber(fields[elem.name]) if val and value_check(elem, val) then meta:set_string(elem.name, val) @@ -155,7 +180,9 @@ local function evaluate_data(pos, meta, form_def, fields) end end elseif elem.type == "ascii" then - if fields[elem.name] then + if fields[elem.name] == ""then + meta:set_string(elem.name, "") + elseif fields[elem.name] then if value_check(elem, fields[elem.name]) then meta:set_string(elem.name, fields[elem.name]) else @@ -166,46 +193,95 @@ local function evaluate_data(pos, meta, form_def, fields) if fields[elem.name] ~= nil then meta:set_string(elem.name, fields[elem.name]) end + elseif elem.type == "items" then + local inv_name = minetest.formspec_escape(player_name) .. "_techage_wrench_menu" + local dinv = minetest.get_inventory({type = "detached", name = inv_name}) + local ninv = minetest.get_inventory({type = "node", pos = pos}) + if dinv and ninv then + for i = 1, ninv:get_size("cfg") do + ninv:set_stack("cfg", i, dinv:get_stack("cfg", i)) + end + end end end end return res end -function menu.generate_formspec(pos, ndef, form_def) +function menu.generate_formspec(pos, ndef, form_def, player_name) local meta = minetest.get_meta(pos) local number = techage.get_node_number(pos) local mem = techage.get_mem(pos) mem.star = ((mem.star or 0) + 1) % 2 local star = mem.star == 1 and "*" or "" + local inv_name = minetest.formspec_escape(player_name) .. "_techage_wrench_menu" + minetest.create_detached_inventory(inv_name, { + allow_put = allow_put, + allow_take = allow_take}) + local dinv = minetest.get_inventory({type = "detached", name = inv_name}) + local ninv = minetest.get_inventory({type = "node", pos = pos}) + if dinv and ninv then + dinv:set_size('cfg', ninv:get_size("cfg")) + for i = 1, ninv:get_size("cfg") do + dinv:set_stack("cfg", i, ninv:get_stack("cfg", i)) + end + end if meta and number and ndef and form_def then local title = ndef.description .. " (" .. number .. ")" - - return "size[10,9]" .. - default.gui_bg .. - default.gui_bg_img .. - default.gui_slots .. - "box[0,-0.1;9.8,0.5;#c6e8ff]" .. - "label[0.2,-0.1;" .. minetest.colorize( "#000000", title) .. "]" .. - "label[9.5,-0.1;" .. minetest.colorize( "#000000", star) .. "]" .. - "container[0,1]" .. - generate_formspec_substring(pos, meta, form_def) .. - "container_end[]" .. - "button[0.5,8.4;3,1;refresh;" .. S("Refresh") .. "]" .. - "button_exit[3.5,8.4;3,1;cancel;" .. S("Cancel") .. "]" .. - "button[6.5,8.4;3,1;save;" .. S("Save") .. "]" + local player_inv_needed, text = generate_formspec_substring(pos, meta, form_def, player_name) + local buttons + + if player_inv_needed then + buttons = "button[0.5,6.2;3,1;refresh;" .. S("Refresh") .. "]" .. + "button_exit[3.5,6.2;3,1;cancel;" .. S("Cancel") .. "]" .. + "button[6.5,6.2;3,1;save;" .. S("Save") .. "]" .. + "list[current_player;main;1,7.2;8,2;]" + else + buttons = "button[0.5,8.4;3,1;refresh;" .. S("Refresh") .. "]" .. + "button_exit[3.5,8.4;3,1;cancel;" .. S("Cancel") .. "]" .. + "button[6.5,8.4;3,1;save;" .. S("Save") .. "]" + end + + if #form_def > 8 then + local size = (#form_def * 10) - 60 + return "size[10,9]" .. + default.gui_bg .. + default.gui_bg_img .. + default.gui_slots .. + "box[0,-0.1;9.8,0.5;#c6e8ff]" .. + "label[0.2,-0.1;" .. minetest.colorize( "#000000", title) .. "]" .. + "label[9.5,-0.1;" .. minetest.colorize( "#000000", star) .. "]" .. + "scrollbaroptions[max=" .. size .. "]" .. + "scrollbar[9.4,0.6;0.4,7.7;vertical;wrenchmenu;]" .. + "scroll_container[0,1;12,9;wrenchmenu;vertical;]" .. + text .. + "scroll_container_end[]" .. + buttons + else + return "size[10,9]" .. + default.gui_bg .. + default.gui_bg_img .. + default.gui_slots .. + "box[0,-0.1;9.8,0.5;#c6e8ff]" .. + "label[0.2,-0.1;" .. minetest.colorize( "#000000", title) .. "]" .. + "label[9.5,-0.1;" .. minetest.colorize( "#000000", star) .. "]" .. + "container[0,1]" .. + text .. + "container_end[]" .. + buttons + end end return "" end -function menu.eval_input(pos, ndef, form_def, fields) +function menu.eval_input(pos, form_def, fields, player_name) --print(dump(fields)) if fields.save then local meta = minetest.get_meta(pos) - evaluate_data(pos, meta, form_def, fields) + evaluate_data(pos, meta, form_def, fields, player_name) end return fields.refresh or fields.save end -return menu \ No newline at end of file +return menu