diff --git a/hyperloop/elevator.lua b/hyperloop/elevator.lua index e1985f1..bf13343 100644 --- a/hyperloop/elevator.lua +++ b/hyperloop/elevator.lua @@ -323,6 +323,11 @@ local function door_command(floor_pos, facedir, cmnd, sound) -- one step up local door_pos1 = hyperloop.new_pos(floor_pos, facedir, "1B", 0) local door_pos2 = hyperloop.new_pos(floor_pos, facedir, "1B", 1) + local meta = M(floor_pos) + local owner = meta:contains("owner") and meta:get_string("owner") + if owner and (minetest.is_protected(door_pos1, owner) or minetest.is_protected(door_pos2, owner)) then + return + end local node1 = minetest.get_node(door_pos1) local node2 = minetest.get_node(door_pos2) @@ -455,6 +460,7 @@ minetest.register_node("hyperloop:elevator_bottom", { "field[0.5,1.5;5,1;floor;"..S("Floor name")..";"..S("Base").."]" .. "button_exit[2,3;2,1;exit;"..S("Save").."]" meta:set_string("formspec", formspec) + meta:set_string("owner", placer:get_player_name()) -- add upper part of the car pos = Shaft:get_pos(pos, 6) diff --git a/networks/networks.lua b/networks/networks.lua index 1b44459..077a34c 100644 --- a/networks/networks.lua +++ b/networks/networks.lua @@ -266,7 +266,7 @@ local function collect_network_nodes(pos, tlib2, outdir) -- outdir corresponds to the indir coming from connection_walk(pos, outdir, Flip[outdir], node, tlib2, function(pos, indir, node) local ndef = net_def2(pos, node.name, netw_type) - if ndef then + if ndef and ndef.ntype then local ntype = ndef.ntype if not netw[ntype] then netw[ntype] = {} end netw[ntype][#netw[ntype] + 1] = {pos = pos, indir = indir} diff --git a/safer_lua/environ.lua b/safer_lua/environ.lua index 09edbb6..b367d62 100644 --- a/safer_lua/environ.lua +++ b/safer_lua/environ.lua @@ -14,7 +14,7 @@ safer_lua.MaxCodeSize = 5000 -- size if source code in bytes safer_lua.MaxTableSize = 1000 -- sum over all table sizes -safer_lua.MaxExeTime = 20000 -- max. execution time in us +safer_lua.MaxExeTime = 20000 -- max. execution time in us local function memsize() return safer_lua.MaxTableSize @@ -102,7 +102,7 @@ local function format_error_str(str, label) if s:find("function 'xpcall'") then break elseif s:find(".-%.lua:%d+:(.+)") then - local err = s:gsub(".-%.lua:%d+:%s*(.+)", "extern: %1") + local err = s:gsub(".-%.lua:%d+:%s*(.+)", "%1") table.insert(tbl, err) elseif s:find('%[string ".-"%]') then local line, err = s:match('^%[string ".-"%]:(%d+): (.+)$') @@ -134,6 +134,24 @@ local function compile(pos, text, label, err_clbk) end end +local function runtime_delimiter(code) + local time = minetest.get_us_time() + local timeout = function () + if minetest.get_us_time() - time > safer_lua.MaxExeTime then + debug.sethook() + error("Runtime limit exceeded") + end + end + debug.sethook(timeout, "c") + code() + debug.sethook() +end + +local function error_handler(...) + debug.sethook() + return debug.traceback(...) +end + ------------------------------------------------------------------------------- -- Standard init/loop controller ------------------------------------------------------------------------------- @@ -148,7 +166,7 @@ function safer_lua.init(pos, init, loop, environ, err_clbk) env.S = {} env.S = map(env.S, environ) setfenv(code, env) - local res, err = xpcall(code, debug.traceback) + local res, err = xpcall(runtime_delimiter, error_handler, code) if not res then err_clbk(pos, format_error(err, "init")) else @@ -171,7 +189,7 @@ function safer_lua.run_loop(pos, elapsed, code, err_clbk) env.event = false env.ticks = env.ticks + 1 end - local res, err = xpcall(code, debug.traceback) + local res, err = xpcall(runtime_delimiter, error_handler, code) if calc_used_mem_size(env) > safer_lua.MaxTableSize then err_clbk(pos, "Error: Data memory limit exceeded") return false @@ -188,7 +206,7 @@ end ------------------------------------------------------------------------------- local function thread(pos, code, err_clbk) while true do - local res, err = xpcall(code, debug.traceback) + local res, err = xpcall(runtime_delimiter, error_handler, code) if not res then err_clbk(pos, format_error(err, "loop")) return false diff --git a/safer_lua/readme.md b/safer_lua/readme.md index eb6bde8..ba82e58 100644 --- a/safer_lua/readme.md +++ b/safer_lua/readme.md @@ -8,7 +8,7 @@ A subset of the language Lua for safe and secure Lua sandboxes with: - limited posibilities to call functions ### License -Copyright (C) 2018-2021 Joachim Stolberg +Copyright (C) 2018-2022 Joachim Stolberg Code: Licensed under the GNU LGPL version 2.1 or later. See LICENSE.txt @@ -19,3 +19,4 @@ none - 2018-06-24 v0.01 * first draft - 2020-03-14 v1.00 * extracted from TechPack and released - 2021-11-28 v1.01 * function `string.split2` added, `unpack` removed +- 2022-12-22 v1.02 * Limit code execution time for recursive function calls (#3 by Thomas--S) diff --git a/safer_lua/scanner.lua b/safer_lua/scanner.lua index a95a23b..6a3d146 100644 --- a/safer_lua/scanner.lua +++ b/safer_lua/scanner.lua @@ -41,13 +41,13 @@ function safer_lua:string(pttrn) end local function lines(str) - local t = {} - local function helper(line) - table.insert(t, line) - return "" - end - helper((str:gsub("(.-)\r?\n", helper))) - return t + local t = {} + local function helper(line) + table.insert(t, line) + return "" + end + helper((str:gsub("(.-)\r?\n", helper))) + return t end function safer_lua:scanner(text) diff --git a/signs_bot/cmd_move.lua b/signs_bot/cmd_move.lua index 12c908a..df51d01 100644 --- a/signs_bot/cmd_move.lua +++ b/signs_bot/cmd_move.lua @@ -48,6 +48,7 @@ function signs_bot.move_robot(mem) if node4.name == "signs_bot:robot_foot" then minetest.swap_node(pos4, mem.stored_node or {name = "air"}) end + minetest.swap_node(pos3, {name = "air"}) minetest.remove_node(pos) else minetest.swap_node(pos, mem.stored_node or {name = "air"}) @@ -319,7 +320,7 @@ signs_bot.register_botcommand("stop", { if mem.capa then mem.capa = mem.capa + 2 end - return signs_bot.DONE + return signs_bot.BUSY end, }) diff --git a/signs_bot/cmd_place.lua b/signs_bot/cmd_place.lua index ae53b6b..5492755 100644 --- a/signs_bot/cmd_place.lua +++ b/signs_bot/cmd_place.lua @@ -168,6 +168,7 @@ signs_bot.register_botcommand("place_below", { end, cmnd = function(base_pos, mem, slot) slot = tonumber(slot) or 0 + mem.stored_node = {name = "air"} return place_item_below(base_pos, mem.robot_pos, mem.robot_param2, slot) end, }) diff --git a/signs_bot/interpreter.lua b/signs_bot/interpreter.lua index 7a8bd1a..ec9fbc6 100644 --- a/signs_bot/interpreter.lua +++ b/signs_bot/interpreter.lua @@ -129,6 +129,7 @@ end local function gen_string_cmnd(code, pc, num_param, script) local tokens = tokenizer(script) + pc = math.min(pc, #tokens) if num_param == 0 then return tokens[pc] elseif num_param == 1 then diff --git a/techage/basic_machines/foreign_nodes.lua b/techage/basic_machines/foreign_nodes.lua index e9a3ebc..c9799d3 100644 --- a/techage/basic_machines/foreign_nodes.lua +++ b/techage/basic_machines/foreign_nodes.lua @@ -109,17 +109,19 @@ techage.register_node({"default:furnace", "default:furnace_active"}, { local inv = meta:get_inventory() return techage.get_items(pos, inv, "dst", num) end, - on_push_item = function(pos, side, stack) + on_push_item = function(pos, in_dir, stack) local meta = minetest.get_meta(pos) local inv = meta:get_inventory() minetest.get_node_timer(pos):start(1.0) - if minetest.get_craft_result({method="fuel", width=1, items={stack}}).time ~= 0 then + if in_dir == 5 then + return techage.put_items(inv, "src", stack) + elseif minetest.get_craft_result({method="fuel", width=1, items={stack}}).time ~= 0 then return techage.put_items(inv, "fuel", stack) else return techage.put_items(inv, "src", stack) end end, - on_unpull_item = function(pos, side, stack) + on_unpull_item = function(pos, in_dir, stack) local meta = minetest.get_meta(pos) local inv = meta:get_inventory() return techage.put_items(inv, "dst", stack) diff --git a/techage/basic_machines/grinder.lua b/techage/basic_machines/grinder.lua index 97a8340..a3cc579 100644 --- a/techage/basic_machines/grinder.lua +++ b/techage/basic_machines/grinder.lua @@ -431,4 +431,5 @@ if minetest.global_exists("farming") then techage.add_grinder_recipe({input="farming:seed_rice 6", output="farming:rice_flour"}, true) techage.add_grinder_recipe({input="farming:oat 3", output="farming:flour"}, true) techage.add_grinder_recipe({input="farming:seed_oat 6", output="farming:flour"}, true) + techage.add_grinder_recipe({input="farming:seed_cotton 3", output="basic_materials:oil_extract"}, true) end diff --git a/techage/basic_machines/quarry.lua b/techage/basic_machines/quarry.lua index 33be5ec..14a4796 100644 --- a/techage/basic_machines/quarry.lua +++ b/techage/basic_machines/quarry.lua @@ -26,7 +26,7 @@ local CRD = function(pos) return (minetest.registered_nodes[techage.get_node_lvm local S = techage.S -local CYCLE_TIME = 3 +local CYCLE_TIME = 4 local STANDBY_TICKS = 4 local COUNTDOWN_TICKS = 4 @@ -205,6 +205,7 @@ local function quarry_task(pos, crd, nvm) if not is_air_level(pos1, pos2, nvm.hole_diameter) then mark_area(pos1, pos2, owner) + M(pos):set_string("formspec", formspec(CRD(pos).State, pos, nvm)) coroutine.yield() for zoffs = 1, nvm.hole_diameter do diff --git a/techage/basic_machines/ta4_chest.lua b/techage/basic_machines/ta4_chest.lua index cb5b7e9..eb91de0 100644 --- a/techage/basic_machines/ta4_chest.lua +++ b/techage/basic_machines/ta4_chest.lua @@ -613,10 +613,10 @@ techage.register_node({"techage:ta4_chest"}, { on_recv_message = function(pos, src, topic, payload) if topic == "count" then local nvm = techage.get_nvm(pos) - return get_count(nvm, tonumber(payload or 1) or 1) + return get_count(nvm, tonumber(payload or 0) or 0) elseif topic == "itemstring" then local nvm = techage.get_nvm(pos) - return get_itemstring(nvm, tonumber(payload or 1) or 1) + return get_itemstring(nvm, tonumber(payload or 0) or 0) elseif topic == "state" then local nvm = techage.get_nvm(pos) return inv_state(nvm) @@ -627,10 +627,10 @@ techage.register_node({"techage:ta4_chest"}, { on_beduino_request_data = function(pos, src, topic, payload) if topic == 140 and payload[1] == 1 then -- Inventory Item Count local nvm = techage.get_nvm(pos) - return 0, {get_count(nvm, tonumber(payload[2] or 1) or 1)} + return 0, {get_count(nvm, tonumber(payload[2] or 0) or 0)} elseif topic == 140 and payload[1] == 2 then -- Inventory Item Name local nvm = techage.get_nvm(pos) - return 0, get_itemstring(nvm, tonumber(payload[2] or 1) or 1) + return 0, get_itemstring(nvm, tonumber(payload[2] or 0) or 0) elseif topic == 131 then -- Chest State local nvm = techage.get_nvm(pos) return 0, {inv_state_num(nvm)} diff --git a/techage/basis/command.lua b/techage/basis/command.lua index 1ae41e8..584adbe 100644 --- a/techage/basis/command.lua +++ b/techage/basis/command.lua @@ -16,6 +16,7 @@ local S = function(pos) if pos then return minetest.pos_to_string(pos) end end --local P = minetest.string_to_pos --local M = minetest.get_meta +local has_mesecons = minetest.global_exists("mesecon") local NodeInfoCache = {} local NumbersToBeRecycled = {} @@ -171,7 +172,7 @@ end) techage.dug_node = {} minetest.register_on_dignode(function(pos, oldnode, digger) if not digger then return end - -- store pos for tools without own 'register_on_dignode' + -- store the position of the dug block for tools like the TA1 hammer techage.dug_node[digger:get_player_name()] = pos end) @@ -317,6 +318,13 @@ function techage.register_node(names, node_definition) if node_definition.on_node_load then register_lbm(names[1], names) end + + -- register mvps stopper + if has_mesecons then + for _, name in ipairs(names) do + mesecon.register_mvps_stopper(name) + end + end end ------------------------------------------------------------------- @@ -331,6 +339,19 @@ function techage.not_protected(number, placer_name, clicker_name) return false end +-- Check the given number value. +-- Returns true if the number is valid, point to real node and +-- and the node is not protected for the given player_name. +function techage.check_number(number, placer_name) + if number then + if not techage.not_protected(number, placer_name, nil) then + return false + end + return true + end + return false +end + -- Check the given list of numbers. -- Returns true if number(s) is/are valid, point to real nodes and -- and the nodes are not protected for the given player_name. diff --git a/techage/basis/fly_lib.lua b/techage/basis/fly_lib.lua index 00ec087..61107d1 100644 --- a/techage/basis/fly_lib.lua +++ b/techage/basis/fly_lib.lua @@ -3,7 +3,7 @@ TechAge ======= - Copyright (C) 2020-2021 Joachim Stolberg + Copyright (C) 2020-2022 Joachim Stolberg AGPL v3 See LICENSE.txt for more information @@ -57,6 +57,96 @@ local function rotate(v, yaw) return {x = v.x * cosyaw - v.z * sinyaw, y = v.y, z = v.x * sinyaw + v.z * cosyaw} end +local function set_node(item) + local dest_pos = item.dest_pos + local name = item.name or "air" + local param2 = item.param2 or 0 + local metadata = item.metadata or {} + local nvm = techage.get_nvm(item.base_pos) + local node = techage.get_node_lvm(dest_pos) + local ndef1 = minetest.registered_nodes[name] + local ndef2 = minetest.registered_nodes[node.name] + + nvm.running = false + M(item.base_pos):set_string("status", S("Stopped")) + if ndef1 and ndef2 then + if ndef2.buildable_to then + local meta = M(dest_pos) + minetest.set_node(dest_pos, {name=name, param2=param2}) + meta:from_table(item.metadata or {}) + meta:set_string("ta_move_block", "") + meta:set_int("ta_door_locked", 1) + return + end + local meta = M(dest_pos) + if not meta:contains("ta_move_block") then + meta:set_string("ta_move_block", minetest.serialize({name=name, param2=param2})) + return + end + elseif ndef1 then + minetest.add_item(dest_pos, ItemStack(name)) + end +end + +------------------------------------------------------------------------------- +-- Entity monitoring +------------------------------------------------------------------------------- +local queue = {} +local first = 0 +local last = -1 + +local function push(item) + last = last + 1 + queue[last] = item +end + +local function pop(nvm, time) + if first > last then return end + local item = queue[first] + queue[first] = nil -- to allow garbage collection + first = first + 1 + return item +end + +local function monitoring() + local num = last - first + 1 + for _ = 1, num do + local item = pop() + if item.ttl >= techage.SystemTime then + -- still valud + push(item) + elseif item.ttl ~= 0 then + set_node(item) + end + end + minetest.after(1, monitoring) +end +minetest.after(1, monitoring) + +minetest.register_on_shutdown(function() + local num = last - first + 1 + for _ = 1, num do + local item = pop() + if item.ttl ~= 0 then + set_node(item) + end + end +end) + +local function monitoring_add_entity(item) + item.ttl = techage.SystemTime + 1 + push(item) +end + +local function monitoring_del_entity(item) + -- Mark as timed out + item.ttl = 0 +end + +local function monitoring_trigger_entity(item) + item.ttl = techage.SystemTime + 1 +end + ------------------------------------------------------------------------------- -- to_path function for the fly/move path ------------------------------------------------------------------------------- @@ -310,41 +400,15 @@ end local function entity_to_node(pos, obj) local self = obj:get_luaentity() - if self then - local name = self.item_name or "air" - local param2 = self.param2 or 0 - local metadata = self.metadata or {} + if self and self.item then detach_objects(pos, self) - if self.base_pos then - local nvm = techage.get_nvm(self.base_pos) - nvm.running = nil - end + monitoring_del_entity(self.item) minetest.after(0.1, obj.remove, obj) - local node = minetest.get_node(pos) - local ndef1 = minetest.registered_nodes[name] - local ndef2 = minetest.registered_nodes[node.name] - 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", "") - meta:set_int("ta_door_locked", 1) - 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 + set_node(self.item) end end -local function node_to_entity(start_pos) +local function node_to_entity(base_pos, start_pos, dest_pos) local meta = M(start_pos) local node, metadata @@ -356,7 +420,7 @@ local function node_to_entity(start_pos) meta:set_string("ta_block_locked", "true") elseif not meta:contains("ta_block_locked") then -- Block with other metadata - node = minetest.get_node(start_pos) + node = techage.get_node_lvm(start_pos) metadata = meta:to_table() minetest.after(0.1, minetest.remove_node, start_pos) else @@ -371,9 +435,15 @@ local function node_to_entity(start_pos) obj:set_armor_groups({immortal=1}) -- To be able to revert to node - self.item_name = node.name self.param2 = node.param2 - self.metadata = metadata or {} + self.item = { + name = node.name, + param2 = node.param2, + metadata = metadata or {}, + dest_pos = dest_pos, + base_pos = base_pos, + } + monitoring_add_entity(self.item) -- Prepare for attachments self.players = {} @@ -436,7 +506,6 @@ local function handover_to(obj, self, pos1) end local pos2 = next_path_pos(pos1, self.lpath, 1) local dir = determine_dir(pos1, pos2) - --print("handover_to", P2S(pos1), P2S(pos2), P2S(dir), P2S(info.pos), meta:get_string("path")) if not self.handover then local nvm = techage.get_nvm(info.pos) nvm.lpos1 = nvm.lpos1 or {} @@ -458,7 +527,7 @@ minetest.register_entity("techage:move_item", { initial_properties = { pointable = true, makes_footstep_sound = true, - static_save = true, + static_save = false, collide_with_objects = false, physical = false, visual = "wielditem", @@ -467,49 +536,6 @@ minetest.register_entity("techage:move_item", { selectionbox = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5}, }, - get_staticdata = function(self) - return minetest.serialize({ - item_name = self.item_name, - param2 = self.param2, - metadata = self.metadata, - move2to1 = self.move2to1, - handover = self.handover, - path_idx = self.path_idx, - pos1_idx = self.pos1_idx, - lpath = self.lpath, - start_pos = self.start_pos, - base_pos = self.base_pos, - max_speed = self.max_speed, - dest_pos = self.dest_pos, - dir = self.dir, - respawn = true, - }) - end, - - on_activate = function(self, staticdata) - if staticdata then - local tbl = minetest.deserialize(staticdata) or {} - self.item_name = tbl.item_name or "air" - self.param2 = tbl.param2 or 0 - self.metadata = tbl.metadata or {} - self.move2to1 = tbl.move2to1 or false - self.handover = tbl.handover - self.path_idx = tbl.path_idx or 1 - self.pos1_idx = tbl.pos1_idx or 1 - self.lpath = tbl.lpath or {} - 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.base_pos = tbl.base_pos - self.dir = tbl.dir or {x=0, y=0, z=0} - self.object:set_properties({wield_item = self.item}) - --print("tbl.respawn", tbl.respawn) - if tbl.respawn then - entity_to_node(self.dest_pos, self.object) - end - end - end, - on_step = function(self, dtime, moveresult) local stop_obj = function(obj, self) local dest_pos = self.dest_pos @@ -518,7 +544,6 @@ minetest.register_entity("techage:move_item", { obj:set_velocity({x=0, y=0, z=0}) self.dest_pos = nil self.old_dist = nil - self.ttl = 2 return dest_pos end @@ -571,19 +596,13 @@ minetest.register_entity("techage:move_item", { end 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 + monitoring_trigger_entity(self.item) end end, }) local function is_valid_dest(pos) - local node = minetest.get_node(pos) + local node = techage.get_node_lvm(pos) if techage.is_air_like(node.name) then return true end @@ -594,20 +613,19 @@ local function is_valid_dest(pos) end local function is_simple_node(pos) - local node = minetest.get_node(pos) + local node =techage.get_node_lvm(pos) local ndef = minetest.registered_nodes[node.name] return not techage.is_air_like(node.name) and techage.can_dig_node(node.name, ndef) end local function move_node(pos, pos1_idx, start_pos, lpath, max_speed, height, move2to1, handover, cpos) local pos2 = next_path_pos(start_pos, lpath, 1) - --print("move_node", P2S(pos), P2S(start_pos), lpath, max_speed, height, move2to1, P2S(pos2)) -- optional for non-player objects local yoffs = M(pos):get_float("offset") if pos2 then local dir = determine_dir(start_pos, pos2) - local obj = node_to_entity(start_pos) + local obj = node_to_entity(pos, start_pos, pos2) if obj then local offs = {x=0, y=height or 1, z=0} @@ -622,40 +640,43 @@ local function move_node(pos, pos1_idx, start_pos, lpath, max_speed, height, mov self.pos1_idx = pos1_idx self.lpath = lpath self.max_speed = max_speed - self.start_pos = start_pos - self.base_pos = pos self.move2to1 = move2to1 self.handover = handover self.yoffs = yoffs - --print("move_node", P2S(start_pos), P2S(pos2), P2S(dir), P2S(pos)) move_entity(obj, pos2, dir) + return true + else + return false end end end local function move_nodes(pos, meta, nvm, lpath, max_speed, height, move2to1, handover) - --print("move_nodes", dump(nvm), dump(lpath), max_speed, height, move2to1, handover) local owner = meta:get_string("owner") - techage.counting_add(owner, #nvm.lpos1 * #lpath) + techage.counting_add(owner, #lpath, #nvm.lpos1 * #lpath) for idx = 1, #nvm.lpos1 do local pos1 = nvm.lpos1[idx] local pos2 = nvm.lpos2[idx] + --print("move_nodes", idx, P2S(pos1), P2S(pos2)) if move2to1 then pos1, pos2 = pos2, pos1 end - --print("move_nodes", P2S(pos1), P2S(pos2)) if not minetest.is_protected(pos1, owner) and not minetest.is_protected(pos2, owner) then if is_simple_node(pos1) and is_valid_dest(pos2) then - move_node(pos, idx, pos1, lpath, max_speed, height, move2to1, handover) + if move_node(pos, idx, pos1, lpath, max_speed, height, move2to1, handover) == false then + meta:set_string("status", S("No valid node at the start position")) + return false + 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 + return false end else if minetest.is_protected(pos1, owner) then @@ -666,12 +687,12 @@ local function move_nodes(pos, meta, nvm, lpath, max_speed, height, move2to1, ha return false end end + meta:set_string("status", S("Running")) return true end -- Move nodes from lpos1 by the given x/y/z 'line' local function move_nodes2(pos, meta, lpos1, line, max_speed, height) - --print("move_nodes2", dump(lpos1), dump(line), max_speed, height) local owner = meta:get_string("owner") techage.counting_add(owner, #lpos1) @@ -691,6 +712,7 @@ local function move_nodes2(pos, meta, lpos1, line, max_speed, height) else meta:set_string("status", S("No valid destination position")) end + return false, lpos1 end else if minetest.is_protected(pos1, owner) then @@ -702,7 +724,7 @@ local function move_nodes2(pos, meta, lpos1, line, max_speed, height) end end - meta:set_string("status", "") + meta:set_string("status", S("Running")) return true, lpos2 end @@ -714,7 +736,7 @@ function flylib.move_to_other_pos(pos, move2to1) local height = meta:contains("height") and meta:get_float("height") or 1 local handover - if err then return false end + if err or nvm.running then return false end height = techage.in_range(height, 0, 1) max_speed = techage.in_range(max_speed, MIN_SPEED, MAX_SPEED) @@ -732,7 +754,9 @@ function flylib.move_to_other_pos(pos, move2to1) else handover = meta:contains("handoverB") and meta:get_string("handoverB") or nil end - return move_nodes(pos, meta, nvm, lpath, max_speed, height, move2to1, handover) + nvm.running = move_nodes(pos, meta, nvm, lpath, max_speed, height, move2to1, handover) + nvm.moveBA = nvm.running and not move2to1 + return nvm.running end function flylib.move_to(pos, line) @@ -742,8 +766,10 @@ function flylib.move_to(pos, line) local max_speed = meta:contains("max_speed") and meta:get_int("max_speed") or MAX_SPEED local resp - resp, nvm.lastpos = move_nodes2(pos, meta, nvm.lastpos or nvm.lpos1, line, max_speed, height) - return resp + if nvm.running then return false end + + nvm.running, nvm.lastpos = move_nodes2(pos, meta, nvm.lastpos or nvm.lpos1, line, max_speed, height) + return nvm.running end function flylib.reset_move(pos) @@ -751,11 +777,17 @@ function flylib.reset_move(pos) local nvm = techage.get_nvm(pos) local height = techage.in_range(meta:contains("height") and meta:get_float("height") or 1, 0, 1) local max_speed = meta:contains("max_speed") and meta:get_int("max_speed") or MAX_SPEED - local move = vector.subtract(nvm.lpos1[1], (nvm.lastpos or nvm.lpos1)[1]) - local resp - resp, nvm.lastpos = move_nodes2(pos, meta, nvm.lastpos or nvm.lpos1, move, max_speed, height) - return resp + if nvm.running then return false end + + if nvm.lpos1 and nvm.lpos1[1] then + local move = vector.subtract(nvm.lpos1[1], (nvm.lastpos or nvm.lpos1)[1]) + local resp + + nvm.running, nvm.lastpos = move_nodes2(pos, meta, nvm.lastpos or nvm.lpos1, move, max_speed, height) + return nvm.running + end + return false end -- rot is one of "l", "r", "2l", "2r" @@ -842,4 +874,4 @@ minetest.register_on_dieplayer(function(player) end end) -return flylib +techage.flylib = flylib diff --git a/techage/basis/nodedata_sqlite.lua b/techage/basis/nodedata_sqlite.lua index dcc9cfa..8540365 100644 --- a/techage/basis/nodedata_sqlite.lua +++ b/techage/basis/nodedata_sqlite.lua @@ -72,8 +72,11 @@ end local api = {} function api.store_mapblock_data(key, mapblock_data) - if use_marshal then - set_block(key, marshal.encode(mapblock_data)) + if use_marshal and mapblock_data then + local data = marshal.encode(mapblock_data) + if data then + set_block(key, data) + end else set_block(key, minetest.serialize(mapblock_data)) end diff --git a/techage/collider/terminal.lua b/techage/collider/terminal.lua deleted file mode 100644 index 6ef6dd5..0000000 --- a/techage/collider/terminal.lua +++ /dev/null @@ -1,208 +0,0 @@ ---[[ - - Techage - ======= - - Copyright (C) 2020-2021 Joachim Stolberg - - AGPL v3 - See LICENSE.txt for more information - - TA4 Terminal - -]]-- - -local M = minetest.get_meta -local S = techage.S - -local STR_LEN = 80 -local HELP = [[#### TA4 Terminal #### - -Send commands to the connected machine -and output text messages from the -machine. - -Commands can have up to 80 characters. -Local commands: -- clear = clear screen -- help = this message -- pub = switch to public use -- priv = switch to private use -- connect = connect the machine - -All other commands are machine dependent. -]] - -local function get_string(meta, num, default) - local s = meta:get_string("bttn_text"..num) - if not s or s == "" then - return default - end - return s -end - -local function formspec2(mem) - mem.command = mem.command or "" - mem.output = mem.output or "" - local output = minetest.formspec_escape(mem.output) - output = output:gsub("\n", ",") - local command = minetest.formspec_escape(mem.command) - local bttn_text1 = get_string(meta, 1, "User1") - local bttn_text2 = get_string(meta, 2, "User2") - local bttn_text3 = get_string(meta, 3, "User3") - local bttn_text4 = get_string(meta, 4, "User4") - local bttn_text5 = get_string(meta, 5, "User5") - local bttn_text6 = get_string(meta, 6, "User6") - local bttn_text7 = get_string(meta, 7, "User7") - local bttn_text8 = get_string(meta, 8, "User8") - local bttn_text9 = get_string(meta, 9, "User9") - return "size[10,8]".. - "style_type[table,field;font=mono]".. - "button[0,0;3.3,1;bttn1;"..bttn_text1.."]button[3.3,0;3.3,1;bttn2;"..bttn_text2.."]button[6.6,0;3.3,1;bttn3;"..bttn_text3.."]".. - "button[0,0.8;3.3,1;bttn4;"..bttn_text4.."]button[3.3,0.8;3.3,1;bttn5;"..bttn_text5.."]button[6.6,0.8;3.3,1;bttn6;"..bttn_text6.."]".. - "button[0,1.6;3.3,1;bttn7;"..bttn_text7.."]button[3.3,1.6;3.3,1;bttn8;"..bttn_text8.."]button[6.6,1.6;3.3,1;bttn9;"..bttn_text9.."]".. - "table[0,2.5;9.8,4.7;output;"..output..";200]".. - "field[0.4,7.7;7.6,1;cmnd;;"..mem.command.."]" .. - "field_close_on_enter[cmnd;false]".. - "button[7.9,7.4;2,1;enter;"..S("Enter").."]" -end - -local function output(pos, text) - local mem = techage.get_mem(pos) - mem.output = mem.output .. "\n" .. (text or "") - mem.output = mem.output:sub(-500,-1) - M(pos):set_string("formspec", formspec2(mem)) -end - -local function command(pos, mem, player) - local meta = minetest.get_meta(pos) - local owner = meta:get_string("owner") - - if mem.command == "clear" then - mem.output = "" - mem.command = "" - meta:set_string("formspec", formspec2(mem)) - elseif mem.command == "" then - output(pos, ">") - mem.command = "" - meta:set_string("formspec", formspec2(mem)) - elseif mem.command == "help" then - local meta = minetest.get_meta(pos) - mem.output = HELP - mem.command = "" - meta:set_string("formspec", formspec2(mem)) - elseif mem.command == "pub" and owner == player then - meta:set_int("public", 1) - output(pos, "> "..mem.command) - mem.command = "" - output(pos, "Switched to public use!") - elseif mem.command == "priv" and owner == player then - meta:set_int("public", 0) - output(pos, "> "..mem.command) - mem.command = "" - output(pos, "Switched to private use!") - elseif meta:get_int("public") == 1 or owner == player then - if mem.command == "clear" then - mem.output = - mem.command = "" - meta:set_string("formspec", formspec2(mem)) - end - end -end - -minetest.register_node("techage:ta4_terminal", { - description = "TA4 Collider Terminal", - tiles = { - -- up, down, right, left, back, front - 'techage_terminal1_top.png', - 'techage_terminal1_bottom.png', - 'techage_terminal1_side.png', - 'techage_terminal1_side.png', - 'techage_terminal1_bottom.png', - "techage_terminal1_front.png", - }, - drawtype = "nodebox", - node_box = { - type = "fixed", - fixed = { - {-12/32, -16/32, -8/32, 12/32, -14/32, 12/32}, - {-12/32, -14/32, 12/32, 12/32, 6/32, 14/32}, - }, - }, - selection_box = { - type = "fixed", - fixed = { - {-12/32, -16/32, -8/32, 12/32, -14/32, 12/32}, - {-12/32, -14/32, 12/32, 12/32, 6/32, 14/32}, - }, - }, - - after_place_node = function(pos, placer) - local number = techage.add_node(pos, minetest.get_node(pos).name) - local meta = minetest.get_meta(pos) - meta:set_string("formspec", formspec1()) - meta:set_string("owner", placer:get_player_name()) - meta:set_string("infotext", S("TA4 Collider Terminal") .. ": " .. S("not connected") - end, - - on_receive_fields = function(pos, formname, fields, player) - local meta = minetest.get_meta(pos) - local mem = techage.get_mem(pos) - if fields.number and fields.number ~= "" then - local owner = meta:get_string("owner") - if techage.check_numbers(fields.number, owner) then - local own_number = meta:get_string("own_number") - if techage.send_single(own_number, fields.number, "connect") == true then - meta:set_string("number", fields.number) - meta:set_string("infotext", S("TA4 Collider Terminal") .. ": " .. S("connected with") .. " " .. fields.number) - meta:set_string("formspec", formspec2(mem)) - end - end - elseif (fields.enter or fields.key_enter_field) and fields.cmnd then - mem.command = string.sub(fields.cmnd, 1, STR_LEN) - command(pos, mem, player:get_player_name()) - elseif fields.key_up then - mem.command = pdp13.historybuffer_priv(pos) - meta:set_string("formspec", formspec2(mem)) - elseif fields.key_down then - mem.command = pdp13.historybuffer_next(pos) - meta:set_string("formspec", formspec2(mem)) - end - end, - - after_dig_node = function(pos, oldnode, oldmetadata) - techage.remove_node(pos, oldnode, oldmetadata) - end, - - paramtype = "light", - use_texture_alpha = techage.CLIP, - sunlight_propagates = true, - paramtype2 = "facedir", - groups = {choppy=2, cracky=2, crumbly=2}, - is_ground_content = false, - sounds = default.node_sound_metal_defaults(), -}) - -minetest.register_craft({ - output = "techage:ta4_terminal", - recipe = { - {"", "techage:ta4_display", ""}, - {"dye:black", "techage:ta4_wlanchip", "default:copper_ingot"}, - {"", "techage:aluminum", ""}, - }, -}) - -techage.register_node({"techage:ta4_terminal"}, { - on_recv_message = function(pos, src, topic, payload) - if topic == "term" then - output(pos, payload) - return true - elseif topic == "clear" then - local mem = techage.get_mem(pos) - mem.output = "" - mem.command = "" - M(pos):set_string("formspec", formspec2(mem)) - return true - end - end, -}) diff --git a/techage/doc/items.lua b/techage/doc/items.lua index b163cc8..9d85470 100644 --- a/techage/doc/items.lua +++ b/techage/doc/items.lua @@ -208,6 +208,7 @@ techage.Items = { techage_ta5 = "techage:ta5_fr_nucleus", ta5_flycontroller = "techage:ta5_flycontroller", ta5_aichip = "techage:ta5_aichip", + ta5_aichip2 = "techage:ta5_aichip2", ta5_tele_pipe = "techage:ta5_tele_pipe", ta5_tele_tube = "techage:ta5_tele_tube", ta5_chest = "techage:ta5_hl_chest", diff --git a/techage/doc/manual_DE.lua b/techage/doc/manual_DE.lua index 1268fc7..5b06703 100644 --- a/techage/doc/manual_DE.lua +++ b/techage/doc/manual_DE.lua @@ -254,6 +254,7 @@ techage.manual_DE.aTitel = { "2,Weitere TA5 Blöcke/Items", "3,TA5 Container (geplant)", "3,TA5 KI Chip / TA5 AI Chip", + "3,TA5 KI Chip II / TA5 AI Chip II", } techage.manual_DE.aText = { @@ -360,13 +361,20 @@ techage.manual_DE.aText = { "\n", "Den Köhler brauchst du\\, um Holzkohle herzustellen. Holzkohle wird für den Brenner\\, aber auch bspw. in TA2 für die Dampfmaschine benötigt.\n".. "\n".. + "Für den Köhler brauchst du:\n".. + "\n".. + " - einen Anzünderblock ('techage:lighter')\n".. + " - 26 Hölzblöcke (wood)\\, die zu einem Würfen aufgeschichtet werden. Die Holzsorte spielt keine Rolle\n".. + " - Erde (dirt) um den Holzhaufen abzudecken\n".. + " - Flint and Iron (technischer Name: 'fire:flint_and_steel') um den Anzünderblock anzuzünden\n".. + "\n".. "Bauanleitung (siehe auch Plan):\n".. "\n".. " - Baue eine 5x5 große Fläche aus Erde (dirt)\n".. " - Platziere in die Mitte einen Anzünder (lighter)\n".. - " - Baue aus Holz (wood) einen 3x3x3 großen Würfel darüber\n".. - " - Überdecke alles mit einer Schicht Erde zu einem 5x5x5 großen Würfel\n".. - " - Lasse ein Loch zum Anzünder\n".. + " - Platziere rund um den Anzünder 7 Holz (wood)\\, aber lasse ein Loch zum Anzünder frei\n".. + " - Baue weitere 2 Schichten Holz darüber\\, so dass ein 3x3x3 großen Holzwürfel entsteht\n".. + " - Überdecke alles mit einer Schicht Erde zu einem 5x5x5 großen Würfel\\, aber lasse das Loch zum Anzünder frei\n".. " - Zünde den Anzünder an und verschließe das Loch sofort mit jeweils einem Block Holz und Erde\n".. " - Wenn du alles richtig gemacht hast\\, beginnt der Köhler nach wenigen Sekunden an zu rauchen\n".. " - Öffne den Köhler erst\\, wenn der Rauch verschwunden ist (ca. 20 min)\n".. @@ -1479,6 +1487,8 @@ techage.manual_DE.aText = { "\n".. "Der Elektrolyseur besitzt ein Schraubenschlüssel-Menü zur Einstellung der Stromaufnahme und des Abschaltpunkts.\n".. "\n".. + "Unterschreitet die im Stromnetz gespeicherte Leistung den angegebenen Wert des Abschaltpunkts\\, so schaltet sich der Elektrolyseur automatisch ab. Damit kann ein Leerlaufen der Speichersysteme verhindert werden.\n".. + "\n".. "\n".. "\n", "Die Brennstoffzelle wandelt Wasserstoff in Strom um.\n".. @@ -1494,16 +1504,18 @@ techage.manual_DE.aText = { "\n", "Der Reaktor dient dazu\\, die über den Destillationsturm oder aus anderen Rezepten gewonnenen Zutaten zu neuen Produkten weiter zu verarbeiten. Der Plan links zeigt nur eine mögliche Variante\\, da die Anordnung der Silos und Tanks rezeptabhängig ist.\n".. "\n".. + "Das primäre Ausgabeprodukt wird immer an der Seite des Reaktorständers ausgegeben\\, unabhängig davon\\, ob es sich um ein Pulver oder eine Flüssigkeit handelt. Das (sekundäre) Abfallprodukt wird immer unten am Reaktorständers ausgegeben.\n".. + "\n".. "Ein Reaktor besteht aus:\n".. "\n".. " - div. Tanks und Silos mit den Zutaten\\, die über Leitungen mit dem Dosierer verbunden sind\n".. - " - optional einem Reaktorsockel\\, welcher die Abfälle aus dem Reaktor ableitet (nur bei Rezepten mit zwei Ausgangsstoffen notwendig)\n".. + " - optional einem Reaktorsockel\\, welcher die Abfälle aus dem Reaktor ableitet (nur bei Rezepten mit zwei Ausgabestoffen notwendig)\n".. " - dem Reaktorständer\\, der auf den Sockel gesetzt werden muss (sofern vorhanden). Der Ständer hat einen Stromanschluss und zieht bei Betrieb 8 ku.\n".. " - dem eigentlichen Reaktorbehälter\\, der auf den Reaktorständer gesetzt werden muss\n".. " - dem Einfüllstutzen der auf den Reaktorbehälter gesetzt werden muss\n".. " - dem Dosierer\\, welcher über Leitungen mit den Tanks oder Silos sowie dem Einfüllstutzen verbunden werden muss\n".. "\n".. - "Hinweis 1: Flüssigkeiten werden nur in Tanks gelagert\\, feste Stoffe und Stoffe in Pulverform nur in Silos. Dies gilt für Zutaten und Ausgangsstoffe.\n".. + "Hinweis 1: Flüssigkeiten werden nur in Tanks gelagert\\, feste Stoffe und Stoffe in Pulverform nur in Silos. Dies gilt für Zutaten und Ausgabestoffe.\n".. "\n".. "Hinweis 2: Tanks oder Silos mit verschiedenen Inhalten dürfen nicht zu einem Leitungssystem verbunden werden. Mehrere Tanks oder Silos mit gleichem Inhalt dürfen dagegen parallel an einer Leitung hängen.\n".. "\n".. @@ -1524,7 +1536,7 @@ techage.manual_DE.aText = { "Wie auch bei anderen Maschinen:\n".. "\n".. " - geht der Dosierer in den standby Zustand\\, so fehlen ein oder mehrere Zutaten\n".. - " - geht der Dosierer in den blocked Zustand\\, so ist Ausgangstank oder Silo voll\\, defekt oder falsch angeschlossen\n".. + " - geht der Dosierer in den blocked Zustand\\, so ist Ausgabetank oder Silo voll\\, defekt oder falsch angeschlossen\n".. "\n".. "Der Dosierer benötigt keinen Strom. Alle 10 s wird ein Rezept abgearbeitet.\n".. "\n".. @@ -1541,7 +1553,7 @@ techage.manual_DE.aText = { "\n", "Teil des Chemischen Reaktors. Hier ist auch der Stromanschluss für den Reaktor. Der Reaktor benötigt 8 ku Strom.\n".. "\n".. - "Der Ständer hat zwei Leitungsanschlüsse\\, nach rechst für das Ausgangsprodukt und nach unten für den Abfall\\, wie bspw. Rotschlamm bei der Aluminiumherstellung.\n".. + "Der Ständer hat zwei Leitungsanschlüsse\\, nach rechst für das primäre Ausgabeprodukt und nach unten für den Abfall\\, wie bspw. Rotschlamm bei der Aluminiumherstellung.\n".. "\n".. "\n".. "\n", @@ -1722,6 +1734,11 @@ techage.manual_DE.aText = { " - 'b2a' Bewege Block von B nach A\n".. " - 'move' Bewege Block auf die andere Seite\n".. "\n".. + "Über das Schraubenschlüssel-Menü kann auf die Betriebsart 'move xyz' umgeschaltet werden. Nach der Umschaltung werden folgende techage Kommandos unterstützt:\n".. + "\n".. + " - 'move2' Beim Kommando muss zusätzlich die Flugstrecke als x\\,y\\,z Vektor angegeben werden.\nBeispiel Lua Controller: '$send_cmnd(MOVE_CTLR\\, \"move2\"\\, \"0\\,12\\,0\")'\n".. + " - 'reset' Block/Blöcke zurück in Startposition bewegen\n".. + "\n".. "*Wichtige Hinweise:*\n".. "\n".. " - Sofern mehrere Blöcke bewegt werden sollen\\, muss der Block\\, der die Spieler/Mobs mitnehmen soll\\, beim Antrainieren als erstes angeklickt werden.\n".. @@ -2146,6 +2163,10 @@ techage.manual_DE.aText = { "\n".. "\n".. "\n", + "Der TA5 KI Chip II wird zur Herstellung des TA5 Fusionsreaktors benötigt. Der TA5 KI Chip II kann nur auf der TA4 Elektronik Fab hergestellt werden. Dazu werden 50 Erfahrungspunkte benötigt.\n".. + "\n".. + "\n".. + "\n", } techage.manual_DE.aItemName = { @@ -2402,6 +2423,7 @@ techage.manual_DE.aItemName = { "", "", "ta5_aichip", + "ta5_aichip2", } techage.manual_DE.aPlanTable = { @@ -2658,5 +2680,6 @@ techage.manual_DE.aPlanTable = { "", "", "", + "", } diff --git a/techage/doc/manual_EN.lua b/techage/doc/manual_EN.lua index 7f582b8..b10047a 100644 --- a/techage/doc/manual_EN.lua +++ b/techage/doc/manual_EN.lua @@ -254,6 +254,7 @@ techage.manual_EN.aTitel = { "2,More TA5 Blocks/Items", "3,TA5 Container (planned)", "3,TA5 AI Chip", + "3,TA5 AI Chip II", } techage.manual_EN.aText = { @@ -368,13 +369,19 @@ techage.manual_EN.aText = { "\n", "You need the Charcoal Pile to make charcoal. Charcoal is required for the melting furnace\\, but also\\, for example\\, in TA2 for the steam engine.\n".. "\n".. + "For the charcoal burner you need:\n".. + "\n".. + " - a lighter block ('techage:lighter')\n".. + " - 26 wooden blocks that are stacked into a pile of wood. The type of wood is irrelevant\n".. + " - Dirt to cover the pile of wood\n".. + " - Flint and Iron (technical name: 'fire:flint_and_steel') to light the lighter block\n".. + "\n".. "Building instructions (see also plan):\n".. "\n".. - " - Build a 5x5 area of ​​dirt\n".. - " - Place a lighter in the middle\n".. - " - Build a 3x3x3 cube above it out of wood\n".. - " - Cover everything with a layer of dirt to form a 5x5x5 cube\n".. - " - Leave a hole to the lighter\n".. + " - Build a 5x5 area of dirt\n".. + " - Place 7 wood around the lighter but leave a hole to the lighter\n".. + " - Build another 2 layers of wood on top\\, making a 3x3x3 wooden cube\n".. + " - Cover everything with a layer of dirt into a 5x5x5 cube\\, but keep the hole to the lighter open\n".. " - Light the lighter and immediately close the hole with a block of wood and dirt\n".. " - If you have done everything correctly\\, the coal burner will start smoking after a few seconds\n".. " - Only open the charcoal burner when the smoke has disappeared (approx. 20 min)\n".. @@ -1486,6 +1493,8 @@ techage.manual_EN.aText = { "\n".. "The electrolyzer has a wrench menu for setting the current consumption and the switch-off point.\n".. "\n".. + "If the power stored in the power grid falls below the specified value of the switch-off point\\, the electrolyzer switches off automatically. This prevents the storage systems from running empty.\n".. + "\n".. "\n".. "\n", "The fuel cell converts hydrogen into electricity.\n".. @@ -1501,16 +1510,18 @@ techage.manual_EN.aText = { "The reactor is used to process the ingredients obtained from the distillation tower or from other recipes into new products.\n".. "The plan on the left shows only one possible variant\\, since the arrangement of the silos and tanks depends on the recipe.\n".. "\n".. + "The primary output product is always output to the side of the reactor stand\\, regardless of whether it is a powder or a liquid. The (secondary) waste product is always discharged at the bottom of the reactor stand.\n".. + "\n".. "A reactor consists of:\n".. "\n".. " - Various tanks and silos with the ingredients that are connected to the doser via pipes\n".. - " - optionally a reactor base\\, which discharges the waste from the reactor (only necessary for recipes with two starting materials)\n".. + " - optionally a reactor base\\, which discharges the waste from the reactor (only necessary for recipes with two output products)\n".. " - the reactor stand\\, which must be placed on the base (if available). The stand has a power connection and draws 8 ku during operation.\n".. " - The reactor vessel that has to be placed on the reactor stand\n".. " - The filler pipe that must be placed on the reactor vessel\n".. " - The dosing device\\, which has to be connected to the tanks or silos and the filler pipe via pipes\n".. "\n".. - "Note 1: Liquids are only stored in tanks\\, solids and substances in powder form only in silos. This applies to ingredients and raw materials.\n".. + "Note 1: Liquids are only stored in tanks\\, solids and substances in powder form only in silos. This applies to ingredients and output products.\n".. "\n".. "Note 2: Tanks or silos with different contents must not be connected to a pipe system. In contrast\\, several tanks or silos with the same content may hang in parallel on one line.\n".. "\n".. @@ -1531,7 +1542,7 @@ techage.manual_EN.aText = { "As with other machines:\n".. "\n".. " - if the doser is in standby mode\\, one or more ingredients are missing\n".. - " - if the doser is in the blocked state\\, the outlet tank or silo is full\\, defective or incorrectly connected\n".. + " - if the doser is in the blocked state\\, the output tank or silo is full\\, defective or incorrectly connected\n".. "\n".. "The doser does not need any electricity. A recipe is processed every 10 s.\n".. "\n".. @@ -1728,6 +1739,11 @@ techage.manual_EN.aText = { " - 'b2a' Move block from B to A.\n".. " - 'move' Move block to the other side\n".. "\n".. + "You can switch to the 'move xyz' operating mode via the wrench menu. After switching\\, the following techage commands are supported: \n".. + "\n".. + " - 'move2' With the command\\, the flight route must also be specified as an x\\,y\\,z vector.\nExample Lua Controller: '$send_cmnd(MOVE_CTLR\\, \"move2\"\\, \"0\\,12\\,0\")'\n".. + " - 'reset' move block(s) back to start position\n".. + "\n".. "*Important instructions:*\n".. "\n".. " - If several blocks are to be moved\\, the block that is to take the players/mobs must be clicked first when training.\n".. @@ -2151,6 +2167,10 @@ techage.manual_EN.aText = { "\n".. "\n".. "\n", + "The TA5 AI Chip II is required to build the TA5 Fusion Reactor. The TA5 AI Chip II can only be manufactured at the TA4 Electronics Fab. This requires 50 experience points.\n".. + "\n".. + "\n".. + "\n", } techage.manual_EN.aItemName = { @@ -2407,6 +2427,7 @@ techage.manual_EN.aItemName = { "", "", "ta5_aichip", + "ta5_aichip2", } techage.manual_EN.aPlanTable = { @@ -2663,5 +2684,6 @@ techage.manual_EN.aPlanTable = { "", "", "", + "", } diff --git a/techage/doc/plans.lua b/techage/doc/plans.lua index 282997c..ad24c67 100644 --- a/techage/doc/plans.lua +++ b/techage/doc/plans.lua @@ -346,7 +346,8 @@ local STAND = {"techage_reactor_stand_side.png", "techage:ta4_reactor_stand"} local REACT = {"techage_reactor_plan.png", "techage:ta4_reactor"} local FILLR = {"techage_reactor_filler_plan.png", "techage:ta4_reactor_fillerpipe"} local DOSER = {"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_pump_up.png", "techage:ta4_doser"} -local SILO = {"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_silo.png", "techage:ta3_silo"} +local SILO4 = {"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_silo.png", "techage:ta4_silo"} +local TANK4 = {"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_tank.png", "techage:ta4_tank"} techage.ConstructionPlans["ta4_reactor"] = { {false, false, false, false, false, false, SIDEV, false, false, false, false}, @@ -354,9 +355,9 @@ techage.ConstructionPlans["ta4_reactor"] = { {false, false, false, false, PN000, PIPEH, PIPEH, PN270, false, false, false}, {false, false, false, false, PIPEV, false, false, FILLR, false, false, false}, {false, false, false, false, PIPEV, false, false, REACT, false, false, false}, - {false, false, false, false, PIPEV, false, false, STAND, PIPEH, PIPEH, SILO}, - {false, TANK3, PIPEH, PIPEH, DOSER, PN270, false, RBASE, PIPEH, PIPEH, TANK3}, - {false, SILO, PIPEH, PIPEH, PIPEH, PN180, false, false, false, false, false}, + {false, false, false, false, PIPEV, false, false, STAND, PIPEH, PIPEH, SILO4}, + {false, TANK4, PIPEH, PIPEH, DOSER, PN270, false, RBASE, PIPEH, PIPEH, TANK4}, + {false, SILO4, PIPEH, PIPEH, PIPEH, PN180, false, false, false, false, false}, } -- diff --git a/techage/energy_storage/nodes.lua b/techage/energy_storage/nodes.lua index e23b834..6e48972 100644 --- a/techage/energy_storage/nodes.lua +++ b/techage/energy_storage/nodes.lua @@ -30,7 +30,7 @@ minetest.register_node("techage:glow_gravel", { }}, paramtype = "light", light_source = 8, - groups = {crumbly = 2, falling_node = 1}, + groups = {crumbly = 2, falling_node = 1, not_in_creative_inventory = 1}, sounds = default.node_sound_gravel_defaults(), drop = "", }) diff --git a/techage/hydrogen/electrolyzer.lua b/techage/hydrogen/electrolyzer.lua index 155091f..599d489 100644 --- a/techage/hydrogen/electrolyzer.lua +++ b/techage/hydrogen/electrolyzer.lua @@ -200,7 +200,7 @@ local tool_config = { choices = "0%,20%,40%,60%,80%,98%", name = "turnoff", label = S("Turnoff point"), - tooltip = S("If the charge of the storage\nsystem exceeds the configured value,\nthe block switches off"), + tooltip = S("If the charge of the storage\nsystem falls below the configured value,\nthe block switches off"), default = "98%", }, } diff --git a/techage/init.lua b/techage/init.lua index b6d0287..a17e3ba 100644 --- a/techage/init.lua +++ b/techage/init.lua @@ -105,6 +105,7 @@ dofile(MP.."/basis/submenu.lua") dofile(MP.."/basis/shared_inv.lua") dofile(MP.."/basis/shared_tank.lua") dofile(MP.."/basis/teleport.lua") +dofile(MP.."/basis/fly_lib.lua") -- Main doc dofile(MP.."/doc/manual_DE.lua") diff --git a/techage/iron_age/hammer.lua b/techage/iron_age/hammer.lua index 058bfbd..c760b61 100644 --- a/techage/iron_age/hammer.lua +++ b/techage/iron_age/hammer.lua @@ -14,9 +14,29 @@ local S = techage.S +local Stone2Gravel = { + ["default:stone"] = "default:gravel", + ["default:cobble"] = "default:gravel", + ["default:desert_stone"] = "default:gravel", + ["techage:basalt_stone"] = "techage:basalt_gravel", + ["techage:basalt_cobble"] = "techage:basalt_gravel", + ["techage:bauxite_stone"] = "techage:bauxite_gravel", + ["techage:bauxite_cobble"] = "techage:bauxite_gravel", +} + +function techage.register_stone_gravel_pair(stone_name, gravel_name) + Stone2Gravel[stone_name] = gravel_name +end + +-- Pipeworks uses a fakeplayer based on the owner of the nodebraker. +local function is_real_player(player) + return minetest.is_player(player) and not player.is_fake_player +end + local function handler(player_name, node, itemstack, digparams) local pos = techage.dug_node[player_name] if not pos then return end + techage.dug_node[player_name] = nil if minetest.is_protected(pos, player_name) then minetest.record_protection_violation(pos, player_name) @@ -30,6 +50,7 @@ local function handler(player_name, node, itemstack, digparams) local item = ItemStack(ndef.drop or node.name) local inv = minetest.get_inventory({type="player", name=player_name}) if inv and inv:room_for_item("main", item) then + -- item should have been added and can therefore be removed again local taken = inv:remove_item("main", item) else for _,obj in ipairs(minetest.get_objects_inside_radius(pos, 1)) do @@ -38,8 +59,8 @@ local function handler(player_name, node, itemstack, digparams) end end end - if node.name == "techage:basalt_stone" or node.name == "techage:basalt_cobble" then - node.name = "techage:basalt_gravel" + if Stone2Gravel[node.name] then + node.name = Stone2Gravel[node.name] else node.name = "default:gravel" end @@ -61,7 +82,9 @@ minetest.register_tool("techage:hammer_stone", { }, sound = {breaks = "default_tool_breaks"}, after_use = function(itemstack, user, node, digparams) - minetest.after(0.01, handler, user:get_player_name(), node) + if is_real_player(user) then + minetest.after(0.01, handler, user:get_player_name(), node) + end itemstack:add_wear(digparams.wear) return itemstack end, @@ -80,7 +103,9 @@ minetest.register_tool("techage:hammer_bronze", { }, sound = {breaks = "default_tool_breaks"}, after_use = function(itemstack, user, node, digparams) - minetest.after(0.01, handler, user:get_player_name(), node) + if is_real_player(user) then + minetest.after(0.01, handler, user:get_player_name(), node) + end itemstack:add_wear(digparams.wear) return itemstack end, @@ -99,7 +124,9 @@ minetest.register_tool("techage:hammer_steel", { }, sound = {breaks = "default_tool_breaks"}, after_use = function(itemstack, user, node, digparams) - minetest.after(0.01, handler, user:get_player_name(), node) + if is_real_player(user) then + minetest.after(0.01, handler, user:get_player_name(), node) + end itemstack:add_wear(digparams.wear) return itemstack end, @@ -118,7 +145,9 @@ minetest.register_tool("techage:hammer_mese", { }, sound = {breaks = "default_tool_breaks"}, after_use = function(itemstack, user, node, digparams) - minetest.after(0.01, handler, user:get_player_name(), node) + if is_real_player(user) then + minetest.after(0.01, handler, user:get_player_name(), node) + end itemstack:add_wear(digparams.wear) return itemstack end, @@ -137,7 +166,9 @@ minetest.register_tool("techage:hammer_diamond", { }, sound = {breaks = "default_tool_breaks"}, after_use = function(itemstack, user, node, digparams) - minetest.after(0.01, handler, user:get_player_name(), node) + if is_real_player(user) then + minetest.after(0.01, handler, user:get_player_name(), node) + end itemstack:add_wear(digparams.wear) return itemstack end, diff --git a/techage/items/cracking.lua b/techage/items/cracking.lua index 284bda4..52c98f3 100644 --- a/techage/items/cracking.lua +++ b/techage/items/cracking.lua @@ -10,7 +10,8 @@ Cracking breaks long chains of hydrocarbons into short chains using a catalyst. Gibbsite powder serves as a catalyst (is not consumed). - It can be used to convert bitumen into fueloil, fueloil into naphtha and naphtha into gasoline. + It can be used to convert bitumen into fueloil, fueloil into naphtha, naphtha into gasoline, + and gasoline into gas. In hydrogenation, pairs of hydrogen atoms are added to a molecule to convert short-chain hydrocarbons into long ones. @@ -45,6 +46,22 @@ techage.recipes.add("ta4_doser", { catalyst = "techage:gibbsite_powder", }) +techage.recipes.add("ta4_doser", { + output = "techage:isobutane 1", + input = { + "techage:gasoline 1", + }, + catalyst = "techage:gibbsite_powder", +}) + +techage.recipes.add("ta4_doser", { + output = "techage:gas 1", + input = { + "techage:isobutane 1", + }, + catalyst = "techage:gibbsite_powder", +}) + -- Hydrogenate techage.recipes.add("ta4_doser", { output = "techage:isobutane 1", diff --git a/techage/items/powder.lua b/techage/items/powder.lua index a75ab61..b5b445e 100644 --- a/techage/items/powder.lua +++ b/techage/items/powder.lua @@ -70,3 +70,21 @@ techage.add_grinder_recipe({input="techage:aluminum", output="techage:aluminum_p techage.add_grinder_recipe({input="default:silver_sandstone", output="techage:silver_sandstone_powder"}) techage.add_grinder_recipe({input="default:coal_lump", output="techage:graphite_powder"}) +if minetest.get_modpath("ethereal") then + techage.add_grinder_recipe({input="ethereal:bush", output="techage:leave_powder"}) + techage.add_grinder_recipe({input="ethereal:bush2", output="techage:leave_powder"}) + techage.add_grinder_recipe({input="ethereal:bush3", output="techage:leave_powder"}) + techage.add_grinder_recipe({input="ethereal:bamboo_leaves", output="techage:leave_powder"}) + techage.add_grinder_recipe({input="ethereal:bananaleaves", output="techage:leave_powder"}) + techage.add_grinder_recipe({input="ethereal:birch_leaves", output="techage:leave_powder"}) + techage.add_grinder_recipe({input="ethereal:frost_leaves", output="techage:leave_powder"}) + techage.add_grinder_recipe({input="ethereal:lemon_leaves", output="techage:leave_powder"}) + techage.add_grinder_recipe({input="ethereal:olive_leaves", output="techage:leave_powder"}) + techage.add_grinder_recipe({input="ethereal:orange_leaves", output="techage:leave_powder"}) + techage.add_grinder_recipe({input="ethereal:palmleaves", output="techage:leave_powder"}) + techage.add_grinder_recipe({input="ethereal:redwood_leaves", output="techage:leave_powder"}) + techage.add_grinder_recipe({input="ethereal:sakura_leaves", output="techage:leave_powder"}) + techage.add_grinder_recipe({input="ethereal:ethereal:sakura_leaves2", output="techage:leave_powder"}) + techage.add_grinder_recipe({input="ethereal:willow_twig", output="techage:leave_powder"}) + techage.add_grinder_recipe({input="ethereal:yellowleaves", output="techage:leave_powder"}) +end diff --git a/techage/items/redstone.lua b/techage/items/redstone.lua index 2008c0f..202e811 100644 --- a/techage/items/redstone.lua +++ b/techage/items/redstone.lua @@ -58,11 +58,13 @@ minetest.register_craft({ }) techage.furnace.register_recipe({ - output = "techage:red_stone", + output = "techage:red_stone 3", recipe = { "techage:canister_redmud", "default:sand", + "default:sand", + "default:sand", }, waste = "techage:ta3_canister_empty", - time = 4, + time = 10, }) diff --git a/techage/items/silicon.lua b/techage/items/silicon.lua index 2eaac4b..95aeea6 100644 --- a/techage/items/silicon.lua +++ b/techage/items/silicon.lua @@ -19,13 +19,27 @@ minetest.register_craftitem("techage:ta4_silicon_wafer", { inventory_image = "techage_silicon_wafer.png", }) -techage.furnace.register_recipe({ - output = "techage:ta4_silicon_wafer 16", - recipe = { - "basic_materials:silicon", - "basic_materials:silicon", - "basic_materials:silicon", - "techage:baborium_ingot" - }, - time = 6, -}) +if minetest.global_exists("mesecon") then + techage.furnace.register_recipe({ + output = "techage:ta4_silicon_wafer 16", + recipe = { + "mesecons_materials:silicon", + "mesecons_materials:silicon", + "mesecons_materials:silicon", + "techage:baborium_ingot" + }, + time = 6, + }) +else + techage.furnace.register_recipe({ + output = "techage:ta4_silicon_wafer 16", + recipe = { + "basic_materials:silicon", + "basic_materials:silicon", + "basic_materials:silicon", + "techage:baborium_ingot" + }, + time = 6, + }) +end + diff --git a/techage/liquids/pump.lua b/techage/liquids/pump.lua index b56cf47..2346099 100644 --- a/techage/liquids/pump.lua +++ b/techage/liquids/pump.lua @@ -60,7 +60,7 @@ local State4 = techage.NodeStates:new({ -- Function returns the number of pumped units local function pump(pos, mem, nvm, state, outdir, units) local taken, name = liquid.take(pos, Pipe, Flip[outdir], nil, units, mem.dbg_cycles > 0) - if taken > 0 then + if taken > 0 and name then local leftover = liquid.put(pos, Pipe, outdir, name, taken, mem.dbg_cycles > 0) if leftover and leftover > 0 then -- air needs no tank diff --git a/techage/locale/techage.de.tr b/techage/locale/techage.de.tr index 22a49a6..9def28a 100644 --- a/techage/locale/techage.de.tr +++ b/techage/locale/techage.de.tr @@ -128,9 +128,15 @@ TA4 Button/Switch=TA4 Schalter/Taster Access=Zugriff Button protection=Tastenschutz +Type=Typ + +### button.lua ### +### button_2x.lua ### +### button_4x.lua ### +### player_detector.lua ### + Command=Kommando Number=Nummer -Type=Typ ### button.lua ### ### cart_detector.lua ### @@ -163,10 +169,15 @@ TA4 2x Button=TA4 2x Taster ### button_4x.lua ### Command to be sent (ignored for switches)=Zu sendender Befehl (wird für Schalter ignoriert) -Destination block number=Zielblocknummer Label for the button=Beschriftung für die Taste Momentary button or on/off switch=Taster oder Ein-/Ausschalter +### button_2x.lua ### +### button_4x.lua ### +### player_detector.lua ### + +Destination block number=Zielblocknummer + ### button_2x.lua ### ### button_4x.lua ### ### signallamp_2x.lua ### @@ -387,7 +398,7 @@ Power=Strom Configurable value@nfor the current limit=Konfigurierbarer Wert@nfür die Strombegrenzung Current limitation=Strombegrenzung Electrolyzer=Eletrolyseur -If the charge of the storage@nsystem exceeds the configured value,@nthe block switches off=Überschreitet die Ladung des@nSpeichersystems den konfigurierten@nWert, schaltet sich der Block ab +If the charge of the storage@nsystem falls below the configured value,@nthe block switches off=unterschreitet die Ladung des@nSpeichersystems den konfigurierten@nWert, schaltet sich der Block ab Maximum possible@ncurrent consumption=Maximal mögliche Stromaufnahme Maximum power consumption [ku]=maximale Stromaufnahme Storage full=Speicher voll @@ -453,7 +464,9 @@ Destination position is protected=Zielposition ist geschützt Error: Max. length of the flight route exceeded by @1 blocks !!=Fehler: max. Länge der Flugstrecke um @1 Blöcke überschritten !! No valid destination position=Keine gültige Zielposition No valid node at the start position=Kein gültiger Block an der Startposition +Running=In Betrieb Start position is protected=Startposition ist geschützt +Stopped=Gestoppt ### fly_lib.lua ### ### flycontroller.lua ### @@ -959,6 +972,10 @@ Plastic Granules=Plastikgranulat ### player_detector.lua ### +Command to send when player is detected=Befehl zum Senden, wenn ein Spieler erkannt wird +Command to send when player moves away=Befehl zum Senden, wenn sich der Spieler wegbewegt +Radius=Radius +Search radius=Suchradius TA4 Player Detector=TA4 Spieler Detektor ### powder.lua ### @@ -1151,12 +1168,14 @@ stopped=gestoppt is a number from 1 to 50000 and is@n= ist eine Nummer von 1 bis 50000 und ist@n @n=@n Commands=Kommandos +Cycle time=Zykluszeit Example:@n=Beispiel: Invalid command!=Ungültiges Kommando! Start=Start Stop=Stopp Syntax:@n=Syntax:@n TA4 Sequencer=TA4 Sequenzer +Timer cycle time (default: 100 ms)=Zykluszeit (normal: 100 ms) running=läuft the timeslot when the command is executed.@n=der Zeitpunkt, wenn der Befehl ausgeführt wird.@n diff --git a/techage/locale/template.txt b/techage/locale/template.txt index 4a2676e..91e06c9 100644 --- a/techage/locale/template.txt +++ b/techage/locale/template.txt @@ -115,7 +115,7 @@ TA3 Booster= Access:= Button or switch= -Change the node name (infotext)= +Change the block name (infotext)= Command to be sent= Destination block number(s)= Infotext= @@ -128,9 +128,15 @@ TA4 Button/Switch= Access= Button protection= +Type= + +### button.lua ### +### button_2x.lua ### +### button_4x.lua ### +### player_detector.lua ### + Command= Number= -Type= ### button.lua ### ### cart_detector.lua ### @@ -163,10 +169,15 @@ TA4 2x Button= ### button_4x.lua ### Command to be sent (ignored for switches)= -Destination block number= Label for the button= Momentary button or on/off switch= +### button_2x.lua ### +### button_4x.lua ### +### player_detector.lua ### + +Destination block number= + ### button_2x.lua ### ### button_4x.lua ### ### signallamp_2x.lua ### @@ -387,7 +398,7 @@ Power= Configurable value@nfor the current limit= Current limitation= Electrolyzer= -If the charge of the storage@nsystem exceeds the configured value,@nthe block switches off= +If the charge of the storage@nsystem falls below the configured value,@nthe block switches off= Maximum possible@ncurrent consumption= Maximum power consumption [ku]= Storage full= @@ -453,7 +464,9 @@ Destination position is protected= Error: Max. length of the flight route exceeded by @1 blocks !!= No valid destination position= No valid node at the start position= +Running= Start position is protected= +Stopped= ### fly_lib.lua ### ### flycontroller.lua ### @@ -959,6 +972,10 @@ Plastic Granules= ### player_detector.lua ### +Command to send when player is detected= +Command to send when player moves away= +Radius= +Search radius= TA4 Player Detector= ### powder.lua ### @@ -1151,12 +1168,14 @@ stopped= is a number from 1 to 50000 and is@n= @n= Commands= +Cycle time= Example:@n= Invalid command!= Start= Stop= Syntax:@n= TA4 Sequencer= +Timer cycle time (default: 100 ms)= running= the timeslot when the command is executed.@n= diff --git a/techage/logic/button.lua b/techage/logic/button.lua index e677b29..0d9b82f 100644 --- a/techage/logic/button.lua +++ b/techage/logic/button.lua @@ -68,10 +68,7 @@ local function switch_on(pos) elseif name == "techage:ta4_button_off" then logic.swap_node(pos, "techage:ta4_button_on") end - 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) + logic.send_cmnd(pos, "command", "on", cycle_time) minetest.sound_play("techage_button", { pos = pos, gain = 0.5, @@ -87,7 +84,7 @@ local function switch_off(pos, is_button) logic.swap_node(pos, "techage:ta4_button_off") end local meta = M(pos) - if meta:get_string("off_command") ~= "true" and + if meta:get_string("off_command") ~= "true" and (not meta:contains("command") or meta:get_string("command") == "on") then logic.send_off(pos, M(pos)) end @@ -117,7 +114,7 @@ local function store_fields_data(pos, fields) local meta = M(pos) meta:set_string("numbers", fields.numbers) meta:set_string("off_command", "") - + if fields.access == "protected" then meta:set_string("protected", "true") meta:set_string("public", "") diff --git a/techage/logic/lib.lua b/techage/logic/lib.lua index 248c3ff..83165f8 100644 --- a/techage/logic/lib.lua +++ b/techage/logic/lib.lua @@ -67,13 +67,16 @@ function techage.logic.send_on(pos, meta, time) return own_num == numbers end -function techage.logic.send_cmnd(pos, meta, cmnd, payload, time) +function techage.logic.send_cmnd(pos, ident, default, time) + local meta = M(pos) + local s = meta:contains(ident) and meta:get_string(ident) or default + local command, payload = unpack(string.split(s, " ", false, 1)) 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) + techage.send_multi(own_num, numbers, command, payload) end function techage.logic.send_off(pos, meta) diff --git a/techage/logic/player_detector.lua b/techage/logic/player_detector.lua index f189185..e234b06 100644 --- a/techage/logic/player_detector.lua +++ b/techage/logic/player_detector.lua @@ -20,15 +20,48 @@ local NDEF = function(pos) return (minetest.registered_nodes[techage.get_node_lv local logic = techage.logic local CYCLE_TIME = 1 +local WRENCH_MENU = { + { + type = "dropdown", + choices = "1,2,3,4,5,6,7,8", + name = "radius", + label = S("Radius"), + tooltip = S("Search radius"), + default = "4", + }, + { + type = "numbers", + name = "numbers", + label = S("Number"), + tooltip = S("Destination block number"), + default = "", + check = techage.check_numbers, + }, + { + type = "ascii", + name = "command1", + label = "On " .. S("Command"), + tooltip = S("Command to send when player is detected"), + default = "on", + }, + { + type = "ascii", + name = "command2", + label = "Off " .. S("Command"), + tooltip = S("Command to send when player moves away"), + default = "off", + }, +} + local function switch_on(pos, stage) if logic.swap_node(pos, "techage:ta"..stage.."_playerdetector_on") then - logic.send_on(pos, M(pos)) + logic.send_cmnd(pos, "command1", "on") end end local function switch_off(pos, stage) if logic.swap_node(pos, "techage:ta"..stage.."_playerdetector_off") then - logic.send_off(pos, M(pos)) + logic.send_cmnd(pos, "command2", "off") end end @@ -36,7 +69,8 @@ local function scan_for_player(pos) local nvm = techage.get_nvm(pos) local meta = minetest.get_meta(pos) local names = meta:get_string("names") or "" - for _, object in pairs(minetest.get_objects_inside_radius(pos, 4)) do + local radius = meta:contains("radius") and meta:get_int("radius") or 4 + for _, object in pairs(minetest.get_objects_inside_radius(pos, radius)) do if object:is_player() then if names == "" then nvm.player_name = object:get_player_name() @@ -228,6 +262,7 @@ minetest.register_node("techage:ta4_playerdetector_off", { techage.del_mem(pos) end, + ta4_formspec = WRENCH_MENU, paramtype = "light", sunlight_propagates = true, paramtype2 = "facedir", @@ -277,6 +312,7 @@ minetest.register_node("techage:ta4_playerdetector_on", { techage.del_mem(pos) end, + ta4_formspec = WRENCH_MENU, paramtype = "light", sunlight_propagates = true, paramtype2 = "facedir", diff --git a/techage/manuals/manual_ta1_DE.md b/techage/manuals/manual_ta1_DE.md index e602081..4811439 100644 --- a/techage/manuals/manual_ta1_DE.md +++ b/techage/manuals/manual_ta1_DE.md @@ -17,13 +17,22 @@ Die Haltbarkeit/Härte bspw. für eine Axt ist: Den Köhler brauchst du, um Holzkohle herzustellen. Holzkohle wird für den Brenner, aber auch bspw. in TA2 für die Dampfmaschine benötigt. +Für den Köhler brauchst du: + +- einen Anzünderblock (`techage:lighter`) +- 26 Hölzblöcke (wood), die zu einem Würfen aufgeschichtet werden. Die Holzsorte spielt keine Rolle +- Erde (dirt) um den Holzhaufen abzudecken +- Flint and Iron (technischer Name: `fire:flint_and_steel`) um den Anzünderblock anzuzünden + + + Bauanleitung (siehe auch Plan): - Baue eine 5x5 große Fläche aus Erde (dirt) - Platziere in die Mitte einen Anzünder (lighter) -- Baue aus Holz (wood) einen 3x3x3 großen Würfel darüber -- Überdecke alles mit einer Schicht Erde zu einem 5x5x5 großen Würfel -- Lasse ein Loch zum Anzünder +- Platziere rund um den Anzünder 7 Holz (wood), aber lasse ein Loch zum Anzünder frei +- Baue weitere 2 Schichten Holz darüber, so dass ein 3x3x3 großen Holzwürfel entsteht +- Überdecke alles mit einer Schicht Erde zu einem 5x5x5 großen Würfel, aber lasse das Loch zum Anzünder frei - Zünde den Anzünder an und verschließe das Loch sofort mit jeweils einem Block Holz und Erde - Wenn du alles richtig gemacht hast, beginnt der Köhler nach wenigen Sekunden an zu rauchen - Öffne den Köhler erst, wenn der Rauch verschwunden ist (ca. 20 min) diff --git a/techage/manuals/manual_ta1_EN.md b/techage/manuals/manual_ta1_EN.md index 79e2ccf..41dada3 100644 --- a/techage/manuals/manual_ta1_EN.md +++ b/techage/manuals/manual_ta1_EN.md @@ -17,13 +17,21 @@ The durability / hardness for an axe, for example: You need the Charcoal Pile to make charcoal. Charcoal is required for the melting furnace, but also, for example, in TA2 for the steam engine. +For the charcoal burner you need: + +- a lighter block (`techage:lighter`) +- 26 wooden blocks that are stacked into a pile of wood. The type of wood is irrelevant +- Dirt to cover the pile of wood +- Flint and Iron (technical name: `fire:flint_and_steel`) to light the lighter block + + + Building instructions (see also plan): -- Build a 5x5 area of ​​dirt -- Place a lighter in the middle -- Build a 3x3x3 cube above it out of wood -- Cover everything with a layer of dirt to form a 5x5x5 cube -- Leave a hole to the lighter +- Build a 5x5 area of dirt +- Place 7 wood around the lighter but leave a hole to the lighter +- Build another 2 layers of wood on top, making a 3x3x3 wooden cube +- Cover everything with a layer of dirt into a 5x5x5 cube, but keep the hole to the lighter open - Light the lighter and immediately close the hole with a block of wood and dirt - If you have done everything correctly, the coal burner will start smoking after a few seconds - Only open the charcoal burner when the smoke has disappeared (approx. 20 min) diff --git a/techage/manuals/manual_ta4_DE.md b/techage/manuals/manual_ta4_DE.md index e12d10c..f17e60c 100644 --- a/techage/manuals/manual_ta4_DE.md +++ b/techage/manuals/manual_ta4_DE.md @@ -258,6 +258,8 @@ In den Elektrolyseur passen 200 Einheiten Wasserstoff. Der Elektrolyseur besitzt ein Schraubenschlüssel-Menü zur Einstellung der Stromaufnahme und des Abschaltpunkts. +Unterschreitet die im Stromnetz gespeicherte Leistung den angegebenen Wert des Abschaltpunkts, so schaltet sich der Elektrolyseur automatisch ab. Damit kann ein Leerlaufen der Speichersysteme verhindert werden. + [ta4_electrolyzer|image] @@ -279,15 +281,17 @@ In diesem Fall können keine anderen Blöcke der Kategorie 2 wie der Akku-Block Der Reaktor dient dazu, die über den Destillationsturm oder aus anderen Rezepten gewonnenen Zutaten zu neuen Produkten weiter zu verarbeiten. Der Plan links zeigt nur eine mögliche Variante, da die Anordnung der Silos und Tanks rezeptabhängig ist. +Das primäre Ausgabeprodukt wird immer an der Seite des Reaktorständers ausgegeben, unabhängig davon, ob es sich um ein Pulver oder eine Flüssigkeit handelt. Das (sekundäre) Abfallprodukt wird immer unten am Reaktorständers ausgegeben. + Ein Reaktor besteht aus: - div. Tanks und Silos mit den Zutaten, die über Leitungen mit dem Dosierer verbunden sind -- optional einem Reaktorsockel, welcher die Abfälle aus dem Reaktor ableitet (nur bei Rezepten mit zwei Ausgangsstoffen notwendig) +- optional einem Reaktorsockel, welcher die Abfälle aus dem Reaktor ableitet (nur bei Rezepten mit zwei Ausgabestoffen notwendig) - dem Reaktorständer, der auf den Sockel gesetzt werden muss (sofern vorhanden). Der Ständer hat einen Stromanschluss und zieht bei Betrieb 8 ku. - dem eigentlichen Reaktorbehälter, der auf den Reaktorständer gesetzt werden muss - dem Einfüllstutzen der auf den Reaktorbehälter gesetzt werden muss - dem Dosierer, welcher über Leitungen mit den Tanks oder Silos sowie dem Einfüllstutzen verbunden werden muss -Hinweis 1: Flüssigkeiten werden nur in Tanks gelagert, feste Stoffe und Stoffe in Pulverform nur in Silos. Dies gilt für Zutaten und Ausgangsstoffe. +Hinweis 1: Flüssigkeiten werden nur in Tanks gelagert, feste Stoffe und Stoffe in Pulverform nur in Silos. Dies gilt für Zutaten und Ausgabestoffe. Hinweis 2: Tanks oder Silos mit verschiedenen Inhalten dürfen nicht zu einem Leitungssystem verbunden werden. Mehrere Tanks oder Silos mit gleichem Inhalt dürfen dagegen parallel an einer Leitung hängen. @@ -310,7 +314,7 @@ Auf allen 4 Seiten der Dosierers können Leitungen für Eingangsmaterialien ange Wie auch bei anderen Maschinen: - geht der Dosierer in den standby Zustand, so fehlen ein oder mehrere Zutaten -- geht der Dosierer in den blocked Zustand, so ist Ausgangstank oder Silo voll, defekt oder falsch angeschlossen +- geht der Dosierer in den blocked Zustand, so ist Ausgabetank oder Silo voll, defekt oder falsch angeschlossen Der Dosierer benötigt keinen Strom. Alle 10 s wird ein Rezept abgearbeitet. @@ -335,7 +339,7 @@ Teil des Chemischen Reaktors. Muss auf den Reaktor gesetzt werden. Wenn dies nic Teil des Chemischen Reaktors. Hier ist auch der Stromanschluss für den Reaktor. Der Reaktor benötigt 8 ku Strom. -Der Ständer hat zwei Leitungsanschlüsse, nach rechst für das Ausgangsprodukt und nach unten für den Abfall, wie bspw. Rotschlamm bei der Aluminiumherstellung. +Der Ständer hat zwei Leitungsanschlüsse, nach rechst für das primäre Ausgabeprodukt und nach unten für den Abfall, wie bspw. Rotschlamm bei der Aluminiumherstellung. [ta4_reactorstand|image] @@ -583,6 +587,12 @@ Der Move Controller unterstützt folgende techage Kommandos: - `b2a` Bewege Block von B nach A - `move` Bewege Block auf die andere Seite +Über das Schraubenschlüssel-Menü kann auf die Betriebsart `move xyz` umgeschaltet werden. Nach der Umschaltung werden folgende techage Kommandos unterstützt: + +- `move2` Beim Kommando muss zusätzlich die Flugstrecke als x,y,z Vektor angegeben werden. + Beispiel Lua Controller: `$send_cmnd(MOVE_CTLR, "move2", "0,12,0")` +- `reset` Block/Blöcke zurück in Startposition bewegen + **Wichtige Hinweise:** - Sofern mehrere Blöcke bewegt werden sollen, muss der Block, der die Spieler/Mobs mitnehmen soll, beim Antrainieren als erstes angeklickt werden. @@ -973,4 +983,4 @@ Die Verarbeitungsleistung beträgt ein Item alle 8 s. Der Block benötigt hierf Die Funktion entspricht der von TA3. -[ta4_item_flow_limiter_pas|image] \ No newline at end of file +[ta4_item_flow_limiter_pas|image] diff --git a/techage/manuals/manual_ta4_EN.md b/techage/manuals/manual_ta4_EN.md index e6ef62b..9464e59 100644 --- a/techage/manuals/manual_ta4_EN.md +++ b/techage/manuals/manual_ta4_EN.md @@ -251,6 +251,8 @@ The electrolyzer can draw up to 35 ku of electricity and then generates a hydrog The electrolyzer has a wrench menu for setting the current consumption and the switch-off point. +If the power stored in the power grid falls below the specified value of the switch-off point, the electrolyzer switches off automatically. This prevents the storage systems from running empty. + [ta4_electrolyzer|image] @@ -272,15 +274,17 @@ In this case, no other category 2 blocks such as the battery block can be charge The reactor is used to process the ingredients obtained from the distillation tower or from other recipes into new products. The plan on the left shows only one possible variant, since the arrangement of the silos and tanks depends on the recipe. +The primary output product is always output to the side of the reactor stand, regardless of whether it is a powder or a liquid. The (secondary) waste product is always discharged at the bottom of the reactor stand. + A reactor consists of: - Various tanks and silos with the ingredients that are connected to the doser via pipes -- optionally a reactor base, which discharges the waste from the reactor (only necessary for recipes with two starting materials) +- optionally a reactor base, which discharges the waste from the reactor (only necessary for recipes with two output products) - the reactor stand, which must be placed on the base (if available). The stand has a power connection and draws 8 ku during operation. - The reactor vessel that has to be placed on the reactor stand - The filler pipe that must be placed on the reactor vessel - The dosing device, which has to be connected to the tanks or silos and the filler pipe via pipes -Note 1: Liquids are only stored in tanks, solids and substances in powder form only in silos. This applies to ingredients and raw materials. +Note 1: Liquids are only stored in tanks, solids and substances in powder form only in silos. This applies to ingredients and output products. Note 2: Tanks or silos with different contents must not be connected to a pipe system. In contrast, several tanks or silos with the same content may hang in parallel on one line. @@ -304,7 +308,7 @@ The recipe can be set and the reactor started via the doser. As with other machines: - if the doser is in standby mode, one or more ingredients are missing -- if the doser is in the blocked state, the outlet tank or silo is full, defective or incorrectly connected +- if the doser is in the blocked state, the output tank or silo is full, defective or incorrectly connected The doser does not need any electricity. A recipe is processed every 10 s. @@ -574,6 +578,12 @@ The Move Controller supports the following techage commands: - `b2a` Move block from B to A. - `move` Move block to the other side +You can switch to the `move xyz` operating mode via the wrench menu. After switching, the following techage commands are supported: + +- `move2` With the command, the flight route must also be specified as an x,y,z vector. + Example Lua Controller: `$send_cmnd(MOVE_CTLR, "move2", "0,12,0")` +- `reset` move block(s) back to start position + **Important instructions:** - If several blocks are to be moved, the block that is to take the players/mobs must be clicked first when training. diff --git a/techage/manuals/manual_ta5_DE.md b/techage/manuals/manual_ta5_DE.md index 29f1124..80bb36b 100644 --- a/techage/manuals/manual_ta5_DE.md +++ b/techage/manuals/manual_ta5_DE.md @@ -158,4 +158,10 @@ Für die Nutzung des TA5 Containers werden 80 Erfahrungspunkte benötigt. Der TA5 KI Chip wird teilweise zur Herstellung von TA5 Blöcken benötigt. Der TA5 KI Chip kann nur auf der TA4 Elektronik Fab hergestellt werden. Dazu werden 10 Erfahrungspunkte benötigt. -[ta5_aichip|image] \ No newline at end of file +[ta5_aichip|image] + +### TA5 KI Chip II / TA5 AI Chip II + +Der TA5 KI Chip II wird zur Herstellung des TA5 Fusionsreaktors benötigt. Der TA5 KI Chip II kann nur auf der TA4 Elektronik Fab hergestellt werden. Dazu werden 50 Erfahrungspunkte benötigt. + +[ta5_aichip2|image] \ No newline at end of file diff --git a/techage/manuals/manual_ta5_EN.md b/techage/manuals/manual_ta5_EN.md index fea4a84..83e0cad 100644 --- a/techage/manuals/manual_ta5_EN.md +++ b/techage/manuals/manual_ta5_EN.md @@ -158,4 +158,10 @@ The TA5 container allows Techage systems to be packed and unpacked at another lo The TA5 AI Chip is partly required for the production of TA5 blocks. The TA5 AI Chip can only be manufactured at the TA4 Electronics Fab. This requires 10 experience points. -[ta5_aichip|image] \ No newline at end of file +[ta5_aichip|image] + +### TA5 AI Chip II + +The TA5 AI Chip II is required to build the TA5 Fusion Reactor. The TA5 AI Chip II can only be manufactured at the TA4 Electronics Fab. This requires 50 experience points. + +[ta5_aichip2|image] diff --git a/techage/manuals/markdown2formspec.py b/techage/manuals/markdown2formspec.py index 230dfe6..f2ea613 100644 --- a/techage/manuals/markdown2formspec.py +++ b/techage/manuals/markdown2formspec.py @@ -5,7 +5,7 @@ import re import sys import pprint -import mistune # must be v0.8.4 +import mistune # must be v0.8.4, install with 'sudo pip install mistune==0.8.4' def formspec_escape(text): text = text.replace("\\", "") diff --git a/techage/manuals/ta4_lua_controller_EN.md b/techage/manuals/ta4_lua_controller_EN.md index 5387272..11b9e71 100644 --- a/techage/manuals/ta4_lua_controller_EN.md +++ b/techage/manuals/ta4_lua_controller_EN.md @@ -406,7 +406,7 @@ Please note, that this is not a technical distinction, only a logical. | "a2b" | nil | TA4 Move Controller command to move the block(s) from position A to B | | "b2a" | nil | TA4 Move Controller command to move the block(s) from position B to A | | "move" | nil | TA4 Move Controller command to move the block(s) to the opposite position | -| "move2" | x,y,z | TA4 Move Controller command to move the block(s) by the given
x/y/z-distance. Valid ranges for x, y, and z are -100 to 100. | +| "move2" | x,y,z | TA4 Move Controller command to move the block(s) by the given
x/y/z-distance. Valid ranges for x, y, and z are -100 to 100.
Example: `$send_cmnd("1674", "move2", "0,4,0")` | | "reset" | nil | Reset TA4 Move Controller (move block(s) to start position) | | "left" | nil | TA4 Turn Controller command to turn the block(s) to the left | | "right" | nil | TA4 Turn Controller command to turn the block(s) to the right | diff --git a/techage/manuals/toc_DE.md b/techage/manuals/toc_DE.md index 075b6aa..808b9b3 100644 --- a/techage/manuals/toc_DE.md +++ b/techage/manuals/toc_DE.md @@ -252,4 +252,5 @@ - [Hyperloop Teleport Blöcke (geplant)](./manual_ta5_DE.md#hyperloop-teleport-blöcke-(geplant)) - [Weitere TA5 Blöcke/Items](./manual_ta5_DE.md#weitere-ta5-blöckeitems) - [TA5 Container (geplant)](./manual_ta5_DE.md#ta5-container-(geplant)) - - [TA5 KI Chip / TA5 AI Chip](./manual_ta5_DE.md#ta5-ki-chip--ta5-ai-chip) \ No newline at end of file + - [TA5 KI Chip / TA5 AI Chip](./manual_ta5_DE.md#ta5-ki-chip--ta5-ai-chip) + - [TA5 KI Chip II / TA5 AI Chip II](./manual_ta5_DE.md#ta5-ki-chip-ii--ta5-ai-chip-ii) \ No newline at end of file diff --git a/techage/manuals/toc_EN.md b/techage/manuals/toc_EN.md index 1e9d6d9..fc0e3a2 100644 --- a/techage/manuals/toc_EN.md +++ b/techage/manuals/toc_EN.md @@ -252,4 +252,5 @@ - [Hyperloop Teleport Blocks (planned)](./manual_ta5_EN.md#hyperloop-teleport-blocks-(planned)) - [More TA5 Blocks/Items](./manual_ta5_EN.md#more-ta5-blocksitems) - [TA5 Container (planned)](./manual_ta5_EN.md#ta5-container-(planned)) - - [TA5 AI Chip](./manual_ta5_EN.md#ta5-ai-chip) \ No newline at end of file + - [TA5 AI Chip](./manual_ta5_EN.md#ta5-ai-chip) + - [TA5 AI Chip II](./manual_ta5_EN.md#ta5-ai-chip-ii) \ No newline at end of file diff --git a/techage/mod.conf b/techage/mod.conf index 2d39f99..0fa5481 100644 --- a/techage/mod.conf +++ b/techage/mod.conf @@ -1,4 +1,4 @@ name = techage depends = default,doors,flowers,tubelib2,networks,basic_materials,bucket,stairs,screwdriver,minecart,lcdlib,safer_lua -optional_depends = unified_inventory,wielded_light,unifieddyes,moreores,ethereal,mesecons,digtron,bakedclay,moreblocks,i3,creative,craftguide +optional_depends = unified_inventory,wielded_light,unifieddyes,moreores,ethereal,mesecons,mesecons_materials,mesecons_mvps,digtron,bakedclay,moreblocks,i3,creative,craftguide description = Techage, go through 5 tech ages in search of wealth and power! diff --git a/techage/move_controller/doorcontroller2.lua b/techage/move_controller/doorcontroller2.lua index 48aa46d..83ffbee 100644 --- a/techage/move_controller/doorcontroller2.lua +++ b/techage/move_controller/doorcontroller2.lua @@ -17,9 +17,8 @@ local M = minetest.get_meta local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end local S = techage.S -local MP = minetest.get_modpath("techage") -local flylib = dofile(MP .. "/basis/fly_lib.lua") local logic = techage.logic +local fly = techage.flylib local MarkedNodes = {} -- t[player] = {{entity, pos},...} local CurrentPos -- to mark punched entities @@ -141,9 +140,9 @@ local function exchange_node(pos, item, param2) local node = minetest.get_node_or_nil(pos) if node and is_simple_node(node.name) then if item and item:get_name() ~= "" and minetest.registered_nodes[item:get_name()] then - flylib.exchange_node(pos, item:get_name(), param2) + fly.exchange_node(pos, item:get_name(), param2) else - flylib.remove_node(pos) + fly.remove_node(pos) end if not techage.is_air_like(node.name) then return ItemStack(node.name), node.param2 @@ -439,7 +438,7 @@ local Doors = { for _, name in ipairs(Doors) do for _, postfix in ipairs({"a", "b", "c", "d"}) do techage.register_simple_nodes({name .. "_" .. postfix}, true) - flylib.protect_door_from_being_opened(name .. "_" .. postfix) + fly.protect_door_from_being_opened(name .. "_" .. postfix) end end @@ -453,6 +452,6 @@ local ProtectorDoors = { for _, name in ipairs(ProtectorDoors) do for _, postfix in ipairs({"b_1", "b_2", "t_1", "t_2"}) do techage.register_simple_nodes({name .. "_" .. postfix}, true) - flylib.protect_door_from_being_opened(name .. "_" .. postfix) + fly.protect_door_from_being_opened(name .. "_" .. postfix) end end diff --git a/techage/move_controller/flycontroller.lua b/techage/move_controller/flycontroller.lua index 36354ff..6e56c49 100644 --- a/techage/move_controller/flycontroller.lua +++ b/techage/move_controller/flycontroller.lua @@ -19,8 +19,8 @@ local S2P = minetest.string_to_pos local S = techage.S local MP = minetest.get_modpath("techage") -local fly = dofile(MP .. "/basis/fly_lib.lua") local mark = dofile(MP .. "/basis/mark_lib.lua") +local fly = techage.flylib local MAX_DIST = 500 local MAX_BLOCKS = 16 diff --git a/techage/move_controller/movecontroller.lua b/techage/move_controller/movecontroller.lua index 2f795f3..caf29af 100644 --- a/techage/move_controller/movecontroller.lua +++ b/techage/move_controller/movecontroller.lua @@ -19,8 +19,8 @@ local S2P = minetest.string_to_pos local S = techage.S local MP = minetest.get_modpath("techage") -local fly = dofile(MP .. "/basis/fly_lib.lua") local mark = dofile(MP .. "/basis/mark_lib.lua") +local fly = techage.flylib local MAX_DIST = 200 local MAX_BLOCKS = 16 @@ -40,7 +40,7 @@ local WRENCH_MENU = { label = S("Handover to B"), tooltip = S("Number of the next movecontroller"), default = "", - check = techage.check_numbers, + check = techage.check_number, }, { type = "number", @@ -48,7 +48,7 @@ local WRENCH_MENU = { label = S("Handover to A"), tooltip = S("Number of the previous movecontroller"), default = "", - check = techage.check_numbers, + check = techage.check_number, }, { type = "float", @@ -131,6 +131,7 @@ minetest.register_node("techage:ta4_movecontroller", { nvm.lpos2 = {} nvm.moveBA = false nvm.running = nil + nvm.lastpos = nil 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")) @@ -144,6 +145,7 @@ minetest.register_node("techage:ta4_movecontroller", { end local text = #pos_list.." "..S("block positions are stored.") nvm.running = nil + nvm.lastpos = nil meta:set_string("status", text) nvm.lpos1 = pos_list mark.unmark_all(name) @@ -161,11 +163,10 @@ minetest.register_node("techage:ta4_movecontroller", { mark.stop(name) nvm.moveBA = false nvm.running = nil + nvm.lastpos = nil elseif fields.moveAB then meta:set_string("status", "") if fly.move_to_other_pos(pos, false) then - nvm.moveBA = true - nvm.running = true meta:set_string("formspec", formspec(nvm, meta)) local name = player:get_player_name() mark.stop(name) @@ -174,8 +175,6 @@ minetest.register_node("techage:ta4_movecontroller", { elseif fields.moveBA then meta:set_string("status", "") if fly.move_to_other_pos(pos, true) then - nvm.moveBA = false - nvm.running = true meta:set_string("formspec", formspec(nvm, meta)) local name = player:get_player_name() mark.stop(name) @@ -187,11 +186,9 @@ minetest.register_node("techage:ta4_movecontroller", { end local line = fly.to_vector(meta:get_string("path"), MAX_DIST) if line then - nvm.running = true fly.move_to(pos, line) end elseif fields.reset then - nvm.running = true fly.reset_move(pos) end end, @@ -230,28 +227,18 @@ techage.register_node({"techage:ta4_movecontroller"}, { elseif topic == "state" then return nvm.running and "running" or "stopped" elseif not move_xyz and topic == "a2b" then - nvm.moveBA = true - nvm.running = true return fly.move_to_other_pos(pos, false) elseif not move_xyz and topic == "b2a" then - nvm.moveBA = false - nvm.running = true return fly.move_to_other_pos(pos, true) elseif not move_xyz and topic == "move" then - nvm.moveBA = nvm.moveBA == false - nvm.running = true return fly.move_to_other_pos(pos, nvm.moveBA == false) elseif move_xyz and topic == "move2" then local line = fly.to_vector(payload, MAX_DIST) if line then - nvm.running = true - nvm.controller_mode = true return fly.move_to(pos, line) end return false elseif topic == "reset" then - nvm.running = true - nvm.controller_mode = true return fly.reset_move(pos) end return false @@ -262,16 +249,10 @@ techage.register_node({"techage:ta4_movecontroller"}, { --print("on_beduino_receive_cmnd", P2S(pos), move_xyz, topic, payload[1]) if not move_xyz and topic == 11 then if payload[1] == 1 then - nvm.moveBA = true - nvm.running = true return fly.move_to_other_pos(pos, false) and 0 or 3 elseif payload[1] == 2 then - nvm.moveBA = false - nvm.running = true return fly.move_to_other_pos(pos, true) and 0 or 3 elseif payload[1] == 3 then - nvm.moveBA = nvm.moveBA == false - nvm.running = true return fly.move_to_other_pos(pos, nvm.moveBA == false) and 0 or 3 end elseif move_xyz and topic == 18 then -- move xyz @@ -280,12 +261,8 @@ techage.register_node({"techage:ta4_movecontroller"}, { y = techage.in_range(techage.beduino_signed_var(payload[2]), -100, 100), z = techage.in_range(techage.beduino_signed_var(payload[3]), -100, 100), } - nvm.running = true - nvm.controller_mode = true return fly.move_to(pos, line) and 0 or 3 elseif move_xyz and topic == 19 then -- reset - nvm.running = true - nvm.controller_mode = true return fly.reset_move(pos) and 0 or 3 else return 2 @@ -298,6 +275,10 @@ techage.register_node({"techage:ta4_movecontroller"}, { end return 2, "" end, + on_node_load = function(pos, node) + local nvm = techage.get_nvm(pos) + nvm.running = false + end, }) minetest.register_craft({ diff --git a/techage/move_controller/turncontroller.lua b/techage/move_controller/turncontroller.lua index 33a3b56..2dc9588 100644 --- a/techage/move_controller/turncontroller.lua +++ b/techage/move_controller/turncontroller.lua @@ -19,8 +19,8 @@ local S2P = minetest.string_to_pos local S = techage.S local MP = minetest.get_modpath("techage") -local fly = dofile(MP .. "/basis/fly_lib.lua") local mark = dofile(MP .. "/basis/mark_lib.lua") +local fly = techage.flylib local MAX_BLOCKS = 16 diff --git a/towercrane/init.lua b/towercrane/init.lua index 71f20fb..9271659 100644 --- a/towercrane/init.lua +++ b/towercrane/init.lua @@ -229,7 +229,7 @@ local function build_crane_up(pos, owner, height, width) ", "..S("Crane size")..": "..height..","..width) meta:set_string("formspec", formspec(height, width)) else - chat(owner, S("Area is protected or too less space for the crane!")) + chat(owner, S("Area is protected or not enough space for the crane!")) end end else diff --git a/towercrane/locale/template.txt b/towercrane/locale/template.txt new file mode 100644 index 0000000..8e1f253 --- /dev/null +++ b/towercrane/locale/template.txt @@ -0,0 +1,16 @@ +# textdomain: towercrane +Area is protected.= +Tower Crane Mast Ctrl On= +Switch crane on/off= +Tower Crane Mast Ctrl Off= +Construction area size= +Build= +Owner= +Crane size= +Area is protected or too less space for the crane!= +Invalid input!= +Tower Crane Base= +Tower Crane Balance= +Tower Crane Mast= +Tower Crane Arm= +Tower Crane Arm2= diff --git a/towercrane/locale/towercrane.eo.tr b/towercrane/locale/towercrane.eo.tr new file mode 100644 index 0000000..f410a2d --- /dev/null +++ b/towercrane/locale/towercrane.eo.tr @@ -0,0 +1,16 @@ +# textdomain: towercrane +Area is protected.=Areo estas protektita. +Tower Crane Mast Ctrl On=Turgruomasta Kontrolo Enŝaltita +Switch crane on/off=Ŝaltu/malŝaltu gruon +Tower Crane Mast Ctrl Off=Turgruomasta Kontrolo Malŝaltita +Construction area size=Konstrua area grandeco +Build=Konstruita +Owner=Posedanto +Crane size=Gruo grandeco +Area is protected or not enough space for the crane!=Areo estas protektita aŭ ne sufice da spaco por la gruo! +Invalid input!=Nevalida enigo! +Tower Crane Base=Bazo de Turgruo +Tower Crane Balance=Ekvilibro de Turgruo +Tower Crane Mast=Masto de Turgruo +Tower Crane Arm=Brako de Turgruo +Tower Crane Arm2=Brako2 de Turgruo diff --git a/tubelib2/internal2.lua b/tubelib2/internal2.lua index 5a641d0..ff1ec85 100644 --- a/tubelib2/internal2.lua +++ b/tubelib2/internal2.lua @@ -249,7 +249,7 @@ function Tube:determine_tube_dirs(pos, preferred_pos, fdir) if friendly then local v = vector.direction(pos, preferred_pos) local dir1 = self:vector_to_dir(v) - local dir2 = Turn180Deg[fdir] + local dir2 = fdir < 5 and Turn180Deg[fdir] or fdir return dir1, dir2, 1 end end diff --git a/tubelib2/locale/tubelib2.de.tr b/tubelib2/locale/tubelib2.de.tr index b41fa5e..4eb4924 100644 --- a/tubelib2/locale/tubelib2.de.tr +++ b/tubelib2/locale/tubelib2.de.tr @@ -1,7 +1,7 @@ # textdomain: tubelib2 Not connected!=Nicht verbunden! Paired with @1=Gepaart mit @1 -Connected to @1=erbunden mit @1 +Connected to @1=Verbunden mit @1 Maximum length reached!=Maximale Länge erreicht! Pairing is missing=Das Pairing fehlt Connection to a tube is missing!=Eine Verbindung zu einer Röhre fehlt! diff --git a/tubelib2/locale/tubelib2.zh_CN.tr b/tubelib2/locale/tubelib2.zh_CN.tr new file mode 100644 index 0000000..57686ee --- /dev/null +++ b/tubelib2/locale/tubelib2.zh_CN.tr @@ -0,0 +1,8 @@ +# textdomain: tubelib2 +Not connected!=未连接! +Paired with @1=与@1配对 +Connected to @1=已连接到 @1 +Maximum length reached!=已达到最大长度! +Pairing is missing=配对缺失 +Connection to a tube is missing!=管道连接缺失! +Pairing is missing (@1)=配对缺失 (@1) diff --git a/tubelib2/locale/tubelib2.zh_TW.tr b/tubelib2/locale/tubelib2.zh_TW.tr new file mode 100644 index 0000000..b2078b7 --- /dev/null +++ b/tubelib2/locale/tubelib2.zh_TW.tr @@ -0,0 +1,8 @@ +# textdomain: tubelib2 +Not connected!=未連接! +Paired with @1=與@1配對 +Connected to @1=已連接到 @1 +Maximum length reached!=已達到最大長度! +Pairing is missing=配對缺失 +Connection to a tube is missing!=管道連接缺失! +Pairing is missing (@1)=配對缺失 (@1) diff --git a/unified_inventory/api.lua b/unified_inventory/api.lua index 1609217..e4b67fa 100644 --- a/unified_inventory/api.lua +++ b/unified_inventory/api.lua @@ -2,40 +2,49 @@ local S = minetest.get_translator("unified_inventory") local F = minetest.formspec_escape local ui = unified_inventory +local function is_recipe_craftable(recipe) + -- Ensure the ingedients exist + for _, itemname in pairs(recipe.items) do + local groups = string.find(itemname, "group:") + if groups then + if not ui.get_group_item(string.sub(groups, 8)).item then + return false + end + else + -- Possibly an item + if not minetest.registered_items[itemname] + or minetest.get_item_group(itemname, "not_in_craft_guide") ~= 0 then + return false + end + end + end + return true +end + -- Create detached creative inventory after loading all mods minetest.after(0.01, function() local rev_aliases = {} - for source, target in pairs(minetest.registered_aliases) do - if not rev_aliases[target] then rev_aliases[target] = {} end - table.insert(rev_aliases[target], source) + for original, newname in pairs(minetest.registered_aliases) do + if not rev_aliases[newname] then + rev_aliases[newname] = {} + end + table.insert(rev_aliases[newname], original) end + + -- Filtered item list ui.items_list = {} for name, def in pairs(minetest.registered_items) do - if (not def.groups.not_in_creative_inventory or - def.groups.not_in_creative_inventory == 0) and - def.description and def.description ~= "" then + if ui.is_itemdef_listable(def) then table.insert(ui.items_list, name) + + -- Alias processing: Find recipes that belong to the current item name local all_names = rev_aliases[name] or {} table.insert(all_names, name) - for _, player_name in ipairs(all_names) do - local recipes = minetest.get_all_craft_recipes(player_name) - if recipes then - for _, recipe in ipairs(recipes) do - - local unknowns - - for _,chk in pairs(recipe.items) do - local groupchk = string.find(chk, "group:") - if (not groupchk and not minetest.registered_items[chk]) - or (groupchk and not ui.get_group_item(string.gsub(chk, "group:", "")).item) - or minetest.get_item_group(chk, "not_in_craft_guide") ~= 0 then - unknowns = true - end - end - - if not unknowns then - ui.register_craft(recipe) - end + for _, itemname in ipairs(all_names) do + local recipes = minetest.get_all_craft_recipes(itemname) + for _, recipe in ipairs(recipes or {}) do + if is_recipe_craftable(recipe) then + ui.register_craft(recipe) end end end @@ -44,6 +53,8 @@ minetest.after(0.01, function() table.sort(ui.items_list) ui.items_list_size = #ui.items_list print("Unified Inventory. Inventory size: "..ui.items_list_size) + + -- Analyse dropped items -> custom "digging" recipes for _, name in ipairs(ui.items_list) do local def = minetest.registered_items[name] -- Simple drops @@ -201,8 +212,8 @@ minetest.after(0.01, function() end end) +---------------- Home API ---------------- --- load_home local function load_home() local input = io.open(ui.home_filename, "r") if not input then @@ -219,6 +230,7 @@ local function load_home() end io.close(input) end + load_home() function ui.set_home(player, pos) @@ -247,7 +259,8 @@ function ui.go_home(player) return false end --- register_craft +---------------- Crafting API ---------------- + function ui.register_craft(options) if not options.output then return @@ -270,14 +283,12 @@ function ui.register_craft(options) end end - local craft_type_defaults = { width = 3, height = 3, uses_crafting_grid = false, } - function ui.craft_type_defaults(name, options) if not options.description then options.description = name @@ -288,8 +299,7 @@ end function ui.register_craft_type(name, options) - ui.registered_craft_types[name] = - ui.craft_type_defaults(name, options) + ui.registered_craft_types[name] = ui.craft_type_defaults(name, options) end @@ -346,6 +356,8 @@ ui.register_craft_type("digging_chance", { height = 1, }) +---------------- GUI registrations ---------------- + function ui.register_page(name, def) ui.pages[name] = def end @@ -361,6 +373,8 @@ function ui.register_button(name, def) table.insert(ui.buttons, def) end +---------------- Callback registrations ---------------- + function ui.register_on_initialized(callback) if type(callback) ~= "function" then error(("Initialized callback must be a function, %s given."):format(type(callback))) @@ -375,6 +389,8 @@ function ui.register_on_craft_registered(callback) table.insert(ui.craft_registered_callbacks, callback) end +---------------- List getters ---------------- + function ui.get_recipe_list(output) return ui.crafts_for.recipe[output] end @@ -387,11 +403,15 @@ function ui.get_registered_outputs() return outputs end +---------------- Player utilities ---------------- + function ui.is_creative(playername) return minetest.check_player_privs(playername, {creative=true}) or minetest.settings:get_bool("creative_mode") end +---------------- Formspec helpers ---------------- + function ui.single_slot(xpos, ypos, bright) return string.format("background9[%f,%f;%f,%f;ui_single_slot%s.png;false;16]", xpos, ypos, ui.imgscale, ui.imgscale, (bright and "_bright" or "") ) diff --git a/unified_inventory/category.lua b/unified_inventory/category.lua index d0fee5e..46b3e02 100644 --- a/unified_inventory/category.lua +++ b/unified_inventory/category.lua @@ -96,6 +96,9 @@ function unified_inventory.register_category(category_name, config) end update_category_list() end + +-- TODO: Mark these for removal. They are pretty much useless + function unified_inventory.set_category_symbol(category_name, symbol) ensure_category_exists(category_name) unified_inventory.registered_categories[category_name].symbol = symbol diff --git a/unified_inventory/doc/mod_api.txt b/unified_inventory/doc/mod_api.txt index ef87697..99fa638 100644 --- a/unified_inventory/doc/mod_api.txt +++ b/unified_inventory/doc/mod_api.txt @@ -1,7 +1,8 @@ unified_inventory API ===================== -This file provides information about the API of unified_inventory. +This file provides information about the API of unified_inventory +and can be viewed in Markdown readers. API revisions within unified_inventory can be checked using: @@ -163,68 +164,57 @@ Register a non-standard craft recipe: Categories ---------- -Register a new category: - The config table (second argument) is optional, and all its members are optional - See the unified_inventory.set_category_* functions for more details on the members of the config table + * `unified_inventory.register_category(name, def)` + * Registers a new category + * `name` (string): internal category name + * `def` (optional, table): also its fields are optional unified_inventory.register_category("category_name", { - symbol = "mod_name:item_name" or "texture.png", + symbol = source, + -- ^ Can be in the format "mod_name:item_name" or "texture.png", label = "Human Readable Label", index = 5, + -- ^ Categories are sorted by index. Lower numbers appear before higher ones. + -- By default, the name is translated to a number: AA -> 0.0101, ZZ -> 0.2626 + --- Predefined category indices: "all" = -2, "uncategorized" = -1 items = { "mod_name:item_name", "another_mod:different_item" } + -- ^ List of items within this category }) + * `unified_inventory.remove_category(name)` + * Removes an entire category -Add / override the symbol for a category: - The category does not need to exist first - The symbol can be an item name or a texture image - If unset this will default to "default:stick" +Modifier functions (to be removed) - unified_inventory.set_category_symbol("category_name", "mod_name:item_name" or "texture.png") + * `unified_inventory.set_category_symbol(name, source)` + * Changes the symbol of the category. The category does not need to exist yet. + * `name` (string): internal category name + * `source` (string, optional): `"mod_name:item_name"` or `"texture.png"`. + Defaults to `"default:stick"` if not specified. + * `unified_inventory.set_category_label(name, label)` + * Changes the human readable label of the category. + * `name` (string): internal category name + * `label` (string): human readable label. Defaults to the category name. + * `unified_inventory.set_category_index(name, index)` + * Changes the sorting index of the category. + * `name` (string): internal category name + * `index` (numeric): any real number -Add / override the human readable label for a category: - If unset this will default to the category name +Item management - unified_inventory.set_category_label("category_name", "Human Readable Label") + * ` unified_inventory.add_category_item(name, itemname)` + * Adds a single item to the category + * `itemname` (string): self-explanatory + * `unified_inventory.add_category_items(name, { itemname1, itemname2, ... }` + * Same as above but with multiple items + * `unified_inventory.remove_category_item(name, itemname)` + * Removes an item from the category + * `unified_inventory.find_category(itemname)` + * Looks up the first category containing this item + * Returns: category name (string) or nil + * `unified_inventory.find_categories(itemname)` + * Looks up the item name within all registered categories + * Returns: array of category names (table) -Add / override the sorting index of the category: - Must be a number, can also be negative (-5) or fractional (2.345) - This determines the position the category appears in the list of categories - The "all" meta-category has index -2, the "misc"/"uncategorized" meta-category has index -1, use a negative number smaller than these to make a category appear before these in the list - By default categories are sorted alphabetically with an index between 0.0101(AA) and 0.2626(ZZ) - - unified_inventory.set_category_index("category_name", 5) - -Add a single item to a category: - - unified_inventory.add_category_item("category_name", "mod_name:item_name") - -Add multiple items to a category: - - unified_inventory.add_category_items("category_name", { - "mod_name:item_name", - "another_mod:different_item" - }) - -Remove an item from a category: - - unified_inventory.remove_category_item("category_name", "mod_name:item_name") - -Remove a category entirely: - - unified_inventory.remove_category("category_name") - -Finding existing items in categories: - This will find the first category an item exists in - It should be used for checking if an item is catgorised - Returns "category_name" or nil - - unified_inventory.find_category("mod_name:item_name") - - - This will find all the categories an item exists in - Returns a number indexed table (list) of category names - - unified_inventory.find_categories("mod_name:item_name") diff --git a/unified_inventory/init.lua b/unified_inventory/init.lua index 1b962da..4a09b32 100644 --- a/unified_inventory/init.lua +++ b/unified_inventory/init.lua @@ -52,6 +52,8 @@ unified_inventory = { list_img_offset = 0.13, standard_background = "bgcolor[#0000]background9[0,0;1,1;ui_formbg_9_sliced.png;true;16]", + hide_disabled_buttons = minetest.settings:get_bool("unified_inventory_hide_disabled_buttons", false), + version = 4 } diff --git a/unified_inventory/internal.lua b/unified_inventory/internal.lua index 938ca19..45db6b3 100644 --- a/unified_inventory/internal.lua +++ b/unified_inventory/internal.lua @@ -52,9 +52,11 @@ local function formspec_tab_buttons(player, formspec, style) local filtered_inv_buttons = {} - for i, def in pairs(ui.buttons) do + for _, def in pairs(ui.buttons) do if not (style.is_lite_mode and def.hide_lite) then - table.insert(filtered_inv_buttons, def) + if def.condition == nil or def.condition(player) or not ui.hide_disabled_buttons then + table.insert(filtered_inv_buttons, def) + end end end @@ -71,13 +73,14 @@ local function formspec_tab_buttons(player, formspec, style) local pos_y = math.floor((i - 1) / style.main_button_cols) * style.btn_spc if def.type == "image" then - if (def.condition == nil or def.condition(player) == true) then + if (def.condition == nil or def.condition(player)) then formspec[n] = string.format("image_button[%g,%g;%g,%g;%s;%s;]", pos_x, pos_y, style.btn_size, style.btn_size, F(def.image), F(def.name)) formspec[n+1] = "tooltip["..F(def.name)..";"..(def.tooltip or "").."]" n = n+2 + else formspec[n] = string.format("image[%g,%g;%g,%g;%s^[colorize:#808080:alpha]", pos_x, pos_y, style.btn_size, style.btn_size, @@ -88,9 +91,10 @@ local function formspec_tab_buttons(player, formspec, style) end formspec[n] = "scroll_container_end[]" if needs_scrollbar then + local total_rows = math.ceil(#filtered_inv_buttons / style.main_button_cols) formspec[n+1] = ("scrollbaroptions[max=%i;arrows=hide]"):format( -- This calculation is not 100% accurate but "good enough" - math.ceil((#filtered_inv_buttons - 1) / style.main_button_cols) * style.btn_spc * 5 + (total_rows - style.main_button_rows) * style.btn_spc * 10 ) formspec[n+2] = ("scrollbar[%g,%g;0.4,%g;vertical;tabbtnscroll;0]"):format( style.main_button_x + style.main_button_cols * style.btn_spc - 0.1, -- x pos @@ -329,7 +333,7 @@ function ui.set_inventory_formspec(player, page) end end -local function valid_def(def) +function ui.is_itemdef_listable(def) return (not def.groups.not_in_creative_inventory or def.groups.not_in_creative_inventory == 0) and def.description @@ -342,9 +346,11 @@ function ui.apply_filter(player, filter, search_dir) return false end local player_name = player:get_player_name() + local lfilter = string.lower(filter) local ffilter if lfilter:sub(1, 6) == "group:" then + -- Group filter: all groups of the item must match local groups = lfilter:sub(7):split(",") ffilter = function(name, def) for _, group in ipairs(groups) do @@ -356,6 +362,7 @@ function ui.apply_filter(player, filter, search_dir) return true end else + -- Name filter: fuzzy match item names and descriptions local player_info = minetest.get_player_information(player_name) local lang = player_info and player_info.lang_code or "" @@ -368,35 +375,41 @@ function ui.apply_filter(player, filter, search_dir) or llocaldesc and string.find(llocaldesc, lfilter, 1, true) end end - ui.filtered_items_list[player_name]={} + + local is_itemdef_listable = ui.is_itemdef_listable + local filtered_items = {} + local category = ui.current_category[player_name] or 'all' if category == 'all' then for name, def in pairs(minetest.registered_items) do - if valid_def(def) + if is_itemdef_listable(def) and ffilter(name, def) then - table.insert(ui.filtered_items_list[player_name], name) + table.insert(filtered_items, name) end end elseif category == 'uncategorized' then for name, def in pairs(minetest.registered_items) do - if (not ui.find_category(name)) - and valid_def(def) + if is_itemdef_listable(def) + and not ui.find_category(name) and ffilter(name, def) then - table.insert(ui.filtered_items_list[player_name], name) + table.insert(filtered_items, name) end end else - for name,exists in pairs(ui.registered_category_items[category]) do + -- Any other category is selected + for name, exists in pairs(ui.registered_category_items[category]) do local def = minetest.registered_items[name] if exists and def - and valid_def(def) + and is_itemdef_listable(def) and ffilter(name, def) then - table.insert(ui.filtered_items_list[player_name], name) + table.insert(filtered_items, name) end end end - table.sort(ui.filtered_items_list[player_name]) - ui.filtered_items_list_size[player_name] = #ui.filtered_items_list[player_name] + table.sort(filtered_items) + + ui.filtered_items_list_size[player_name] = #filtered_items + ui.filtered_items_list[player_name] = filtered_items ui.current_index[player_name] = 1 ui.activefilter[player_name] = filter ui.active_search_direction[player_name] = search_dir diff --git a/unified_inventory/mod.conf b/unified_inventory/mod.conf index 3d27d29..0f03231 100644 --- a/unified_inventory/mod.conf +++ b/unified_inventory/mod.conf @@ -1,6 +1,6 @@ name = unified_inventory -optional_depends = default, creative, sfinv, datastorage, farming +optional_depends = default, creative, sfinv, datastorage description = """ Unified Inventory replaces the default survival and creative inventory. It adds a nicer interface and a number of features, such as a crafting guide. diff --git a/unified_inventory/settingtypes.txt b/unified_inventory/settingtypes.txt index 27768ac..5ab7f84 100644 --- a/unified_inventory/settingtypes.txt +++ b/unified_inventory/settingtypes.txt @@ -10,5 +10,8 @@ unified_inventory_bags (Enable bags) bool true #and the give privilege. unified_inventory_trash (Enable trash) bool true +#If enabled, disabled buttons will be hidden instead of grayed out. +unified_inventory_hide_disabled_buttons (Hide disabled buttons) bool false -unified_inventory_automatic_categorization (Items automatically added to categories) bool true \ No newline at end of file + +unified_inventory_automatic_categorization (Items automatically added to categories) bool true