built on 30/10/2021 16:52:44

This commit is contained in:
Joachim Stolberg 2021-10-30 16:52:44 +02:00
parent 54f7a36018
commit 363346e22d
69 changed files with 2480 additions and 191 deletions

View File

@ -24,7 +24,7 @@ lcdlib = {}
lcdlib.registered_fonts = {} lcdlib.registered_fonts = {}
-- Version for compatibility checks -- Version for compatibility checks
lcdlib.version = 1.0 lcdlib.version = 1.01
-- Local functions -- Local functions
------------------ ------------------
@ -180,7 +180,7 @@ end
-- @return Texture string -- @return Texture string
function lcdlib.make_multiline_texture(font_name, text, width, height, function lcdlib.make_multiline_texture(font_name, text, width, height,
maxlines, valign, color) maxlines, valign, color, y_offs)
local texture = "" local texture = ""
local lines = {} local lines = {}
local textheight = 0 local textheight = 0
@ -199,7 +199,7 @@ function lcdlib.make_multiline_texture(font_name, text, width, height,
if #lines then if #lines then
if valign == "top" then if valign == "top" then
y = 0 y = y_offs or 0
elseif valign == "bottom" then elseif valign == "bottom" then
y = height - textheight y = height - textheight
else else

View File

@ -152,3 +152,4 @@ History
2021-04-10 V2.00 Complete revision to make carts robust against server load/lag, 2021-04-10 V2.00 Complete revision to make carts robust against server load/lag,
Speed limit signs and cart terminal added Speed limit signs and cart terminal added
2021-09-02 V2.01 Chat command /stopcart added 2021-09-02 V2.01 Chat command /stopcart added
2021-10-18 V2.02 Cart reproduction bug fixed

View File

@ -257,9 +257,6 @@ function minecart.add_nodecart(pos, node_name, param2, cargo, owner, userID)
pos2 = minetest.find_node_near(pos, 1, minecart.lRails) pos2 = minetest.find_node_near(pos, 1, minecart.lRails)
if not pos2 or not minecart.is_rail(pos2) then if not pos2 or not minecart.is_rail(pos2) then
pos2 = minetest.find_node_near(pos, 2, minecart.lRails) pos2 = minetest.find_node_near(pos, 2, minecart.lRails)
if not pos2 or not minecart.is_rail(pos2) then
pos2 = minetest.find_node_near(pos, 2, {"air"})
end
end end
else else
pos2 = vector.new(pos) pos2 = vector.new(pos)
@ -282,8 +279,6 @@ function minecart.add_nodecart(pos, node_name, param2, cargo, owner, userID)
ndef.after_place_node(pos2) ndef.after_place_node(pos2)
end end
return pos2 return pos2
else
minetest.add_item(pos, ItemStack({name = node_name}))
end end
end end
end end
@ -363,9 +358,13 @@ function minecart.entity_to_node(pos, entity)
local dir = minetest.yaw_to_dir(rot.y) local dir = minetest.yaw_to_dir(rot.y)
local facedir = minetest.dir_to_facedir(dir) local facedir = minetest.dir_to_facedir(dir)
minecart.stop_recording(entity, pos) minecart.stop_recording(entity, pos)
entity.object:remove()
local pos2 = minecart.add_nodecart(pos, entity.node_name, facedir, entity.cargo, entity.owner, entity.userID) local pos2 = minecart.add_nodecart(pos, entity.node_name, facedir, entity.cargo, entity.owner, entity.userID)
if pos2 then
minecart.stop_monitoring(entity.owner, entity.userID, pos2) minecart.stop_monitoring(entity.owner, entity.userID, pos2)
entity.object:remove()
else
minecart.start_entitycart(entity, pos, facedir)
end
end end
function minecart.add_node_to_player_inventory(pos, player, node_name) function minecart.add_node_to_player_inventory(pos, player, node_name)
@ -388,9 +387,10 @@ function minecart.remove_entity(self, pos, player)
minetest.sound_stop(self.sound_handle) minetest.sound_stop(self.sound_handle)
self.sound_handle = nil self.sound_handle = nil
end end
if player then
minecart.add_node_to_player_inventory(pos, player, self.node_name or "minecart:cart") minecart.add_node_to_player_inventory(pos, player, self.node_name or "minecart:cart")
end
minecart.stop_monitoring(self.owner, self.userID, pos) minecart.stop_monitoring(self.owner, self.userID, pos)
minecart.stop_recording(self, pos) minecart.stop_recording(self, pos)
minecart.monitoring_remove_cart(self.owner, self.userID)
self.object:remove() self.object:remove()
end end

View File

@ -159,13 +159,16 @@ minetest.register_craft({
}) })
minetest.register_lbm({ minetest.register_lbm({
label = "Delete waiting times", label = "Delete metadata",
name = "minecart:del_time", name = "minecart:metadata",
nodenames = {"minecart:buffer"}, nodenames = {"minecart:buffer"},
run_at_every_load = false, run_at_every_load = true,
action = function(pos, node) action = function(pos, node)
-- delete old data -- delete old metadata around the buffer (bugfix)
minecart.get_route(pos) local pos1 = {x = pos.x - 2, y = pos.y - 2, z = pos.z - 2}
M(pos):set_string("formspec", formspec(pos)) local pos2 = {x = pos.x + 2, y = pos.y + 2, z = pos.z + 2}
for _, pos in ipairs(minetest.find_nodes_with_meta(pos1, pos2)) do
minecart.del_metadata(pos)
end
end, end,
}) })

View File

@ -186,7 +186,7 @@ local function play_sound(self)
if self.object then if self.object then
self.sound_handle = minetest.sound_play( self.sound_handle = minetest.sound_play(
"carts_cart_moving", { "carts_cart_moving", {
object = self.object, pos = self.object:get_pos(),
gain = (self.curr_speed or 0) / MAX_SPEED, gain = (self.curr_speed or 0) / MAX_SPEED,
}) })
end end

View File

@ -13,7 +13,7 @@
minecart = {} minecart = {}
-- Version for compatibility checks, see readme.md/history -- Version for compatibility checks, see readme.md/history
minecart.version = 2.01 minecart.version = 2.02
minecart.hopper_enabled = minetest.settings:get_bool("minecart_hopper_enabled") ~= false minecart.hopper_enabled = minetest.settings:get_bool("minecart_hopper_enabled") ~= false
minecart.teleport_enabled = minetest.settings:get_bool("minecart_teleport_enabled") == true minecart.teleport_enabled = minetest.settings:get_bool("minecart_teleport_enabled") == true
@ -35,7 +35,7 @@ dofile(MP .. "/api.lua")
dofile(MP .. "/minecart.lua") dofile(MP .. "/minecart.lua")
dofile(MP .. "/buffer.lua") dofile(MP .. "/buffer.lua")
dofile(MP .. "/protection.lua") dofile(MP .. "/protection.lua")
--dofile(MP .. "/tool.lua") # for debugging only --dofile(MP .. "/tool.lua") -- for debugging only
dofile(MP .. "/signs.lua") dofile(MP .. "/signs.lua")
dofile(MP .. "/terminal.lua") dofile(MP .. "/terminal.lua")
dofile(MP .. "/pusher.lua") dofile(MP .. "/pusher.lua")

View File

@ -68,9 +68,6 @@ local function get_checkpoint(cart)
cp = cart.checkpoints[cart.idx] cp = cart.checkpoints[cart.idx]
end end
local pos = H2P(cp[1]) local pos = H2P(cp[1])
-- if M(pos):contains("waypoints") then
-- print("get_checkpoint", P2S(H2P(cp[1])), P2S(H2P(cp[2])))
-- end
return cp, cart.idx == #cart.checkpoints return cp, cart.idx == #cart.checkpoints
end end
@ -81,6 +78,7 @@ local function get_cart_state_and_loc(name, userID, query_pos)
if tCartsOnRail[name] and tCartsOnRail[name][userID] then if tCartsOnRail[name] and tCartsOnRail[name][userID] then
local cart = tCartsOnRail[name][userID] local cart = tCartsOnRail[name][userID]
local pos = cart.last_pos or cart.pos local pos = cart.last_pos or cart.pos
if pos then
local loc = minecart.get_buffer_name(cart.pos) or local loc = minecart.get_buffer_name(cart.pos) or
math.floor(vector.distance(pos, query_pos)) math.floor(vector.distance(pos, query_pos))
if cart.objID == 0 then if cart.objID == 0 then
@ -90,6 +88,7 @@ local function get_cart_state_and_loc(name, userID, query_pos)
return "running", math.floor(vector.distance(pos, query_pos)), cart.node_name return "running", math.floor(vector.distance(pos, query_pos)), cart.node_name
end end
end end
end
return "unknown", 0, "unknown" return "unknown", 0, "unknown"
end end
@ -103,21 +102,41 @@ local function get_cart_info(owner, userID, query_pos)
end end
end end
local function logging(cart, err)
local s = string.format("[Minecart] Cart %s/%u %s!", cart.owner, cart.userID, err)
minetest.log("warning", s)
end
-- check cart data
local function valid_cart(cart)
if cart.objID == nil or cart.objID == 0 then
return false
end
if tCartsOnRail[cart.owner] and tCartsOnRail[cart.owner][cart.userID] then
return true
end
logging(cart, "with invalid data")
local entity = minetest.luaentities[cart.objID]
if entity then
entity.object:remove()
end
return false
end
local function monitoring(cycle) local function monitoring(cycle)
local cart = pop(cycle) local cart = pop(cycle)
while cart do
-- All running cars -- All running cars
if cart.objID and cart.objID ~= 0 then while cart do
if valid_cart(cart) then
cart.idx = cart.idx + 1 cart.idx = cart.idx + 1
local entity = minetest.luaentities[cart.objID] local entity = minetest.luaentities[cart.objID]
if entity then -- cart entity running if entity then -- cart entity running
local pos = entity.object:get_pos() local pos = entity.object:get_pos()
if pos then if pos then
cart.last_pos = vector.round(pos) cart.last_pos = vector.round(pos)
--print("entity card " .. cart.userID .. " at " .. P2S(cart.last_pos))
else else
minetest.log("warning", "[Minecart] entity card without pos!") logging(cart, "without pos")
end end
push(cycle, cart) push(cycle, cart)
elseif cart.checkpoints then elseif cart.checkpoints then
@ -130,16 +149,15 @@ local function monitoring(cycle)
end end
push(cycle, cart) push(cycle, cart)
else else
minetest.log("warning", "[Minecart] zombie got lost") logging(cart, "as zombie got lost")
end end
else else
local pos = cart.last_pos or cart.pos local pos = cart.last_pos or cart.pos
pos = minecart.add_nodecart(pos, cart.node_name, 0, cart.cargo, cart.owner, cart.userID) pos = minecart.add_nodecart(pos, cart.node_name, 0, cart.cargo, cart.owner, cart.userID)
cart.objID = 0 minecart.stop_monitoring(cart.owner, cart.userID, pos)
cart.pos = pos logging(cart, "stopped at " .. (P2S(pos) or "unknown"))
--print("cart to node", cycle, cart.userID, P2S(pos))
end end
elseif cart and not cart.objID and tCartsOnRail[cart.owner] then elseif not cart.objID and tCartsOnRail[cart.owner] then
-- Delete carts marked as "to be deleted" -- Delete carts marked as "to be deleted"
tCartsOnRail[cart.owner][cart.userID] = nil tCartsOnRail[cart.owner][cart.userID] = nil
end end
@ -184,6 +202,7 @@ function minecart.stop_monitoring(owner, userID, pos)
--print("stop_monitoring", owner, userID) --print("stop_monitoring", owner, userID)
if tCartsOnRail[owner] and tCartsOnRail[owner][userID] then if tCartsOnRail[owner] and tCartsOnRail[owner][userID] then
tCartsOnRail[owner][userID].pos = pos tCartsOnRail[owner][userID].pos = pos
-- Mark as "stopped"
tCartsOnRail[owner][userID].objID = 0 tCartsOnRail[owner][userID].objID = 0
minecart.store_carts() minecart.store_carts()
end end
@ -192,14 +211,20 @@ end
function minecart.monitoring_remove_cart(owner, userID) function minecart.monitoring_remove_cart(owner, userID)
--print("monitoring_remove_cart", owner, userID) --print("monitoring_remove_cart", owner, userID)
if tCartsOnRail[owner] and tCartsOnRail[owner][userID] then if tCartsOnRail[owner] and tCartsOnRail[owner][userID] then
tCartsOnRail[owner][userID].objID = nil -- Cart stopped?
if tCartsOnRail[owner][userID].objID == 0 then
-- Can directly be deleted
tCartsOnRail[owner][userID] = nil tCartsOnRail[owner][userID] = nil
else -- Cart running
-- Mark as "to be deleted" by monitoring
tCartsOnRail[owner][userID].objID = nil
end
minecart.store_carts() minecart.store_carts()
end end
end end
function minecart.monitoring_valid_cart(owner, userID, pos, node_name) function minecart.monitoring_valid_cart(owner, userID, pos, node_name)
if tCartsOnRail[owner] and tCartsOnRail[owner][userID] then if tCartsOnRail[owner] and tCartsOnRail[owner][userID] and tCartsOnRail[owner][userID].pos then
return vector.equals(tCartsOnRail[owner][userID].pos, pos) and return vector.equals(tCartsOnRail[owner][userID].pos, pos) and
tCartsOnRail[owner][userID].node_name == node_name tCartsOnRail[owner][userID].node_name == node_name
end end
@ -245,29 +270,38 @@ minetest.register_chatcommand("mycart", {
minetest.register_chatcommand("stopcart", { minetest.register_chatcommand("stopcart", {
params = "<cart-num>", params = "<cart-num>",
description = S("Stop amd return a missing/running cart."), description = S("Stop and return/drop a missing/running cart."),
func = function(owner, param) func = function(owner, param)
local userID = tonumber(param) local userID = tonumber(param)
local player_pos = minetest.get_player_by_name(owner):get_pos() local player_pos = minetest.get_player_by_name(owner):get_pos()
if userID then if userID then
local data = minecart.get_cart_monitoring_data(owner, userID) local data = minecart.get_cart_monitoring_data(owner, userID)
if data then if data and data.objID then
if data.objID and data.objID ~= 0 then
local entity = minetest.luaentities[data.objID] local entity = minetest.luaentities[data.objID]
if entity then -- cart entity running --print("stopcart", userID, data.pos, data.objID, entity)
minecart.entity_to_node(player_pos, entity) if data.objID == 0 then
minecart.monitoring_remove_cart(owner, userID) -- Cart as node
if data.pos then
local meta = M(data.pos)
if owner == meta:get_string("owner") and userID == meta:get_int("userID") then
minecart.remove_nodecart(data.pos)
end end
end
elseif entity then
-- Cart as entity
minecart.remove_entity(entity, data.pos)
else else
local pos = data.last_pos or data.pos -- Cart as zombie/invalid/corrupted
local cargo, _, _ = minecart.remove_nodecart(pos) -- nothing to do
minecart.add_nodecart(player_pos, data.node_name, 0, cargo, owner, userID)
minecart.monitoring_remove_cart(owner, userID)
end end
return true, S("Cart") .. " " .. userID .. " " .. S("stopped") minetest.add_item(player_pos, ItemStack({name = data.node_name}))
minecart.monitoring_remove_cart(owner, userID)
return true, S("Cart") .. " " .. userID .. " " .. S("dropped")
else else
return false, S("Cart") .. " " .. userID .. " " .. S("is not existing!") return false, S("Cart") .. " " .. userID .. " " .. S("is not existing!")
end end
else
return false
end end
end end
}) })

View File

@ -585,6 +585,9 @@ end
-- minecart.get_next_buffer(pos, facedir) -- minecart.get_next_buffer(pos, facedir)
minecart.get_next_buffer = get_next_buffer minecart.get_next_buffer = get_next_buffer
-- minecart.del_metadata(pos)
minecart.del_metadata = del_metadata
--minetest.register_lbm({ --minetest.register_lbm({
-- label = "Delete waypoints", -- label = "Delete waypoints",
-- name = "minecart:del_meta", -- name = "minecart:del_meta",

View File

@ -50,33 +50,18 @@ minetest.register_on_mods_loaded(function()
else else
local t = minetest.deserialize(storage:get_string("CartsOnRail")) or {} local t = minetest.deserialize(storage:get_string("CartsOnRail")) or {}
for owner, carts in pairs(t) do for owner, carts in pairs(t) do
minecart.CartsOnRail[owner] = {} minecart.CartsOnRail[owner] = minecart.CartsOnRail[owner] or {}
for userID, cart in pairs(carts) do for userID, cart in pairs(carts) do
print("reload cart", owner, userID, cart.objID) if cart.objID then
minecart.CartsOnRail[owner][userID] = cart minecart.CartsOnRail[owner][userID] = cart
-- mark all entity carts as zombified -- mark all entity carts as zombified
if cart.objID and cart.objID ~= 0 then if cart.objID ~= 0 then
cart.objID = -1 cart.objID = -1
minecart.push(1, cart) minecart.push(1, cart)
end end
end end
end end
end end
end)
minetest.after(10, function()
for owner, carts in pairs(minecart.CartsOnRail) do
for userID, cart in pairs(carts) do
-- Remove node carts that are not available anymore
if cart.pos and (cart.objID == 0 or not cart.objID) then
local node = minecart.get_node_lvm(cart.pos)
if not minecart.tNodeNames[node.name] then
-- Mark as "to be deleted"
print("Node cart deleted", owner, userID)
minecart.CartsOnRail[owner][userID] = nil
end
end
end
end end
end) end)

View File

@ -78,7 +78,8 @@ local function click_left(itemstack, placer, pointed_thing)
if pointed_thing.type == "node" then if pointed_thing.type == "node" then
local pos = pointed_thing.under local pos = pointed_thing.under
if minecart.is_rail(pos) then if minecart.is_rail(pos) then
test_get_buffer(pos, placer) --test_get_buffer(pos, placer)
minecart.delete_waypoint(pos)
end end
end end
end end

View File

@ -183,4 +183,5 @@ optional: farming redo, node_io, doc, techage, minecart, xdecor, compost
- 2021-04-24 v1.07 * Adapted to minecart v2.0 - 2021-04-24 v1.07 * Adapted to minecart v2.0
- 2021-05-04 v1.08 * Add print command, improve error msg - 2021-05-04 v1.08 * Add print command, improve error msg
- 2021-08-22 v1.09 * Add soup commands and signs, add aspen sign - 2021-08-22 v1.09 * Add soup commands and signs, add aspen sign
- 2021-09-18 v1.10 * Add techage command 'set <num>' to the Bot Control Unit

View File

@ -8,7 +8,7 @@
GPL v3 GPL v3
See LICENSE.txt for more information See LICENSE.txt for more information
Signgs Changer/Control Unit for Bot Control Signs Changer/Control Unit for Bot Control
]]-- ]]--

View File

@ -61,6 +61,7 @@ local function harvesting(base_pos, mem)
if pos and lib.not_protected(base_pos, pos) then if pos and lib.not_protected(base_pos, pos) then
local node = minetest.get_node_or_nil(pos) local node = minetest.get_node_or_nil(pos)
if node.name ~= "default:papyrus" then
local drop = Flowers[node.name] or is_tree(node) local drop = Flowers[node.name] or is_tree(node)
if drop then if drop then
minetest.remove_node(pos) minetest.remove_node(pos)
@ -69,6 +70,22 @@ local function harvesting(base_pos, mem)
signs_bot.lib.drop_items(mem.robot_pos, leftover) signs_bot.lib.drop_items(mem.robot_pos, leftover)
end end
end end
else
-- papyrus is a special plant that is collected upwards when cut
local count = 0
while node.name == "default:papyrus" and lib.not_protected(base_pos, pos) do
minetest.remove_node(pos)
pos = { x = pos.x, y = pos.y + 1, z = pos.z }
count = count + 1
node = minetest.get_node(pos)
end
if count > 0 then
local leftover = bot_inv_put_item(base_pos, 0, ItemStack("default:papyrus " .. count))
if leftover and leftover:get_count() > 0 then
signs_bot.lib.drop_items(mem.robot_pos, leftover)
end
end
end
end end
end end
@ -76,7 +93,7 @@ signs_bot.register_botcommand("cutting", {
mod = "farming", mod = "farming",
params = "", params = "",
num_param = 0, num_param = 0,
description = S("Cutting flowers, leaves and tree blocks\nin front of the robot\non a 3x3 field."), description = S("Cutting flowers, papyrus,\nleaves and tree blocks\nin front of the robot\non a 3x3 field."),
cmnd = function(base_pos, mem) cmnd = function(base_pos, mem)
if not mem.steps then if not mem.steps then
mem.pos_tbl = signs_bot.lib.gen_position_table(mem.robot_pos, mem.robot_param2, 3, 3, 0) mem.pos_tbl = signs_bot.lib.gen_position_table(mem.robot_pos, mem.robot_param2, 3, 3, 0)

View File

@ -551,3 +551,5 @@ techage.add_manual_items({
ta4_jetpack.register_forbidden_item("techage:cylinder_large_hydrogen") ta4_jetpack.register_forbidden_item("techage:cylinder_large_hydrogen")
ta4_jetpack.register_forbidden_item("techage:cylinder_small_hydrogen") ta4_jetpack.register_forbidden_item("techage:cylinder_small_hydrogen")
ta4_jetpack.register_forbidden_item("techage:hydrogen") ta4_jetpack.register_forbidden_item("techage:hydrogen")
ta4_jetpack.register_forbidden_item("digtron:loaded_crate")
ta4_jetpack.register_forbidden_item("digtron:loaded_locked_crate")

View File

@ -81,6 +81,13 @@ Available worlds will be converted to 'lsqlite3', but there is no way back, so:
### History ### History
**2021-10-24 V1.03**
- Add TA4 Sequencer for time controlled command sequences
- Add TA4 Move Controller for moving blocks
- Add techage command counting function to be able to limit the amount of commands/min.
- Pull request #67: Add switch mode for 4x Button (by realmicu)
- Pull request #69: Add option to keep assignment for TA4 Tank (by Thomas-S)
**2021-09-18 V1.02** **2021-09-18 V1.02**
- TA4 Chest: Fix items disappearing (PR #64 by Thomas--S) - TA4 Chest: Fix items disappearing (PR #64 by Thomas--S)
- Add support for colored cables (PR #63 by Thomas--S) - Add support for colored cables (PR #63 by Thomas--S)

View File

@ -152,6 +152,7 @@ function techage.register_consumer(base_name, inv_name, tiles, tNode, validState
formspec_func = tNode.formspec, formspec_func = tNode.formspec,
on_state_change = tNode.on_state_change, on_state_change = tNode.on_state_change,
can_start = tNode.can_start, can_start = tNode.can_start,
quick_start = tNode.quick_start,
has_power = tNode.has_power or power_used and has_power or nil, has_power = tNode.has_power or power_used and has_power or nil,
start_node = power_used and start_node or nil, start_node = power_used and start_node or nil,
stop_node = power_used and stop_node or nil, stop_node = power_used and stop_node or nil,

View File

@ -350,11 +350,27 @@ local function search_chest_in_front(pos, node)
end end
if node.name == "techage:ta4_chest" then if node.name == "techage:ta4_chest" then
minetest.after(1, count_number_of_chests, pos1) minetest.after(1, count_number_of_chests, pos1)
local nvm = techage.get_nvm(pos)
nvm.front_chest_pos = pos1
return true return true
end end
return false return false
end end
local function get_front_chest_pos(pos)
local nvm = techage.get_nvm(pos)
if nvm.front_chest_pos then
return nvm.front_chest_pos
end
local node = techage.get_node_lvm(pos)
if search_chest_in_front(pos, node) then
return nvm.front_chest_pos
end
return pos
end
local function convert_to_chest_again(pos, node, player) local function convert_to_chest_again(pos, node, player)
local dir = techage.side_to_outdir("B", node.param2) local dir = techage.side_to_outdir("B", node.param2)
local pos1 = tubelib2.get_pos(pos, dir) local pos1 = tubelib2.get_pos(pos, dir)
@ -594,6 +610,33 @@ techage.register_node({"techage:ta4_chest"}, {
end, end,
}) })
techage.register_node({"techage:ta4_chest_dummy"}, {
on_pull_item = function(pos, in_dir, num, item_name)
local fc_pos = get_front_chest_pos(pos)
local res = tube_take_from_chest(fc_pos, item_name, num)
if techage.is_activeformspec(fc_pos) then
M(fc_pos):set_string("formspec", formspec(fc_pos))
end
return res
end,
on_push_item = function(pos, in_dir, stack)
local fc_pos = get_front_chest_pos(pos)
local res = tube_add_to_chest(fc_pos, stack)
if techage.is_activeformspec(fc_pos) then
M(fc_pos):set_string("formspec", formspec(fc_pos))
end
return res
end,
on_unpull_item = function(pos, in_dir, stack)
local fc_pos = get_front_chest_pos(pos)
local res = tube_add_to_chest(fc_pos, stack)
if techage.is_activeformspec(fc_pos) then
M(fc_pos):set_string("formspec", formspec(fc_pos))
end
return res
end
})
minetest.register_craft({ minetest.register_craft({
type = "shapeless", type = "shapeless",
output = "techage:ta4_chest", output = "techage:ta4_chest",

View File

@ -175,7 +175,7 @@ local function pushing(pos, crd, meta, nvm)
end end
end end
local function keep_running(pos, elapsed) local function node_timer(pos, elapsed)
local nvm = techage.get_nvm(pos) local nvm = techage.get_nvm(pos)
local crd = CRD(pos) local crd = CRD(pos)
pushing(pos, crd, M(pos), nvm) pushing(pos, crd, M(pos), nvm)
@ -253,6 +253,7 @@ local _, node_name_ta3, node_name_ta4 =
standby_ticks = STANDBY_TICKS, standby_ticks = STANDBY_TICKS,
formspec = formspec, formspec = formspec,
tubing = tubing, tubing = tubing,
quick_start = node_timer,
after_place_node = function(pos, placer) after_place_node = function(pos, placer)
local meta = M(pos) local meta = M(pos)
local node = minetest.get_node(pos) local node = minetest.get_node(pos)
@ -268,7 +269,7 @@ local _, node_name_ta3, node_name_ta4 =
allow_metadata_inventory_take = allow_metadata_inventory_take, allow_metadata_inventory_take = allow_metadata_inventory_take,
allow_metadata_inventory_move = function() return 0 end, allow_metadata_inventory_move = function() return 0 end,
on_receive_fields = on_receive_fields, on_receive_fields = on_receive_fields,
node_timer = keep_running, node_timer = node_timer,
on_rotate = screwdriver.disallow, on_rotate = screwdriver.disallow,
groups = {choppy=2, cracky=2, crumbly=2}, groups = {choppy=2, cracky=2, crumbly=2},

View File

@ -27,6 +27,7 @@ local string_split = string.split
local NodeDef = techage.NodeDef local NodeDef = techage.NodeDef
local Tube = techage.Tube local Tube = techage.Tube
local is_cart_available = minecart.is_nodecart_available local is_cart_available = minecart.is_nodecart_available
local techage_counting_hit = techage.counting_hit
------------------------------------------------------------------- -------------------------------------------------------------------
-- Database -- Database
@ -253,6 +254,14 @@ function techage.remove_node(pos, oldnode, oldmetadata)
end end
end end
-- Repairs the node number after it was erased by `backend.delete_invalid_entries`
function techage.repair_number(pos)
local number = techage.get_node_number(pos)
if number then
backend.set_nodepos(number, pos)
end
end
------------------------------------------------------------------- -------------------------------------------------------------------
-- Node register function -- Node register function
@ -324,6 +333,7 @@ function techage.send_multi(src, numbers, topic, payload)
if ninfo and ninfo.name and ninfo.pos then if ninfo and ninfo.name and ninfo.pos then
local ndef = NodeDef[ninfo.name] local ndef = NodeDef[ninfo.name]
if ndef and ndef.on_recv_message then if ndef and ndef.on_recv_message then
techage_counting_hit()
ndef.on_recv_message(ninfo.pos, src, topic, payload) ndef.on_recv_message(ninfo.pos, src, topic, payload)
end end
end end
@ -336,6 +346,7 @@ function techage.send_single(src, number, topic, payload)
if ninfo and ninfo.name and ninfo.pos then if ninfo and ninfo.name and ninfo.pos then
local ndef = NodeDef[ninfo.name] local ndef = NodeDef[ninfo.name]
if ndef and ndef.on_recv_message then if ndef and ndef.on_recv_message then
techage_counting_hit()
return ndef.on_recv_message(ninfo.pos, src, topic, payload) return ndef.on_recv_message(ninfo.pos, src, topic, payload)
end end
end end

View File

@ -0,0 +1,68 @@
--[[
TechAge
=======
Copyright (C) 2019-2021 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Count techage commands player related
]]--
local PlayerName
local PlayerPoints = {}
local LastPlayerPoints = {}
local S = techage.S
local MAX_POINTS = tonumber(minetest.settings:get("techage_command_limit")) or 1200
function techage.counting_start(player_name)
PlayerName = player_name
PlayerPoints[PlayerName] = PlayerPoints[PlayerName] or 0
end
function techage.counting_stop()
PlayerName = nil
end
function techage.counting_hit()
if PlayerName then
PlayerPoints[PlayerName] = PlayerPoints[PlayerName] + 1
end
end
local function output()
for name, val in pairs(PlayerPoints) do
if val > MAX_POINTS then
local obj = minetest.get_player_by_name(name)
if obj then
minetest.chat_send_player(name,
S("[techage] The limit for 'number of commands per minute' has been exceeded.") ..
" " .. string.format(MAX_POINTS .. " " .. S("is allowed. Current value is") .. " " .. val));
minetest.log("action", "[techage] " .. name ..
" exceeds the limit for commands per minute. value = " .. val)
local factor = 100 / (obj:get_armor_groups().fleshy or 100)
obj:punch(obj, 1.0, {full_punch_interval=1.0, damage_groups = {fleshy=factor * 5}})
end
end
end
LastPlayerPoints = table.copy(PlayerPoints)
PlayerPoints = {}
minetest.after(60, output)
end
minetest.after(60, output)
minetest.register_chatcommand("ta_limit", {
description = "Get your current techage command limit value",
func = function(name)
local num = LastPlayerPoints[name] or 0
return true, S("Your current value is") .. " " .. num .. " " .. S("per minute") .. ". " ..
MAX_POINTS .. " " .. S("is allowed")
end
})

View File

@ -102,7 +102,7 @@ for _, size in ipairs(SIZES) do
physical = false, physical = false,
collide_with_objects = false, collide_with_objects = false,
pointable = false, pointable = false,
static_save = true, static_save = false,
visual_size = {x = size, y = 0.05, z = 0.05}, visual_size = {x = size, y = 0.05, z = 0.05},
glow = 14, glow = 14,
shaded = true, shaded = true,

View File

@ -38,21 +38,18 @@ function techage.liquid.formspec(pos, nvm)
end end
local name = minetest.get_node(pos).name local name = minetest.get_node(pos).name
if name == "techage:ta4_tank" then if name == "techage:ta4_tank" then
local public = dump((M(pos):get_int("public") or 0) == 1) local meta = M(pos)
return "size[5,3]".. local public = dump((meta:get_int("public") or 0) == 1)
default.gui_bg.. local keep_assignment = dump((meta:get_int("keep_assignment") or 0) == 1)
default.gui_bg_img.. return "size[5,3.5]"..
default.gui_slots..
"box[0,-0.1;4.8,0.5;#c6e8ff]".. "box[0,-0.1;4.8,0.5;#c6e8ff]"..
"label[1.5,-0.1;"..minetest.colorize("#000000", title).."]".. "label[1.5,-0.1;"..minetest.colorize("#000000", title).."]"..
help(4.4, -0.1).. help(4.4, -0.1)..
techage.item_image(2, 1, itemname).. techage.item_image(2, 1, itemname)..
"checkbox[0.1,2.5;public;"..S("Allow public access to the tank")..";"..public.."]" "checkbox[0.1,2.5;public;"..S("Allow public access to the tank")..";"..public.."]"..
"checkbox[0.1,3;keep_assignment;"..S("keep assignment")..";"..keep_assignment.."]"
else else
return "size[4,2]".. return "size[4,2]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"box[0,-0.1;3.8,0.5;#c6e8ff]".. "box[0,-0.1;3.8,0.5;#c6e8ff]"..
"label[1,-0.1;"..minetest.colorize("#000000", title).."]".. "label[1,-0.1;"..minetest.colorize("#000000", title).."]"..
help(3.4, -0.1).. help(3.4, -0.1)..

View File

@ -183,6 +183,7 @@ function NodeStates:new(attr)
stop_node = attr.stop_node, stop_node = attr.stop_node,
formspec_func = attr.formspec_func, formspec_func = attr.formspec_func,
on_state_change = attr.on_state_change, on_state_change = attr.on_state_change,
quick_start = attr.quick_start,
} }
setmetatable(o, self) setmetatable(o, self)
self.__index = self self.__index = self
@ -272,6 +273,10 @@ function NodeStates:start(pos, nvm)
self.on_state_change(pos, state, RUNNING) self.on_state_change(pos, state, RUNNING)
end end
start_timer_delayed(pos, self.cycle_time) start_timer_delayed(pos, self.cycle_time)
if self.quick_start and state == STOPPED then
self.quick_start(pos, 0)
end
return true return true
end end
return false return false

View File

@ -118,6 +118,9 @@ minetest.register_node("techage:tank_cart", {
local nvm = techage.get_nvm(pos) local nvm = techage.get_nvm(pos)
nvm.liquid = nvm.liquid or {} nvm.liquid = nvm.liquid or {}
M(pos):set_string("formspec", techage.liquid.formspec(pos, nvm)) M(pos):set_string("formspec", techage.liquid.formspec(pos, nvm))
-- Delete the network between pump and cart
Pipe:after_dig_node(pos)
Pipe:after_place_node(pos)
end, end,
set_cargo = function(pos, data) set_cargo = function(pos, data)

View File

@ -191,6 +191,9 @@ techage.Items = {
ta4_electricmeter = "techage:ta4_electricmeter", ta4_electricmeter = "techage:ta4_electricmeter",
ta4_transformer = "techage:ta4_transformer", ta4_transformer = "techage:ta4_transformer",
power_reduction = "techage_power_reduction.png", power_reduction = "techage_power_reduction.png",
ta4_button_4x = "techage:ta4_button_4x",
ta4_sequencer = "techage:ta4_sequencer",
ta4_movecontroller = "techage:ta4_movecontroller",
--ta4_ "", --ta4_ "",
} }

View File

@ -183,9 +183,12 @@ techage.manual_DE.aTitel = {
"3,TA4 Lua Controller Terminal", "3,TA4 Lua Controller Terminal",
"2,TA4 Logik-/Schalt-Module", "2,TA4 Logik-/Schalt-Module",
"3,TA4 Taster/Schalter / Button/Switch", "3,TA4 Taster/Schalter / Button/Switch",
"3,TA4 4x Taster / 4x Button",
"3,TA4 Spieler Detektor / Player Detector", "3,TA4 Spieler Detektor / Player Detector",
"3,TA4 Zustandssammler / State Collector", "3,TA4 Zustandssammler / State Collector",
"3,TA4 Detektor / Detector", "3,TA4 Detektor / Detector",
"3,TA4 Move Controller",
"3,TA4 Sequenzer",
"2,TA4 Lampen", "2,TA4 Lampen",
"3,TA4 LED Pflanzenlampe / TA4 LED Grow Light", "3,TA4 LED Pflanzenlampe / TA4 LED Grow Light",
"3,TA4 LED Straßenlampe / TA4 LED Street Lamp", "3,TA4 LED Straßenlampe / TA4 LED Street Lamp",
@ -1126,6 +1129,7 @@ techage.manual_DE.aText = {
"Der Detektor ist eine spezieller Röhrenblock\\, der erkennt\\, wenn Items über die Röhre weitergegeben werden. Es muss dazu auf beiden Seiten mit der Röhre verbunden sein. Werden Items mit einem Schieber in den Detektor geschoben\\, gibt er diese automatisch weiter.\n".. "Der Detektor ist eine spezieller Röhrenblock\\, der erkennt\\, wenn Items über die Röhre weitergegeben werden. Es muss dazu auf beiden Seiten mit der Röhre verbunden sein. Werden Items mit einem Schieber in den Detektor geschoben\\, gibt er diese automatisch weiter.\n"..
"Er sendet ein 'on'\\, wenn ein Item erkannt wird\\, gefolgt von einem 'off' eine Sekunde später.\n".. "Er sendet ein 'on'\\, wenn ein Item erkannt wird\\, gefolgt von einem 'off' eine Sekunde später.\n"..
"Danach werden weitere Kommando für 8 Sekunden blockiert.\n".. "Danach werden weitere Kommando für 8 Sekunden blockiert.\n"..
"Die Wartezeit\\, sowie die Items\\, die ein Kommando auslösen sollen\\, können über das Gabelschlüssel-Menü konfiguriert werden.\n"..
"\n".. "\n"..
"\n".. "\n"..
"\n", "\n",
@ -1558,6 +1562,10 @@ techage.manual_DE.aText = {
"\n".. "\n"..
"\n".. "\n"..
"\n", "\n",
"Dieser Block hat vier Taster\\, die über das Schraubenschlüssel-Menü individuell konfiguriert werden können. Für jeden Taster kann die Beschriftung und die Zielblockadresse konfiguriert werden. Zusätzlich kann für jeden Taster das Kommando konfiguriert werden\\, welches gesendet werden soll.\n"..
"\n"..
"\n"..
"\n",
"Beim TA4 Spieler Detektor hat sich nur das Aussehen geändert. Die Funktionalität ist gleich wie beim TA3 Spieler Detektor.\n".. "Beim TA4 Spieler Detektor hat sich nur das Aussehen geändert. Die Funktionalität ist gleich wie beim TA3 Spieler Detektor.\n"..
"\n".. "\n"..
"\n".. "\n"..
@ -1571,6 +1579,50 @@ techage.manual_DE.aText = {
"\n".. "\n"..
"\n".. "\n"..
"\n", "\n",
"Der TA4 Move Controller ist ähnlich zum \"Door Controller 2\"\\, aber die ausgewählten Blöcke werden nicht entfernt\\, sondern können bewegt werden.\n"..
"Da die bewegten Blöcke Spieler und Mobs mitnehmen können\\, die auf dem Block stehen\\, können damit Fahrstühle und ähnliche Transportsysteme gebaut werden.\n"..
"\n"..
"Anleitung:\n"..
"\n"..
" - Controller setzen und die Blöcke\\, die bewegt werden sollen\\, über das Menü an-trainieren (Es können bis zu 16 Blöcke an-trainiert werden)\n"..
" - die \"Flugstrecke\" muss über eine x\\,y\\,z Angabe (relativ) eingegeben werden (die maximale Distanz beträgt 100 m)\n"..
" - mit den Menü-Tasten \"Bewege A-B\" sowie \"Bewege B-A\" kann die Bewegung getestet werden\n"..
" - man kann auch durch Wände oder andere Blöcke fliegen\n"..
" - auch die Zielposition für die Blöcke kann belegt sein. Die Blöcke werden in diesem Falle \"unsichtbar\" gespeichert. Dies ist für Schiebetüren und ähnliches gedacht\n"..
" - Über das Gabelschlüssel-Menü kann im Controller auch ein \"handover\" programmiert werden. Durch Eingabe einer Blocknummer werden die Blöcke dann an den nächsten Move Controller übergeben. So lassen sich auch zusammenhängende Bewegungen über mehrere Move Controller realisieren.\n"..
"\n"..
"Der Move Controller unterstützt folgende techage Kommandos:\n"..
"\n"..
" - 'a2b' Bewege Block von A nach B\n"..
" - 'b2a' Bewege Block von B nach A\n"..
" - 'move' Bewege Block auf die andere Seite\n"..
"\n"..
"\n"..
"\n",
"über den TA4 Sequenzer können ganze Abläufe programmiert werden. Hier ein Beispiel:\n"..
"\n"..
" -- this is a comment\n"..
" \\[1\\] send 1234 a2b\n"..
" \\[30\\] send 1234 b2a\n"..
" \\[60\\] goto 1\n"..
"\n"..
" - Jede Zeile beginnt mit einem Nummer\\, welche einem Zeitpunkt entspricht '\\[<num>\\]'\n"..
" - Für Zeitpunkte sind Werte von 1 bis 50000 zulässig\n"..
" - 1 entspricht 100 ms\\, 50000 entspricht in etwa 4 Spieltagen\n"..
" - Leerzeilen oder Kommentare sind erlaubt ('-- comment')\n"..
" - Mit 'send <num> <command> <data>' kann man ein Kommando an einen Block senden\n"..
" - Mit 'goto <num>' kann man an eine andere Zeile/Zeitpunkt springen\n"..
" - Mit 'stop' kann man den Sequenzer verzögert stoppen\\, so dass er kein neues Kommando\nvon einem Taster oder anderem Block annimmt (um eine Bewegung abzuschließen)\nOhne 'stop' geht der Sequenzer sofort nach dem letzten Kommando in den stopped Modus.\n"..
"\n"..
"Der TA4 Sequenzer unterstützt folgende techage Kommandos:\n"..
"\n"..
" - 'goto <num>' Zu einer Kommandozeile springen und damit den Sequenzer starten\n"..
" - 'stop' Den Sequenzer anhalten\n"..
"\n"..
"Das 'goto' Kommando wird nur angenommen\\, wenn der Sequenzer gestoppt ist.\n"..
"\n"..
"\n"..
"\n",
"TA4 beinhaltet eine Reihe von leistungsstarken Lampen\\, die eine bessere Ausleuchtung ermöglichen oder Spezialaufgaben übernehmen.\n".. "TA4 beinhaltet eine Reihe von leistungsstarken Lampen\\, die eine bessere Ausleuchtung ermöglichen oder Spezialaufgaben übernehmen.\n"..
"\n", "\n",
"Die TA4 LED Pflanzenlampe ermöglicht ein schnelles und kräftiges Wachstum aller Pflanzen aus der 'farming' Mod. Die Lampe beleuchtet ein 3x3 großes Feld\\, so dass sich damit auch Pflanzen unter Tage anbauen lassen.\n".. "Die TA4 LED Pflanzenlampe ermöglicht ein schnelles und kräftiges Wachstum aller Pflanzen aus der 'farming' Mod. Die Lampe beleuchtet ein 3x3 großes Feld\\, so dass sich damit auch Pflanzen unter Tage anbauen lassen.\n"..
@ -1932,9 +1984,12 @@ techage.manual_DE.aItemName = {
"ta4_terminal", "ta4_terminal",
"", "",
"ta4_button", "ta4_button",
"ta4_button_4x",
"ta4_playerdetector", "ta4_playerdetector",
"ta4_collector", "ta4_collector",
"ta4_detector", "ta4_detector",
"ta4_movecontroller",
"ta4_sequencer",
"", "",
"ta4_growlight", "ta4_growlight",
"ta4_streetlamp", "ta4_streetlamp",
@ -2154,6 +2209,9 @@ techage.manual_DE.aPlanTable = {
"", "",
"", "",
"", "",
"",
"",
"",
"ta4_liquid_filter_base", "ta4_liquid_filter_base",
"ta4_liquid_filter_gravel", "ta4_liquid_filter_gravel",
"ta4_liquid_filter_top", "ta4_liquid_filter_top",

View File

@ -183,9 +183,12 @@ techage.manual_EN.aTitel = {
"3,TA4 Lua Controller Terminal", "3,TA4 Lua Controller Terminal",
"2,TA4 Logic/Switching Modules", "2,TA4 Logic/Switching Modules",
"3,TA4 Button/Switch", "3,TA4 Button/Switch",
"3,TA4 4x Button",
"3,TA4 Player Detector", "3,TA4 Player Detector",
"3,TA4 State Collector", "3,TA4 State Collector",
"3,TA4 Detector", "3,TA4 Detector",
"3,TA4 Move Controller",
"3,TA4 Sequencer",
"2,TA4 Lamps", "2,TA4 Lamps",
"3,TA4 LED Grow Light", "3,TA4 LED Grow Light",
"3,TA4 Street Lamp", "3,TA4 Street Lamp",
@ -1125,6 +1128,7 @@ techage.manual_EN.aText = {
"The detector is a special tube block that detects when items are passed on through the tube. To do this\\, it must be connected to tubes on both sides. If items are pushed into the detector with a pusher\\, they are automatically passed on.\n".. "The detector is a special tube block that detects when items are passed on through the tube. To do this\\, it must be connected to tubes on both sides. If items are pushed into the detector with a pusher\\, they are automatically passed on.\n"..
"It sends an 'on' when an item is recognized\\, followed by an 'off' a second later.\n".. "It sends an 'on' when an item is recognized\\, followed by an 'off' a second later.\n"..
"Then further commands are blocked for 8 seconds.\n".. "Then further commands are blocked for 8 seconds.\n"..
"The waiting time and the items that should trigger a command can be configured using the open-ended wrench menu. \n"..
"\n".. "\n"..
"\n".. "\n"..
"\n", "\n",
@ -1200,7 +1204,7 @@ techage.manual_EN.aText = {
"\n".. "\n"..
"\n", "\n",
"", "",
"The Techage Info Tool (wrench) has several functions. It shows the time\\, position\\, temperature and biome when an unknown block is clicked on.\n".. "The Techage Info Tool (open-ended wrench) has several functions. It shows the time\\, position\\, temperature and biome when an unknown block is clicked on.\n"..
"If you click on a TechAge block with command interface\\, all available data will be shown (see also \"Logic / switching blocks\").\n".. "If you click on a TechAge block with command interface\\, all available data will be shown (see also \"Logic / switching blocks\").\n"..
"\n".. "\n"..
"With Shift + right click an extended menu can be opened for some blocks. Depending on the block\\, further data can be called up or special settings can be made here. In the case of a generator\\, for example\\, the charging curve/switch-off can be programmed. \n".. "With Shift + right click an extended menu can be opened for some blocks. Depending on the block\\, further data can be called up or special settings can be made here. In the case of a generator\\, for example\\, the charging curve/switch-off can be programmed. \n"..
@ -1556,6 +1560,10 @@ techage.manual_EN.aText = {
"\n".. "\n"..
"\n".. "\n"..
"\n", "\n",
"This block has four buttons that can be individually configured using the wrench menu. The labeling and the target block address can be configured for each button. In addition\\, the command that is to be sent can be configured for each button. \n"..
"\n"..
"\n"..
"\n",
"Only the appearance of the TA4 player detector has changed. The functionality is the same as with the TA3 player detector.\n".. "Only the appearance of the TA4 player detector has changed. The functionality is the same as with the TA3 player detector.\n"..
"\n".. "\n"..
"\n".. "\n"..
@ -1569,6 +1577,50 @@ techage.manual_EN.aText = {
"\n".. "\n"..
"\n".. "\n"..
"\n", "\n",
"The TA4 Move Controller is similar to \"Door Controller 2\"\\, but the selected blocks are not removed\\, but can be moved.\n"..
"Since the moving blocks can take players and mobs standing on the block with them\\, elevators and similar transport systems can be built with them.\n"..
"\n"..
"Instructions:\n"..
"\n"..
" - Set the controller and train the blocks to be moved via the menu (up to 16 blocks can be trained)\n"..
" - the \"flight route\" must be entered via an x\\, y\\, z specification (relative) (the maximum distance is 100 m)\n"..
" - The movement can be tested with the menu buttons \"Move A-B\" and \"Move B-A\"\n"..
" - you can also fly through walls or other blocks\n"..
" - The target position for the blocks can also be occupied. In this case\\, the blocks are saved \"invisibly\". This is intended for sliding doors and the like\n"..
" - A \"handover\" can also be programmed in the controller via the open-ended wrench menu. By entering a block number\\, the blocks are then transferred to the next move controller. In this way\\, connected movements can also be implemented using several Move Controllers.\n"..
"\n"..
"The Move Controller supports the following techage commands:\n"..
"\n"..
" - 'a2b' Move block from A to B.\n"..
" - 'b2a' Move block from B to A.\n"..
" - 'move' Move block to the other side\n"..
"\n"..
"\n"..
"\n",
"Entire processes can be programmed using the TA4 sequencer. Here's an example:\n"..
"\n"..
" -- this is a comment\n"..
" \\[1\\] send 1234 a2b\n"..
" \\[30\\] send 1234 b2a\n"..
" \\[60\\] goto 1\n"..
"\n"..
" - Each line begins with a number which corresponds to a point in time '\\[<num>\\]'\n"..
" - Values from 1 to 50000 are permitted for times\n"..
" - 1 corresponds to 100 ms\\, 50000 corresponds to about 4 game days\n"..
" - Empty lines or comments are allowed ('-- comment')\n"..
" - With 'send <num> <command> <data>' you can send a command to a block\n"..
" - With 'goto <num>' you can jump to another line / point in time\n"..
" - With 'stop' you can stop the sequencer with a delay so that it does not receive a new command\naccepts from a button or other block (to complete a movement)\nWithout 'stop'\\, the sequencer goes into stopped mode immediately after the last command.\n"..
"\n"..
"The TA4 sequencer supports the following techage commands:\n"..
"\n"..
" - 'goto <num>' Jump to a command line and start the sequencer\n"..
" - 'stop' Stop the sequencer\n"..
"\n"..
"The 'goto' command is only accepted when the sequencer is stopped.\n"..
"\n"..
"\n"..
"\n",
"TA4 contains a series of powerful lamps that enable better illumination or take on special tasks.\n".. "TA4 contains a series of powerful lamps that enable better illumination or take on special tasks.\n"..
"\n", "\n",
"The TA4 LED grow light enables fast and vigorous growth of all plants from the 'farming' mod. The lamp illuminates a 3x3 field\\, so that plants can also be grown underground.\n".. "The TA4 LED grow light enables fast and vigorous growth of all plants from the 'farming' mod. The lamp illuminates a 3x3 field\\, so that plants can also be grown underground.\n"..
@ -1931,9 +1983,12 @@ techage.manual_EN.aItemName = {
"ta4_terminal", "ta4_terminal",
"", "",
"ta4_button", "ta4_button",
"ta4_button_4x",
"ta4_playerdetector", "ta4_playerdetector",
"ta4_collector", "ta4_collector",
"ta4_detector", "ta4_detector",
"ta4_movecontroller",
"ta4_sequencer",
"", "",
"ta4_growlight", "ta4_growlight",
"ta4_streetlamp", "ta4_streetlamp",
@ -2153,6 +2208,9 @@ techage.manual_EN.aPlanTable = {
"", "",
"", "",
"", "",
"",
"",
"",
"ta4_liquid_filter_base", "ta4_liquid_filter_base",
"ta4_liquid_filter_gravel", "ta4_liquid_filter_gravel",
"ta4_liquid_filter_top", "ta4_liquid_filter_top",

Binary file not shown.

After

Width:  |  Height:  |  Size: 453 KiB

View File

@ -13,7 +13,7 @@
techage = {} techage = {}
-- Version for compatibility checks, see readme.md/history -- Version for compatibility checks, see readme.md/history
techage.version = 1.02 techage.version = 1.03
if minetest.global_exists("tubelib") then if minetest.global_exists("tubelib") then
minetest.log("error", "[techage] Techage can't be used together with the mod tubelib!") minetest.log("error", "[techage] Techage can't be used together with the mod tubelib!")
@ -30,8 +30,8 @@ elseif minetest.global_exists("tubelib2") and tubelib2.version < 1.9 then
elseif minetest.global_exists("minecart") and minecart.version < 1.08 then elseif minetest.global_exists("minecart") and minecart.version < 1.08 then
minetest.log("error", "[techage] Techage requires minecart version 1.08 or newer!") minetest.log("error", "[techage] Techage requires minecart version 1.08 or newer!")
return return
elseif minetest.global_exists("lcdlib") and lcdlib.version < 1.0 then elseif minetest.global_exists("lcdlib") and lcdlib.version < 1.01 then
minetest.log("error", "[techage] Techage requires lcdlib version 1.0 or newer!") minetest.log("error", "[techage] Techage requires lcdlib version 1.01 or newer!")
return return
elseif minetest.global_exists("safer_lua") and safer_lua.version < 1.0 then elseif minetest.global_exists("safer_lua") and safer_lua.version < 1.0 then
minetest.log("error", "[techage] Techage requires safer_lua version 1.0 or newer!") minetest.log("error", "[techage] Techage requires safer_lua version 1.0 or newer!")
@ -73,6 +73,7 @@ end
-- Basis features -- Basis features
local MP = minetest.get_modpath("techage") local MP = minetest.get_modpath("techage")
dofile(MP.."/basis/lib.lua") -- helper functions dofile(MP.."/basis/lib.lua") -- helper functions
dofile(MP.."/basis/counting.lua") -- command counting
dofile(MP.."/basis/fake_player.lua") -- dummy player object dofile(MP.."/basis/fake_player.lua") -- dummy player object
dofile(MP.."/basis/node_store.lua") dofile(MP.."/basis/node_store.lua")
dofile(MP.."/basis/gravel_lib.lua") -- ore probability dofile(MP.."/basis/gravel_lib.lua") -- ore probability
@ -263,6 +264,7 @@ dofile(MP.."/logic/repeater.lua")
dofile(MP.."/logic/programmer.lua") dofile(MP.."/logic/programmer.lua")
dofile(MP.."/logic/signallamp.lua") dofile(MP.."/logic/signallamp.lua")
dofile(MP.."/logic/sequencer.lua") dofile(MP.."/logic/sequencer.lua")
dofile(MP.."/logic/sequencer2.lua")
dofile(MP.."/logic/timer.lua") dofile(MP.."/logic/timer.lua")
dofile(MP.."/logic/lua_logic.lua") -- old dofile(MP.."/logic/lua_logic.lua") -- old
dofile(MP.."/logic/logic_block.lua") -- new dofile(MP.."/logic/logic_block.lua") -- new
@ -274,6 +276,8 @@ dofile(MP.."/logic/doorblock.lua")
dofile(MP.."/logic/doorcontroller.lua") -- old dofile(MP.."/logic/doorcontroller.lua") -- old
dofile(MP.."/logic/doorcontroller2.lua") -- new dofile(MP.."/logic/doorcontroller2.lua") -- new
dofile(MP.."/logic/collector.lua") dofile(MP.."/logic/collector.lua")
dofile(MP.."/logic/button_4x.lua")
dofile(MP.."/logic/movecontroller.lua")
if minetest.global_exists("mesecon") then if minetest.global_exists("mesecon") then
dofile(MP.."/logic/mesecons_converter.lua") dofile(MP.."/logic/mesecons_converter.lua")
end end

View File

@ -74,12 +74,12 @@ local function node_timer(pos, elapsed)
if not inv:is_empty("src") then if not inv:is_empty("src") then
local taken = techage.get_items(pos, inv, "src", 1) local taken = techage.get_items(pos, inv, "src", 1)
if liquid.is_container_empty(taken:get_name()) then if liquid.is_container_empty(taken:get_name()) then
return liquid.fill_container({x = pos.x, y = pos.y+1, z = pos.z}, inv, taken:get_name()) liquid.fill_container({x = pos.x, y = pos.y+1, z = pos.z}, inv, taken:get_name())
else else
return liquid.empty_container({x = pos.x, y = pos.y-1, z = pos.z}, inv, taken:get_name()) liquid.empty_container({x = pos.x, y = pos.y-1, z = pos.z}, inv, taken:get_name())
end end
end end
return false return true
end end
minetest.register_node("techage:filler", { minetest.register_node("techage:filler", {

View File

@ -45,7 +45,6 @@ local function pumping(pos, nvm, state, capa)
local mem = techage.get_mem(pos) local mem = techage.get_mem(pos)
mem.dbg_cycles = (mem.dbg_cycles or 0) - 1 mem.dbg_cycles = (mem.dbg_cycles or 0) - 1
local outdir = M(pos):get_int("outdir") local outdir = M(pos):get_int("outdir")
--print("pumping", outdir, Flip[outdir])
local taken, name = liquid.take(pos, Pipe, Flip[outdir], nil, capa, mem.dbg_cycles > 0) local taken, name = liquid.take(pos, Pipe, Flip[outdir], nil, capa, mem.dbg_cycles > 0)
if taken > 0 then if taken > 0 then
local leftover = liquid.put(pos, Pipe, outdir, name, taken, mem.dbg_cycles > 0) local leftover = liquid.put(pos, Pipe, outdir, name, taken, mem.dbg_cycles > 0)

View File

@ -53,6 +53,9 @@ end
local function take_liquid(pos, indir, name, amount) local function take_liquid(pos, indir, name, amount)
local nvm = techage.get_nvm(pos) local nvm = techage.get_nvm(pos)
if (M(pos):get_int("keep_assignment") or 0) == 1 then
amount = math.max(math.min(amount, ((nvm.liquid or {}).amount or 0) - 1), 0)
end
amount, name = liquid.srv_take(nvm, name, amount) amount, name = liquid.srv_take(nvm, name, amount)
if techage.is_activeformspec(pos) then if techage.is_activeformspec(pos) then
M(pos):set_string("formspec", techage.liquid.formspec(pos, nvm)) M(pos):set_string("formspec", techage.liquid.formspec(pos, nvm))
@ -219,6 +222,9 @@ minetest.register_node("techage:ta4_tank", {
if fields.public then if fields.public then
M(pos):set_int("public", fields.public == "true" and 1 or 0) M(pos):set_int("public", fields.public == "true" and 1 or 0)
end end
if fields.keep_assignment then
M(pos):set_int("keep_assignment", fields.keep_assignment == "true" and 1 or 0)
end
end, end,
on_timer = node_timer, on_timer = node_timer,
on_punch = techage.liquid.on_punch, on_punch = techage.liquid.on_punch,

View File

@ -43,6 +43,9 @@ minetest.register_node("techage:ta3_valve_open", {
return false return false
end, end,
on_rightclick = function(pos, node, clicker) on_rightclick = function(pos, node, clicker)
if minetest.is_protected(pos, clicker:get_player_name()) then
return
end
if liquid.turn_valve_off(pos, Pipe, "techage:ta3_valve_closed", "techage:ta3_valve_open") then if liquid.turn_valve_off(pos, Pipe, "techage:ta3_valve_closed", "techage:ta3_valve_open") then
minetest.sound_play("techage_valve", { minetest.sound_play("techage_valve", {
pos = pos, pos = pos,
@ -84,6 +87,9 @@ minetest.register_node("techage:ta3_valve_closed", {
}, },
on_rightclick = function(pos, node, clicker) on_rightclick = function(pos, node, clicker)
if minetest.is_protected(pos, clicker:get_player_name()) then
return
end
if liquid.turn_valve_on(pos, Pipe, "techage:ta3_valve_closed", "techage:ta3_valve_open") then if liquid.turn_valve_on(pos, Pipe, "techage:ta3_valve_closed", "techage:ta3_valve_open") then
minetest.sound_play("techage_valve", { minetest.sound_play("techage_valve", {
pos = pos, pos = pos,

View File

@ -113,6 +113,12 @@ Access:=Zugriff:
TA3 Button/Switch=TA3 Taster/Schalter TA3 Button/Switch=TA3 Taster/Schalter
TA4 Button/Switch=TA4 Schalter/Taster TA4 Button/Switch=TA4 Schalter/Taster
### button.lua ###
### button_4x.lua ###
### signallamp_4x.lua ###
Command=Kommando
### button.lua ### ### button.lua ###
### cart_detector.lua ### ### cart_detector.lua ###
### detector.lua ### ### detector.lua ###
@ -130,10 +136,33 @@ Insert destination node number(s)=Gebe Zielnummer(n) ein
### doorcontroller.lua ### ### doorcontroller.lua ###
### mesecons_converter.lua ### ### mesecons_converter.lua ###
### repeater.lua ### ### repeater.lua ###
### sequencer2.lua ###
### submenu.lua ### ### submenu.lua ###
Save=Speichern Save=Speichern
### button.lua ###
### signallamp_4x.lua ###
Command to be sent=Zu sendender Befehl
### button_4x.lua ###
Command to be sent (ignored for switches)=Zu sendender Befehl (wird für Schalter ignoriert)
Label=Beschriftung
Label for the button=Beschriftung für die Taste
Momentary button or on/off switch=Taster oder Ein-/Ausschalter
TA4 4x Button=TA4 4x Taster
Type=Typ
### button_4x.lua ###
### signallamp_4x.lua ###
Access=Zugriff
Button protection=Tastenschutz
Destination block number=Zielblocknummer
Number=Nummer
### cart_detector.lua ### ### cart_detector.lua ###
TA3 Cart Detector=TA3 Wagen Detektor TA3 Cart Detector=TA3 Wagen Detektor
@ -204,14 +233,32 @@ TA3 Melting=TA3 Schmelzen
TA3 Cooler=TA3 Kühler TA3 Cooler=TA3 Kühler
### counting.lua ###
Your current value is=Der aktuelle Wert ist
[techage] The limit for 'number of commands per minute' has been exceeded.=[techage] Das Limit für 'Anzahl Befehle pro Minute' wurde überschritten.
is allowed=ist erlaubt
is allowed. Current value is=ist erlaubt. Aktueller Wert ist
per minute=pro Minute
### cylinder.lua ### ### cylinder.lua ###
TA2 Cylinder=TA2 Zylinder TA2 Cylinder=TA2 Zylinder
### detector.lua ### ### detector.lua ###
Configured Items=Konfigurierte Gegenstände
Items which generate an 'on' command.@nIf empty, all passed items generate an 'on' command.=Items, die einen 'on'-Kommando generieren.@nWenn leer, generieren alle übergebenen Items einen 'on'-Befehl.
On Time=ON Zeit
TA3 Detector=TA3 Detektor TA3 Detector=TA3 Detektor
TA4 Detector=TA4 Detektor TA4 Detector=TA4 Detektor
The time after the 'off' command@nuntil the next 'on' command is accepted.=Die Zeit nach dem 'off' Kommando,@nbis das nächste 'on' Kommando akzeptiert wird.
The time between the 'on' and 'off' commands.=Die Zeit zwischen den 'on' und 'off' Kommandos.
### detector.lua ###
### logic_block.lua ###
Blocking Time=Sperrzeit
### display.lua ### ### display.lua ###
@ -250,15 +297,19 @@ Blocks are back=Blöcke sind wieder da
Blocks are disappeared=Blöcke sind verschwunden Blocks are disappeared=Blöcke sind verschwunden
Click on all the blocks that are part of the door/gate=Klicke auf alle Blöcke, die Teil des Tores sind Click on all the blocks that are part of the door/gate=Klicke auf alle Blöcke, die Teil des Tores sind
Ctrl,Inv=Ctrl,Inv Ctrl,Inv=Ctrl,Inv
Done=Fertig
Record=Aufzeichnen
Recording...=Aufzeichnung...
Remove=Entfernen Remove=Entfernen
Set=Setzen Set=Setzen
TA3 Door Controller II=TA3 Tür Controller II TA3 Door Controller II=TA3 Tür Controller II
block positions are stored.=Block Positionen gespeichert.
with door sound=mit Türgeräusch with door sound=mit Türgeräusch
### doorcontroller2.lua ###
### movecontroller.lua ###
Done=Fertig
Record=Aufzeichnen
Recording...=Aufzeichnung...
block positions are stored.=Block Positionen gespeichert.
### drillbox.lua ### ### drillbox.lua ###
Build derrick=Errichte Ölturm Build derrick=Errichte Ölturm
@ -370,6 +421,7 @@ loaded=geladen
### formspecs.lua ### ### formspecs.lua ###
Block has a wrench menu=Block hat ein Gabelschlüssel-Menü
Charge termination=Ladebegrenzung Charge termination=Ladebegrenzung
Current output [ku]=Aktueller Ausgabewert Current output [ku]=Aktueller Ausgabewert
Maximum output [ku]=Maximaler Ausgabewert Maximum output [ku]=Maximaler Ausgabewert
@ -570,6 +622,11 @@ Allow public access to the tank=Erlaube öffentlichen Zugriff auf den Tank
Liquid Tank=Flüssigkeitstank Liquid Tank=Flüssigkeitstank
To add liquids punch@nthe tank@nwith a liquid container=Um Flüssigkeit nachzufüllen,@nschlage mit einem Flüssigkeitsbehälter@nauf den Block To add liquids punch@nthe tank@nwith a liquid container=Um Flüssigkeit nachzufüllen,@nschlage mit einem Flüssigkeitsbehälter@nauf den Block
### liquid_lib.lua ###
### ta4_chest.lua ###
keep assignment=Zuordnung beibehalten
### liquid_pipe.lua ### ### liquid_pipe.lua ###
TA Junction Pipe=TA Leitungskupplung TA Junction Pipe=TA Leitungskupplung
@ -595,8 +652,8 @@ no usable water=Kein brauchbares Wasser
@nRule:@n<output> @= on/off if <input-expression> is true@n=@nRegel:@n<output> @= on/off if <input-expression> is true@n @nRule:@n<output> @= on/off if <input-expression> is true@n=@nRegel:@n<output> @= on/off if <input-expression> is true@n
@nThe internal processing time for all@ncommands is 100 ms.=@nDie interne Durchlaufzeit für alle@nKommandos beträgt 100 ms. @nThe internal processing time for all@ncommands is 100 ms.=@nDie interne Durchlaufzeit für alle@nKommandos beträgt 100 ms.
@nValid operators:@nand or on off me @=@= ~@= ( )@n=@nGültige Operatoren:@nand or on off @=@= ~@= ( )@n @nValid operators:@nand or on off me @=@= ~@= ( )@n=@nGültige Operatoren:@nand or on off @=@= ~@= ( )@n
Blocking Time=Sperrzeit Clear=Löschen
Help=Hilfe Debug=Debug
Inputs=Eingänge Inputs=Eingänge
Outputs=Ausgänge Outputs=Ausgänge
Rules=Regeln Rules=Regeln
@ -606,10 +663,20 @@ Syntax=Syntax
### logic_block.lua ### ### logic_block.lua ###
### lua_logic.lua ### ### lua_logic.lua ###
Store=Speichern
TA3 Logic Block=TA3 Logikblock TA3 Logic Block=TA3 Logikblock
Update=Update Update=Update
### logic_block.lua ###
### lua_logic.lua ###
### movecontroller.lua ###
Store=Speichern
### logic_block.lua ###
### sequencer2.lua ###
Help=Hilfe
### lye.lua ### ### lye.lua ###
Lye=Lauge Lye=Lauge
@ -667,6 +734,28 @@ TA1 Pine Wood Board=TA1 Kiefernholzbrett
TA4 Streetlamp Solar Cell=TA4 Straßenlampen-Solarzelle TA4 Streetlamp Solar Cell=TA4 Straßenlampen-Solarzelle
### movecontroller.lua ###
Click on all blocks that shall be moved=Klicke auf alle Blöcke, die verschoben werden sollen
Destination position is protected=Zielposition ist geschützt
Error: Distance > 100 m !!=Fehler: Distanz > 100 m !!
Handover to A=Übergabe an A
Handover to B=Übergabe an B
Maximum Speed=Maximalgeschwindigkeit
Maximum speed for the moving block.=Maximale Geschwindigkeit für den beweglichen Block.
Move A-B=Bewege A-B
Move B-A=Bewege B-A
Move block height=Move Block Höhe
Move distance (A to B)=Entfernung (A nach B)
No valid destination position=Keine gültige Zielposition
No valid node at the start position=Kein gültiger Block an der Startposition
Number of the next movecontroller.=Nummer des nächsten Move Controllers.
Number of the previous movecontroller.=Nummer des vorherigen Move Controllers.
Position list error=Positionslistenfehler
Start position is protected=Startposition ist geschützt
TA4 Move Controller=TA4 Move Controller
Value in the range of 0.0 to 1.0=Wert im Bereich von 0.0 bis 1.0
### node_detector.lua ### ### node_detector.lua ###
Send signal if nodes have been:=Sende ein Signal falls Blöcke: Send signal if nodes have been:=Sende ein Signal falls Blöcke:
@ -750,7 +839,7 @@ TA Power Pole Top 2 (for landlines)=TA Strommastkopf 2 (für Überlandleitungen)
### power_terminal2.lua ### ### power_terminal2.lua ###
Commands@nhelp . . . print this text@ncls . . . . . clear screen@ngen . . . . print all generators@nsto . . . . . print all storage systems@n=Kommandos@nhelp . . . diesen Text ausgeben@ncls . . . . . Bildschirm löschen@ngen . . . . Alle Generatoren ausgeben@nsto . . . . . Alle Speichersysteme ausgeben@n Commands@nhelp . . . print this text@ncls . . . . . clear screen@ngen . . . . print all generators@nsto . . . . . print all storage systems@ncon . . . . . print main consumers@n=Kommandos@nhelp . . . diesen Text ausgeben@ncls . . . . . Bildschirm löschen@ngen . . . . Alle Generatoren ausgeben@nsto . . . . . Alle Speichersysteme ausgeben@ncon . . . . . Hauptverbraucher ausgeben@n
Consumer=Verbraucher Consumer=Verbraucher
Network Data=Netzwerkdaten Network Data=Netzwerkdaten
Number of consumers:=Anzahl der Verbraucher Number of consumers:=Anzahl der Verbraucher
@ -877,14 +966,48 @@ not connected=nicht verbunden
### sequencer.lua ### ### sequencer.lua ###
TA3 Sequencer=TA3 Sequenzer TA3 Sequencer=TA3 Sequenzer
### sequencer.lua ###
### sequencer2.lua ###
stopped=gestoppt stopped=gestoppt
### sequencer2.lua ###
- 'goto <num>' (jump to another line)@n= - 'goto <num>' (springe zu einer anderen Zeile)@n
- 'send <node num> <cmnd>' (techage command)@n= - 'send <node num> <cmnd>' (techage Kommando)@n
- 'stop' (stop the execution)@n= - 'stop' (stoppe die Ausführung)@n
- 1 corresponds to 100 ms@n= - 1 entspricht 100 ms@n
- 50000 corresponds to 4 game days@n= - 50000 entspricht 4 Spieltagen@n
'[<num>] <command>'@n='[<num>] <command>'@n
<command> is one of the following:@n=<command> ist eines der folgenden:@n
<num> is a number from 1 to 50000 and is@n=<num> ist eine Nummer von 1 bis 50000 und ist@n
@n=@n
Commands=Kommandos
Example:@n=Beispiel:
Invalid command!=Ungültiges Kommando!
Start=Start
Stop=Stopp
Syntax:@n=Syntax:@n
TA4 Sequencer=TA4 Sequenzer
running=läuft
the timeslot when the command is executed.@n=der Zeitpunkt, wenn der Befehl ausgeführt wird.@n
### sequencer2.lua ###
### submenu.lua ###
Cancel=Abbruch
### signallamp.lua ### ### signallamp.lua ###
TA4 Wind Turbine Signal Lamp=TA4 Windkraftanlagenlampe TA4 Wind Turbine Signal Lamp=TA4 Windkraftanlagenlampe
TechAge Signal Lamp=TechAge Signallampe TechAge Signal Lamp=TechAge Signallampe
TechAge Signal Lamp (can be colored)=TechAge Signallampe (kann gefärbt werden) TechAge Signal Lamp (can be colored)=TechAge Signallampe (kann gefärbt werden)
### signallamp_4x.lua ###
TA4 4x Signal Lamp=
### silicon.lua ### ### silicon.lua ###
TA4 Silicon Wafer=TA4 Silizium-Wafer TA4 Silicon Wafer=TA4 Silizium-Wafer
@ -902,7 +1025,6 @@ TA Lamp=TA Lampe
TA1 Sluice Gate=TA1 Schleusenschieber TA1 Sluice Gate=TA1 Schleusenschieber
TA1 Sluice Handle=TA1 Schleusengriff TA1 Sluice Handle=TA1 Schleusengriff
Your pond is too small!=Der Teich ist zu klein!
### solarcell.lua ### ### solarcell.lua ###
@ -948,7 +1070,6 @@ TA4 LED Street Lamp Pole=TA4 LED Lampenmast
### submenu.lua ### ### submenu.lua ###
Cancel=Abbruch
Note: You can't change any values while the block is running!=Hinweis: Während der Block läuft, kann kein Wert geändert werden! Note: You can't change any values while the block is running!=Hinweis: Während der Block läuft, kann kein Wert geändert werden!
Refresh=Aktualisieren Refresh=Aktualisieren
@ -982,7 +1103,6 @@ Size=Größe
TA4 8x2000 Chest=TA4 8x2000 Kiste TA4 8x2000 Chest=TA4 8x2000 Kiste
Unlock=Entsperren Unlock=Entsperren
Unlock connected chest@nif all slots are below 2000=Nachfolgende Kiste entsperren,@nsofern alle Speicherplätze <= 2000 Unlock connected chest@nif all slots are below 2000=Nachfolgende Kiste entsperren,@nsofern alle Speicherplätze <= 2000
keep assignment=Zuordnung beibehalten
right to left=von rechts nach links right to left=von rechts nach links
### ta4_doser.lua ### ### ta4_doser.lua ###
@ -1099,11 +1219,6 @@ Usmium Powder=Usmium Pulver
TA Valve=TA Ventil TA Valve=TA Ventil
TA3 Valve=TA3 Ventil TA3 Valve=TA3 Ventil
### water.lua ###
Flowing Water=Fließendes Wasser
Water Source=Wasserquelle
### waterinlet.lua ### ### waterinlet.lua ###
Error: No natural water!=Fehler: Kein natürliches Wasser! Error: No natural water!=Fehler: Kein natürliches Wasser!
@ -1132,3 +1247,8 @@ This is not the surface of the ocean!=Das ist nicht die Meeresoberfläche!
[TA4 Wind Turbine]=[TA4 Windkraftanlage] [TA4 Wind Turbine]=[TA4 Windkraftanlage]
biome and no ocean!=Biom und keine Meer (ocean)! biome and no ocean!=Biom und keine Meer (ocean)!
is a suitable place for a wind turbine!=ist ein geeigneter Ort für eine Windkraftanlage! is a suitable place for a wind turbine!=ist ein geeigneter Ort für eine Windkraftanlage!
##### not used anymore #####
[techage] The limit for commands per minute has been exceeded.=[techage] Das Limit für Befehle pro Minute wurde überschritten.

View File

@ -113,6 +113,12 @@ Access:=
TA3 Button/Switch= TA3 Button/Switch=
TA4 Button/Switch= TA4 Button/Switch=
### button.lua ###
### button_4x.lua ###
### signallamp_4x.lua ###
Command=
### button.lua ### ### button.lua ###
### cart_detector.lua ### ### cart_detector.lua ###
### detector.lua ### ### detector.lua ###
@ -130,10 +136,33 @@ Insert destination node number(s)=
### doorcontroller.lua ### ### doorcontroller.lua ###
### mesecons_converter.lua ### ### mesecons_converter.lua ###
### repeater.lua ### ### repeater.lua ###
### sequencer2.lua ###
### submenu.lua ### ### submenu.lua ###
Save= Save=
### button.lua ###
### signallamp_4x.lua ###
Command to be sent=
### button_4x.lua ###
Command to be sent (ignored for switches)=
Label=
Label for the button=
Momentary button or on/off switch=
TA4 4x Button=
Type=
### button_4x.lua ###
### signallamp_4x.lua ###
Access=
Button protection=
Destination block number=
Number=
### cart_detector.lua ### ### cart_detector.lua ###
TA3 Cart Detector= TA3 Cart Detector=
@ -204,14 +233,32 @@ TA3 Melting=
TA3 Cooler= TA3 Cooler=
### counting.lua ###
Your current value is=
[techage] The limit for 'number of commands per minute' has been exceeded.=
is allowed=
is allowed. Current value is=
per minute=
### cylinder.lua ### ### cylinder.lua ###
TA2 Cylinder= TA2 Cylinder=
### detector.lua ### ### detector.lua ###
Configured Items=
Items which generate an 'on' command.@nIf empty, all passed items generate an 'on' command.=
On Time=
TA3 Detector= TA3 Detector=
TA4 Detector= TA4 Detector=
The time after the 'off' command@nuntil the next 'on' command is accepted.=
The time between the 'on' and 'off' commands.=
### detector.lua ###
### logic_block.lua ###
Blocking Time=
### display.lua ### ### display.lua ###
@ -250,15 +297,19 @@ Blocks are back=
Blocks are disappeared= Blocks are disappeared=
Click on all the blocks that are part of the door/gate= Click on all the blocks that are part of the door/gate=
Ctrl,Inv= Ctrl,Inv=
Done=
Record=
Recording...=
Remove= Remove=
Set= Set=
TA3 Door Controller II= TA3 Door Controller II=
block positions are stored.=
with door sound= with door sound=
### doorcontroller2.lua ###
### movecontroller.lua ###
Done=
Record=
Recording...=
block positions are stored.=
### drillbox.lua ### ### drillbox.lua ###
Build derrick= Build derrick=
@ -370,6 +421,7 @@ loaded=
### formspecs.lua ### ### formspecs.lua ###
Block has a wrench menu=
Charge termination= Charge termination=
Current output [ku]= Current output [ku]=
Maximum output [ku]= Maximum output [ku]=
@ -570,6 +622,11 @@ Allow public access to the tank=
Liquid Tank= Liquid Tank=
To add liquids punch@nthe tank@nwith a liquid container= To add liquids punch@nthe tank@nwith a liquid container=
### liquid_lib.lua ###
### ta4_chest.lua ###
keep assignment=
### liquid_pipe.lua ### ### liquid_pipe.lua ###
TA Junction Pipe= TA Junction Pipe=
@ -595,8 +652,8 @@ no usable water=
@nRule:@n<output> @= on/off if <input-expression> is true@n= @nRule:@n<output> @= on/off if <input-expression> is true@n=
@nThe internal processing time for all@ncommands is 100 ms.= @nThe internal processing time for all@ncommands is 100 ms.=
@nValid operators:@nand or on off me @=@= ~@= ( )@n= @nValid operators:@nand or on off me @=@= ~@= ( )@n=
Blocking Time= Clear=
Help= Debug=
Inputs= Inputs=
Outputs= Outputs=
Rules= Rules=
@ -606,10 +663,20 @@ Syntax=
### logic_block.lua ### ### logic_block.lua ###
### lua_logic.lua ### ### lua_logic.lua ###
Store=
TA3 Logic Block= TA3 Logic Block=
Update= Update=
### logic_block.lua ###
### lua_logic.lua ###
### movecontroller.lua ###
Store=
### logic_block.lua ###
### sequencer2.lua ###
Help=
### lye.lua ### ### lye.lua ###
Lye= Lye=
@ -667,6 +734,28 @@ TA1 Pine Wood Board=
TA4 Streetlamp Solar Cell= TA4 Streetlamp Solar Cell=
### movecontroller.lua ###
Click on all blocks that shall be moved=
Destination position is protected=
Error: Distance > 100 m !!=
Handover to A=
Handover to B=
Maximum Speed=
Maximum speed for the moving block.=
Move A-B=
Move B-A=
Move block height=
Move distance (A to B)=
No valid destination position=
No valid node at the start position=
Number of the next movecontroller.=
Number of the previous movecontroller.=
Position list error=
Start position is protected=
TA4 Move Controller=
Value in the range of 0.0 to 1.0=
### node_detector.lua ### ### node_detector.lua ###
Send signal if nodes have been:= Send signal if nodes have been:=
@ -750,7 +839,7 @@ TA Power Pole Top 2 (for landlines)=
### power_terminal2.lua ### ### power_terminal2.lua ###
Commands@nhelp . . . print this text@ncls . . . . . clear screen@ngen . . . . print all generators@nsto . . . . . print all storage systems@n= Commands@nhelp . . . print this text@ncls . . . . . clear screen@ngen . . . . print all generators@nsto . . . . . print all storage systems@ncon . . . . . print main consumers@n=
Consumer= Consumer=
Network Data= Network Data=
Number of consumers:= Number of consumers:=
@ -877,14 +966,48 @@ not connected=
### sequencer.lua ### ### sequencer.lua ###
TA3 Sequencer= TA3 Sequencer=
### sequencer.lua ###
### sequencer2.lua ###
stopped= stopped=
### sequencer2.lua ###
- 'goto <num>' (jump to another line)@n=
- 'send <node num> <cmnd>' (techage command)@n=
- 'stop' (stop the execution)@n=
- 1 corresponds to 100 ms@n=
- 50000 corresponds to 4 game days@n=
'[<num>] <command>'@n=
<command> is one of the following:@n=
<num> is a number from 1 to 50000 and is@n=
@n=
Commands=
Example:@n=
Invalid command!=
Start=
Stop=
Syntax:@n=
TA4 Sequencer=
running=
the timeslot when the command is executed.@n=
### sequencer2.lua ###
### submenu.lua ###
Cancel=
### signallamp.lua ### ### signallamp.lua ###
TA4 Wind Turbine Signal Lamp= TA4 Wind Turbine Signal Lamp=
TechAge Signal Lamp= TechAge Signal Lamp=
TechAge Signal Lamp (can be colored)= TechAge Signal Lamp (can be colored)=
### signallamp_4x.lua ###
TA4 4x Signal Lamp=
### silicon.lua ### ### silicon.lua ###
TA4 Silicon Wafer= TA4 Silicon Wafer=
@ -902,7 +1025,6 @@ TA Lamp=
TA1 Sluice Gate= TA1 Sluice Gate=
TA1 Sluice Handle= TA1 Sluice Handle=
Your pond is too small!=
### solarcell.lua ### ### solarcell.lua ###
@ -948,7 +1070,6 @@ TA4 LED Street Lamp Pole=
### submenu.lua ### ### submenu.lua ###
Cancel=
Note: You can't change any values while the block is running!= Note: You can't change any values while the block is running!=
Refresh= Refresh=
@ -982,7 +1103,6 @@ Size=
TA4 8x2000 Chest= TA4 8x2000 Chest=
Unlock= Unlock=
Unlock connected chest@nif all slots are below 2000= Unlock connected chest@nif all slots are below 2000=
keep assignment=
right to left= right to left=
### ta4_doser.lua ### ### ta4_doser.lua ###
@ -1099,11 +1219,6 @@ Usmium Powder=
TA Valve= TA Valve=
TA3 Valve= TA3 Valve=
### water.lua ###
Flowing Water=
Water Source=
### waterinlet.lua ### ### waterinlet.lua ###
Error: No natural water!= Error: No natural water!=

View File

@ -19,6 +19,16 @@ local NDEF = function(pos) return (minetest.registered_nodes[techage.get_node_lv
local logic = techage.logic local logic = techage.logic
local WRENCH_MENU = {
{
type = "ascii",
name = "command",
label = S("Command"),
tooltip = S("Command to be sent"),
default = "on",
},
}
local function switch_on(pos) local function switch_on(pos)
local cycle_time = M(pos):get_int("cycle_time") local cycle_time = M(pos):get_int("cycle_time")
local name = techage.get_node_lvm(pos).name local name = techage.get_node_lvm(pos).name
@ -27,7 +37,10 @@ local function switch_on(pos)
elseif name == "techage:ta4_button_off" then elseif name == "techage:ta4_button_off" then
logic.swap_node(pos, "techage:ta4_button_on") logic.swap_node(pos, "techage:ta4_button_on")
end end
logic.send_on(pos, M(pos), cycle_time) local meta = M(pos)
local s = meta:contains("command") and meta:get_string("command") or "on"
local command, payload = unpack(string.split(s, " ", false, 1))
logic.send_cmnd(pos, M(pos), command, payload, cycle_time)
minetest.sound_play("techage_button", { minetest.sound_play("techage_button", {
pos = pos, pos = pos,
gain = 0.5, gain = 0.5,
@ -249,6 +262,7 @@ minetest.register_node("techage:ta4_button_off", {
meta:set_int("cycle_time", 0) meta:set_int("cycle_time", 0)
end, end,
ta4_formspec = WRENCH_MENU,
on_receive_fields = on_receive_fields, on_receive_fields = on_receive_fields,
on_rightclick = on_rightclick_on, on_rightclick = on_rightclick_on,
techage_set_numbers = techage_set_numbers, techage_set_numbers = techage_set_numbers,

297
techage/logic/button_4x.lua Normal file
View File

@ -0,0 +1,297 @@
--[[
TechAge
=======
Copyright (C) 2017-2021 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA4 Logic fourfold button
]]--
-- for lazy programmers
local M = minetest.get_meta
local S = techage.S
local function get_button_num(pos, clicker, pointed_thing)
-- use the node behind the button to get better results
if clicker and pointed_thing then
local offs = vector.subtract(pointed_thing.under, pointed_thing.above)
pointed_thing.under = vector.add(pointed_thing.under, offs)
pointed_thing.above = vector.add(pointed_thing.above, offs)
local pos1 = minetest.pointed_thing_to_face_pos(clicker, pointed_thing)
local y = pos1.y - pos.y
if y < -0.3 then
return 4
elseif y < -0.03 and y > -0.22 then
return 3
elseif y > 0.03 and y < 0.22 then
return 2
elseif y > 0.3 then
return 1
end
end
end
local WRENCH_MENU = {
{
type = "dropdown",
choices = "button,switch",
name = "type",
label = S("Type"),
tooltip = S("Momentary button or on/off switch"),
default = "1",
},
{
type = "ascii",
name = "label1",
label = S("Label") .. " 1",
tooltip = S("Label for the button"),
default = "1",
},
{
type = "numbers",
name = "dest_number1",
label = S("Number") .. " 1",
tooltip = S("Destination block number"),
default = "",
},
{
type = "ascii",
name = "command1",
label = S("Command") .. " 1",
tooltip = S("Command to be sent (ignored for switches)"),
default = "1",
},
{
type = "ascii",
name = "label2",
label = S("Label") .. " 2",
tooltip = S("Label for the button"),
default = "1",
},
{
type = "numbers",
name = "dest_number2",
label = S("Number") .. " 2",
tooltip = S("Destination block number"),
default = "",
},
{
type = "ascii",
name = "command2",
label = S("Command") .. " 2",
tooltip = S("Command to be sent (ignored for switches)"),
default = "2",
},
{
type = "ascii",
name = "label3",
label = S("Label") .. " 3",
tooltip = S("Label for the button"),
default = "1",
},
{
type = "numbers",
name = "dest_number3",
label = S("Number") .. " 3",
tooltip = S("Destination block number"),
default = "",
},
{
type = "ascii",
name = "command3",
label = S("Command") .. " 3",
tooltip = S("Command to be sent (ignored for switches)"),
default = "3",
},
{
type = "ascii",
name = "label4",
label = S("Label") .. " 4",
tooltip = S("Label for the button"),
default = "1",
},
{
type = "numbers",
name = "dest_number4",
label = S("Number") .. " 4",
tooltip = S("Destination block number"),
default = "",
},
{
type = "ascii",
name = "command4",
label = S("Command") .. " 4",
tooltip = S("Command to be sent (ignored for switches)"),
default = "4",
},
{
type = "dropdown",
choices = "private,protected,public",
name = "access",
label = S("Access"),
tooltip = S("Button protection"),
default = "8",
},
}
local function send_cmnd(pos, num, cmd)
local meta = M(pos)
local own_num = meta:get_string("node_number")
local dest = meta:get_string("dest_number" .. num)
local command, payload = cmd, nil
if not cmd then
local s = meta:get_string("command" .. num)
command, payload = unpack(string.split(s, " ", false, 1))
end
local owner = meta:get_string("owner")
if techage.check_numbers(dest, owner) then
techage.send_multi(own_num, dest, command, payload)
end
end
local function button_update(pos, objref)
local meta = M(pos)
pos = vector.round(pos)
local nvm = techage.get_nvm(pos)
nvm.button = nvm.button or {}
local tbl = {meta:get_string("label1"), " ", meta:get_string("label2"), " ", meta:get_string("label3"), " ", meta:get_string("label4")}
local text = "< " .. table.concat(tbl, "\n< ")
local texture = lcdlib.make_multiline_texture("default", text, 96, 96, 7, "top", "#000", 6)
if nvm.button[1] then
texture = texture .. "^techage_smartline_button_4x_on1.png"
end
if nvm.button[2] then
texture = texture .. "^techage_smartline_button_4x_on2.png"
end
if nvm.button[3] then
texture = texture .. "^techage_smartline_button_4x_on3.png"
end
if nvm.button[4] then
texture = texture .. "^techage_smartline_button_4x_on4.png"
end
objref:set_properties({ textures = {texture}, visual_size = {x=1, y=1} })
end
local function switch_off(pos, num)
local nvm = techage.get_nvm(pos)
nvm.button = nvm.button or {}
nvm.button[num] = nil
lcdlib.update_entities(pos)
end
local function switch_on(pos, num)
local nvm = techage.get_nvm(pos)
nvm.button = nvm.button or {}
nvm.button[num] = true
lcdlib.update_entities(pos)
end
local lcd_box = {-8/16, -8/16, 7.75/16, 8/16, 8/16, 8/16}
minetest.register_node("techage:ta4_button_4x", {
description = S("TA4 4x Button"),
inventory_image = 'techage_smartline_button_4x.png',
tiles = {'techage_smartline_button_4x.png'},
drawtype = "nodebox",
paramtype = "light",
use_texture_alpha = "clip",
sunlight_propagates = true,
paramtype2 = "facedir",
node_box = {
type = "fixed",
fixed = lcd_box,
},
light_source = 6,
display_entities = {
["techage:display_entity"] = { depth = 0.48,
on_display_update = button_update},
},
after_place_node = function(pos, placer)
local number = techage.add_node(pos, "techage:ta4_button_4x")
local meta = minetest.get_meta(pos)
meta:set_string("node_number", number)
meta:set_string("owner", placer:get_player_name())
meta:set_string("infotext", "TA4 4x Button " .. number)
meta:set_string("type", "button")
meta:set_string("label1", "B1")
meta:set_string("label2", "B2")
meta:set_string("label3", "B3")
meta:set_string("label4", "B4")
lcdlib.update_entities(pos)
end,
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
if clicker and clicker:is_player() then
local playername = clicker:get_player_name()
if minetest.is_protected(pos, playername) then
return
end
-- Check node settings in addition
local access = M(pos):get_string("access")
local owner = M(pos):get_string("owner")
if access == "private" and playername ~= owner then
return
end
local num = get_button_num(pos, clicker, pointed_thing)
if num then
local typ = M(pos):get_string("type")
if typ == "switch" then
local nvm = techage.get_nvm(pos)
nvm.button = nvm.button or {}
if nvm.button[num] then
switch_off(pos, num)
send_cmnd(pos, num, "off")
else
switch_on(pos, num)
send_cmnd(pos, num, "on")
end
else
switch_on(pos, num)
send_cmnd(pos, num)
minetest.after(0.5, switch_off, pos, num)
end
minetest.sound_play("techage_button", {
pos = pos,
gain = 0.5,
max_hear_distance = 5,
})
end
end
end,
ta_after_formspec = function(pos, fields, playername)
lcdlib.update_entities(pos)
end,
after_dig_node = function(pos, oldnode, oldmetadata)
techage.remove_node(pos, oldnode, oldmetadata)
end,
ta3_formspec = WRENCH_MENU,
on_place = lcdlib.on_place,
on_construct = lcdlib.on_construct,
on_destruct = lcdlib.on_destruct,
on_rotate = lcdlib.on_rotate,
groups = {cracky=2, crumbly=2},
is_ground_content = false,
sounds = default.node_sound_glass_defaults(),
})
minetest.register_craft({
output = "techage:ta4_button_4x",
recipe = {
{"", "techage:ta4_button_off", "techage:ta4_button_off"},
{"", "techage:ta4_button_off", "techage:ta4_button_off"},
{"", "", ""},
},
})

View File

@ -86,8 +86,8 @@ local function on_timer(pos,elapsed)
if nvm.idx > #nvm.poll_numbers then if nvm.idx > #nvm.poll_numbers then
nvm.idx = 1 nvm.idx = 1
send_event(nvm, meta)
if nvm.stored_state ~= nvm.common_state then if nvm.stored_state ~= nvm.common_state then
send_event(nvm, meta)
local own_number = meta:get_string("own_number") local own_number = meta:get_string("own_number")
meta:set_string("infotext", S("TA4 State Collector").." "..own_number..': "'..lStates[nvm.common_state]..'"') meta:set_string("infotext", S("TA4 State Collector").." "..own_number..': "'..lStates[nvm.common_state]..'"')
nvm.stored_state = nvm.common_state nvm.stored_state = nvm.common_state

View File

@ -19,6 +19,33 @@ local NDEF = function(pos) return (minetest.registered_nodes[techage.get_node_lv
local logic = techage.logic local logic = techage.logic
local BLOCKING_TIME = 8 -- seconds local BLOCKING_TIME = 8 -- seconds
local ON_TIME = 1
local WRENCH_MENU = {
{
type = "dropdown",
choices = "1,2,4,6,8,12,16",
name = "ontime",
label = S("On Time") .. " [s]",
tooltip = S("The time between the 'on' and 'off' commands."),
default = "1",
},
{
type = "dropdown",
choices = "2,4,6,8,12,16,20",
name = "blockingtime",
label = S("Blocking Time") .. " [s]",
tooltip = S("The time after the 'off' command\nuntil the next 'on' command is accepted."),
default = "8",
},
{
type = "items",
name = "config",
label = S("Configured Items"),
tooltip = S("Items which generate an 'on' command.\nIf empty, all passed items generate an 'on' command."),
size = 4,
}
}
local function switch_on(pos) local function switch_on(pos)
local mem = techage.get_mem(pos) local mem = techage.get_mem(pos)
@ -30,8 +57,11 @@ local function switch_on(pos)
else else
logic.swap_node(pos, "techage:ta4_detector_on") logic.swap_node(pos, "techage:ta4_detector_on")
end end
logic.send_on(pos, M(pos), 1) local meta = M(pos)
mem.time = t + BLOCKING_TIME local on_time = math.max(meta:get_int("ontime"), ON_TIME)
local blocking_time = tonumber(meta:get_string("blockingtime")) or BLOCKING_TIME
logic.send_on(pos, meta, on_time)
mem.time = t + blocking_time + on_time
end end
end end
@ -48,12 +78,15 @@ end
local function formspec(meta) local function formspec(meta)
local numbers = meta:get_string("numbers") or "" local numbers = meta:get_string("numbers") or ""
return "size[7.5,3]".. return "size[7.5,3]"..
techage.wrench_image(7, -0.1) ..
"field[0.5,1;7,1;numbers;"..S("Insert destination node number(s)")..";"..numbers.."]" .. "field[0.5,1;7,1;numbers;"..S("Insert destination node number(s)")..";"..numbers.."]" ..
"button_exit[2,2;3,1;exit;"..S("Save").."]" "button_exit[2,2;3,1;exit;"..S("Save").."]"
end end
local function after_place_node(pos, placer) local function after_place_node(pos, placer)
local meta = M(pos) local meta = M(pos)
local inv = meta:get_inventory()
inv:set_size('cfg', 4)
logic.after_place_node(pos, placer, "techage:ta3_detector_off", NDEF(pos).description) logic.after_place_node(pos, placer, "techage:ta3_detector_off", NDEF(pos).description)
logic.infotext(meta, NDEF(pos).description) logic.infotext(meta, NDEF(pos).description)
meta:set_string("formspec", formspec(meta)) meta:set_string("formspec", formspec(meta))
@ -97,6 +130,7 @@ minetest.register_node("techage:ta3_detector_off", {
on_receive_fields = on_receive_fields, on_receive_fields = on_receive_fields,
techage_set_numbers = techage_set_numbers, techage_set_numbers = techage_set_numbers,
after_dig_node = after_dig_node, after_dig_node = after_dig_node,
ta3_formspec = WRENCH_MENU,
on_rotate = screwdriver.disallow, on_rotate = screwdriver.disallow,
paramtype = "light", paramtype = "light",
@ -124,6 +158,7 @@ minetest.register_node("techage:ta3_detector_on", {
on_rotate = screwdriver.disallow, on_rotate = screwdriver.disallow,
techage_set_numbers = techage_set_numbers, techage_set_numbers = techage_set_numbers,
after_dig_node = after_dig_node, after_dig_node = after_dig_node,
ta3_formspec = WRENCH_MENU,
paramtype2 = "facedir", paramtype2 = "facedir",
groups = {choppy=2, cracky=2, crumbly=2, not_in_creative_inventory=1}, groups = {choppy=2, cracky=2, crumbly=2, not_in_creative_inventory=1},
@ -148,6 +183,7 @@ minetest.register_node("techage:ta4_detector_off", {
on_receive_fields = on_receive_fields, on_receive_fields = on_receive_fields,
techage_set_numbers = techage_set_numbers, techage_set_numbers = techage_set_numbers,
after_dig_node = after_dig_node, after_dig_node = after_dig_node,
ta3_formspec = WRENCH_MENU,
on_rotate = screwdriver.disallow, on_rotate = screwdriver.disallow,
paramtype = "light", paramtype = "light",
@ -175,6 +211,7 @@ minetest.register_node("techage:ta4_detector_on", {
on_rotate = screwdriver.disallow, on_rotate = screwdriver.disallow,
techage_set_numbers = techage_set_numbers, techage_set_numbers = techage_set_numbers,
after_dig_node = after_dig_node, after_dig_node = after_dig_node,
ta3_formspec = WRENCH_MENU,
paramtype2 = "facedir", paramtype2 = "facedir",
groups = {choppy=2, cracky=2, crumbly=2, not_in_creative_inventory=1}, groups = {choppy=2, cracky=2, crumbly=2, not_in_creative_inventory=1},
@ -204,7 +241,10 @@ minetest.register_craft({
techage.register_node({"techage:ta3_detector_off", "techage:ta3_detector_on"}, { techage.register_node({"techage:ta3_detector_off", "techage:ta3_detector_on"}, {
on_push_item = function(pos, in_dir, stack) on_push_item = function(pos, in_dir, stack)
if techage.safe_push_items(pos, in_dir, stack) then if techage.safe_push_items(pos, in_dir, stack) then
local inv = minetest.get_inventory({type = "node", pos = pos})
if not inv or inv:is_empty("cfg") or inv:contains_item("cfg", ItemStack(stack:get_name())) then
switch_on(pos) switch_on(pos)
end
return true return true
end end
return false return false

View File

@ -230,7 +230,7 @@ minetest.register_node("techage:ta3_doorcontroller2", {
local meta = M(pos) local meta = M(pos)
local inv = meta:get_inventory() local inv = meta:get_inventory()
inv:set_size('main', 16) inv:set_size('main', 16)
logic.after_place_node(pos, placer, "techage:ta3_doorcontroller", S("TA3 Door Controller II")) logic.after_place_node(pos, placer, "techage:ta3_doorcontroller2", S("TA3 Door Controller II"))
logic.infotext(meta, S("TA3 Door Controller II")) logic.infotext(meta, S("TA3 Door Controller II"))
local nvm = techage.get_nvm(pos) local nvm = techage.get_nvm(pos)
meta:set_string("formspec", formspec1(nvm, meta)) meta:set_string("formspec", formspec1(nvm, meta))
@ -321,7 +321,9 @@ minetest.register_node("techage:ta3_doorcontroller2", {
return inv:is_empty("main") return inv:is_empty("main")
end, end,
after_dig_node = function(pos, oldnode, oldmetadata) after_dig_node = function(pos, oldnode, oldmetadata, digger)
local name = digger:get_player_name()
unmark_all(name)
techage.remove_node(pos, oldnode, oldmetadata) techage.remove_node(pos, oldnode, oldmetadata)
end, end,
@ -423,3 +425,5 @@ for _, name in ipairs(ProtectorDoors) do
logic.register_doorcontroller_nodes({name .. "_" .. postfix}) logic.register_doorcontroller_nodes({name .. "_" .. postfix})
end end
end end
logic.SimpleNodes = RegisteredNodes

View File

@ -67,6 +67,15 @@ function techage.logic.send_on(pos, meta, time)
return own_num == numbers return own_num == numbers
end end
function techage.logic.send_cmnd(pos, meta, cmnd, payload, time)
local own_num = meta:get_string("node_number") or ""
local numbers = meta:get_string("numbers") or ""
if time and time > 0 then
minetest.get_node_timer(pos):start(time)
end
techage.send_multi(own_num, numbers, cmnd, payload)
end
function techage.logic.send_off(pos, meta) function techage.logic.send_off(pos, meta)
local own_num = meta:get_string("node_number") or "" local own_num = meta:get_string("node_number") or ""
local numbers = meta:get_string("numbers") or "" local numbers = meta:get_string("numbers") or ""

View File

@ -0,0 +1,812 @@
--[[
TechAge
=======
Copyright (C) 2020-2021 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA4 Move Controller
]]--
-- for lazy programmers
local M = minetest.get_meta
local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local S2P = minetest.string_to_pos
local S = techage.S
-------------------------------------------------------------------------------
-- Entity / Move / Attach / Detach
-------------------------------------------------------------------------------
local MIN_SPEED = 0.4
local MAX_SPEED = 8
local function to_vector(s)
local x,y,z = unpack(string.split(s, ","))
if x and y and z then
return {
x=tonumber(x) or 0,
y=tonumber(y) or 0,
z=tonumber(z) or 0,
}
end
return {x=0, y=0, z=0}
end
-- Only the ID ist stored, not the object
local function get_object_id(object)
for id, entity in pairs(minetest.luaentities) do
if entity.object == object then
return id
end
end
end
-- determine exact position of attached entities
local function obj_pos(obj)
local _, _, pos = obj:get_attach()
pos = vector.divide(pos, 29)
return vector.add(obj:get_pos(), pos)
end
-- Check access conflicts with other mods
local function lock_player(player)
local meta = player:get_meta()
if meta:get_int("player_physics_locked") == 0 then
meta:set_int("player_physics_locked", 1)
meta:set_string("player_physics_locked_by", "ta_movecontroller")
return true
end
return false
end
local function unlock_player(player)
local meta = player:get_meta()
if meta:get_int("player_physics_locked") == 1 then
if meta:get_string("player_physics_locked_by") == "ta_movecontroller" then
meta:set_int("player_physics_locked", 0)
meta:set_string("player_physics_locked_by", "")
return true
end
end
return false
end
local function detach_player(player)
local pos = obj_pos(player)
player:set_detach()
player:set_properties({visual_size = {x=1, y=1}})
player:set_pos(pos)
-- TODO: move to save position
end
-- Attach player/mob to given parent object (block)
local function attach_single_object(parent, obj, dir)
local self = parent:get_luaentity()
local rot = obj:get_rotation()
local res = obj:get_attach()
if not res then
local offs = table.copy(dir)
dir = vector.multiply(dir, 29)
obj:set_attach(parent, "", dir, rot, true)
obj:set_properties({visual_size = {x=2.9, y=2.9}})
if obj:is_player() then
if lock_player(obj) then
table.insert(self.players, {name = obj:get_player_name(), offs = offs})
end
else
table.insert(self.entities, {objID = get_object_id(obj), offs = offs})
end
end
end
-- Attach all objects around to the parent object
-- offs is the search/attach position offset
local function attach_objects(pos, offs, parent)
local pos1 = vector.add(pos, offs)
for _, obj in pairs(minetest.get_objects_inside_radius(pos1, 0.9)) do
local dir = vector.subtract(obj:get_pos(), pos)
local entity = obj:get_luaentity()
if entity then
if entity.name == "__builtin:item" then -- dropped items
--obj:set_attach(objref, "", {x=0, y=0, z=0}, {x=0, y=0, z=0}, true) -- hier kracht es
elseif entity.name ~= "techage:move_item" then
attach_single_object(parent, obj, dir)
end
elseif obj:is_player() then
attach_single_object(parent, obj, dir)
end
end
end
-- Detach all attached objects from the parent object
local function detach_objects(pos, self)
for _, item in ipairs(self.entities or {}) do
local entity = minetest.luaentities[item.objID]
if entity then
local obj = entity.object
obj:set_detach()
obj:set_properties({visual_size = {x=1, y=1}})
local pos1 = vector.add(pos, item.offs)
obj:set_pos(pos1)
end
end
for _, item in ipairs(self.players or {}) do
local obj = minetest.get_player_by_name(item.name)
if obj then
obj:set_detach()
obj:set_properties({visual_size = {x=1, y=1}})
local pos1 = vector.add(pos, item.offs)
obj:set_pos(pos1)
unlock_player(obj)
end
end
self.entities = {}
self.players = {}
end
local function entity_to_node(pos, obj)
local self = obj:get_luaentity()
if self then
local name = self.item or "air"
local metadata = self.metadata or {}
local rot = obj:get_rotation()
detach_objects(pos, self)
obj:remove()
pos = vector.round(pos)
local dir = minetest.yaw_to_dir(rot.y or 0)
local param2 = minetest.dir_to_facedir(dir) or 0
local node = minetest.get_node(pos)
local ndef1 = minetest.registered_nodes[name]
local ndef2 = minetest.registered_nodes[node.name]
if ndef1 and ndef2 then
if ndef2.buildable_to then
local meta = M(pos)
minetest.set_node(pos, {name=name, param2=param2})
meta:from_table(metadata)
meta:set_string("ta_move_block", "")
return
end
local meta = M(pos)
if not meta:contains("ta_move_block") then
meta:set_string("ta_move_block", minetest.serialize({name=name, param2=param2}))
return
end
minetest.add_item(pos, ItemStack(name))
elseif ndef1 then
minetest.add_item(pos, ItemStack(name))
end
end
end
local function node_to_entity(pos, handover)
local meta = M(pos)
local node, metadata
if meta:contains("ta_move_block") then
node = minetest.deserialize(meta:get_string("ta_move_block"))
metadata = {}
meta:set_string("ta_move_block", "")
else
node = minetest.get_node(pos)
meta:set_string("ta_move_block", "")
metadata = meta:to_table()
minetest.remove_node(pos)
end
local dir = minetest.facedir_to_dir(node.param2)
local yaw = minetest.dir_to_yaw(dir)
local obj = minetest.add_entity(pos, "techage:move_item")
if obj then
local self = obj:get_luaentity()
obj:set_rotation({x=0, y=yaw, z=0})
obj:set_properties({wield_item=node.name})
obj:set_armor_groups({immortal=1})
self.item = node.name
self.metadata = metadata or {}
self.handover = handover
self.start_pos = table.copy(pos)
return obj
end
end
local function capture_entity(pos)
local l = minetest.get_objects_in_area(pos, pos)
for _, obj in ipairs(l) do
local self = obj:get_luaentity()
if self and self.name == "techage:move_item" then
return obj
end
end
end
-- move block direction
local function determine_dir(pos1, pos2)
local vdist = vector.subtract(pos2, pos1)
local ndist = vector.length(vdist)
return vector.divide(vdist, ndist)
end
local function move_entity(obj, pos2, dir, max_speed)
local self = obj:get_luaentity()
self.max_speed = max_speed
self.dest_pos = table.copy(pos2)
self.dir = dir
local acc = vector.multiply(dir, max_speed / 2)
obj:set_acceleration(acc)
end
-- Handover the entity to the next movecontroller
local function handover_to(pos, self)
local info = techage.get_node_info(self.handover)
if info and info.name == "techage:ta4_movecontroller" then
local mem = techage.get_mem(info.pos)
if not mem.entities_are_there then
mem.entities_are_there = true
-- copy move direction
--print("techage.get_nvm(pos).pos_2to1", techage.get_nvm(pos).pos_2to1)
techage.get_nvm(info.pos).pos_2to1 = techage.get_nvm(pos).pos_2to1
minetest.after(0.2, techage.send_single, "0", self.handover, "handover")
end
return true
end
end
minetest.register_entity("techage:move_item", {
initial_properties = {
pointable = true,
makes_footstep_sound = true,
static_save = true,
collide_with_objects = false,
physical = false,
visual = "wielditem",
wield_item = "default:dirt",
visual_size = {x=0.67, y=0.67, z=0.67},
selectionbox = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
},
get_staticdata = function(self)
return minetest.serialize({
item = self.item,
max_speed = self.max_speed,
dest_pos = self.dest_pos,
start_pos = self.start_pos,
dir = self.dir,
metadata = self.metadata,
respawn = true,
})
end,
on_activate = function(self, staticdata)
if staticdata then
local tbl = minetest.deserialize(staticdata) or {}
self.item = tbl.item or "air"
self.max_speed = tbl.max_speed or MAX_SPEED
self.dest_pos = tbl.dest_pos or self.object:get_pos()
self.start_pos = tbl.start_pos or self.object:get_pos()
self.dir = tbl.dir or {x=0, y=0, z=0}
self.metadata = tbl.metadata or {}
self.object:set_properties({wield_item = self.item})
if tbl.respawn then
entity_to_node(self.start_pos, self.object)
end
end
end,
on_step = function(self, dtime, moveresult)
if self.dest_pos then
local obj = self.object
local pos = obj:get_pos()
local dist = vector.distance(pos, self.dest_pos)
local speed = vector.length(obj:get_velocity())
-- Landing
if dist < 0.05 then
obj:move_to(self.dest_pos, true)
obj:set_acceleration({x=0, y=0, z=0})
obj:set_velocity({x=0, y=0, z=0})
self.dest_pos = nil
if not self.handover or not handover_to(pos, self) then
minetest.after(0.5, entity_to_node, pos, obj)
end
self.ttl = 2
return
end
-- Braking or limit max speed
if speed > (dist * 2) or speed > self.max_speed then
local speed = math.min(speed, math.max(dist * 2, MIN_SPEED))
local vel = vector.multiply(self.dir,speed)
obj:set_velocity(vel)
obj:set_acceleration({x=0, y=0, z=0})
end
elseif self.ttl then
self.ttl = self.ttl - dtime
if self.ttl < 0 then
local obj = self.object
local pos = obj:get_pos()
entity_to_node(pos, obj)
end
end
end,
})
-------------------------------------------------------------------------------
-- Marker / Record
-------------------------------------------------------------------------------
local MarkedNodes = {} -- t[player] = {{entity, pos},...}
local CurrentPos -- to mark punched entities
local SimpleNodes = techage.logic.SimpleNodes
local function is_valid_dest(pos)
local node = minetest.get_node(pos)
local ndef = minetest.registered_nodes[node.name]
if ndef and ndef.buildable_to then
return true
end
if not M(pos):contains("ta_move_block") then
return true
end
return false
end
local function is_simple_node(pos)
-- special handling
local name = minetest.get_node(pos).name
if SimpleNodes[name] ~= nil then
return SimpleNodes[name]
end
local ndef = minetest.registered_nodes[name]
if not ndef or name == "air" or name == "ignore" then return false end
-- don't remove nodes with some intelligence or undiggable nodes
if ndef.drop == "" then return false end
if ndef.diggable == false then return false end
if ndef.after_dig_node then return false end
return true
end
local function table_add(tbl, offs)
if not tbl or not offs then return end
local tbl2 = {}
for _, v in ipairs(tbl) do
tbl2[#tbl2 + 1] = vector.add(v, offs)
end
return tbl2
end
local function unmark_position(name, pos)
pos = vector.round(pos)
for idx,item in ipairs(MarkedNodes[name] or {}) do
if vector.equals(pos, item.pos) then
item.entity:remove()
table.remove(MarkedNodes[name], idx)
CurrentPos = pos
return
end
end
end
local function unmark_all(name)
for _,item in ipairs(MarkedNodes[name] or {}) do
item.entity:remove()
end
MarkedNodes[name] = nil
end
local function mark_position(name, pos)
MarkedNodes[name] = MarkedNodes[name] or {}
pos = vector.round(pos)
if not CurrentPos or not vector.equals(pos, CurrentPos) then -- entity not punched?
local entity = minetest.add_entity(pos, "techage:moveblock_marker")
if entity ~= nil then
entity:get_luaentity().player_name = name
table.insert(MarkedNodes[name], {pos = pos, entity = entity})
end
CurrentPos = nil
return true
end
CurrentPos = nil
end
local function get_poslist(name)
local idx = 0
local lst = {}
for _,item in ipairs(MarkedNodes[name] or {}) do
table.insert(lst, item.pos)
idx = idx + 1
if idx >= 16 then break end
end
return lst
end
minetest.register_on_punchnode(function(pos, node, puncher, pointed_thing)
if puncher and puncher:is_player() then
local name = puncher:get_player_name()
if not MarkedNodes[name] then
return
end
mark_position(name, pointed_thing.under)
end
end)
minetest.register_entity(":techage:moveblock_marker", {
initial_properties = {
visual = "cube",
textures = {
"techage_cube_mark.png",
"techage_cube_mark.png",
"techage_cube_mark.png",
"techage_cube_mark.png",
"techage_cube_mark.png",
"techage_cube_mark.png",
},
--use_texture_alpha = true,
physical = false,
visual_size = {x=1.1, y=1.1},
collisionbox = {-0.55,-0.55,-0.55, 0.55,0.55,0.55},
glow = 8,
},
on_step = function(self, dtime)
self.ttl = (self.ttl or 2400) - 1
if self.ttl <= 0 then
local pos = self.object:get_pos()
unmark_position(self.player_name, pos)
end
end,
on_punch = function(self, hitter)
local pos = self.object:get_pos()
local name = hitter:get_player_name()
if name == self.player_name then
unmark_position(name, pos)
end
end,
})
-------------------------------------------------------------------------------
-- TA4 Move Controller
-------------------------------------------------------------------------------
local WRENCH_MENU = {
{
type = "dropdown",
choices = "0.5,1,2,4,6,8",
name = "max_speed",
label = S("Maximum Speed"),
tooltip = S("Maximum speed for the moving block."),
default = "8",
},
{
type = "number",
name = "handoverB",
label = S("Handover to B"),
tooltip = S("Number of the next movecontroller."),
default = "",
},
{
type = "number",
name = "handoverA",
label = S("Handover to A"),
tooltip = S("Number of the previous movecontroller."),
default = "",
},
{
type = "float",
name = "height",
label = S("Move block height"),
tooltip = S("Value in the range of 0.0 to 1.0"),
default = "1.0",
},
}
local function formspec(nvm, meta)
local status = meta:get_string("status")
local distance = meta:contains("distance") and meta:get_string("distance") or "0,3,0"
return "size[8,5]" ..
default.gui_bg ..
default.gui_bg_img ..
default.gui_slots ..
"box[0,-0.1;7.2,0.5;#c6e8ff]" ..
"label[0.2,-0.1;" .. minetest.colorize( "#000000", S("TA4 Move Controller")) .. "]" ..
techage.wrench_image(7.4, -0.05) ..
"button[0.1,0.8;3.8,1;record;" .. S("Record") .. "]" ..
"button[4.1,0.8;3.8,1;ready;" .. S("Done") .. "]" ..
"field[0.4,2.5;3.8,1;distance;" .. S("Move distance (A to B)") .. ";" .. distance .. "]" ..
"button[4.1,2.2;3.8,1;store;" .. S("Store") .. "]" ..
"button[0.1,3.3;3.8,1;moveAB;" .. S("Move A-B") .. "]" ..
"button[4.1,3.3;3.8,1;moveBA;" .. S("Move B-A") .. "]" ..
"label[0.3,4.3;" .. status .. "]"
end
local function move_node(pos, pos1, pos2, max_speed, handover, height)
local meta = M(pos)
local dir = determine_dir(pos1, pos2)
local obj = node_to_entity(pos1, handover)
local self = obj:get_luaentity()
self.players = {}
self.entities = {}
if obj then
local offs = {x=0, y=height or 1, z=0}
attach_objects(pos1, offs, obj)
if dir.y == 0 then
if (dir.x ~= 0 and dir.z == 0) or (dir.x == 0 and dir.z ~= 0) then
attach_objects(pos1, dir, obj)
end
end
move_entity(obj, pos2, dir, max_speed)
end
end
local function move_nodes(pos, lpos1, lpos2, handover)
local meta = M(pos)
local owner = meta:get_string("owner")
local max_speed = meta:contains("max_speed") and meta:get_int("max_speed") or MAX_SPEED
local height = meta:contains("height") and meta:get_float("height") or 1
height = techage.in_range(height, 0, 1)
if #lpos1 == #lpos2 then
for idx = 1, #lpos1 do
local pos1 = lpos1[idx]
local pos2 = lpos2[idx]
if not minetest.is_protected(pos1, owner) and not minetest.is_protected(pos2, owner) then
if is_simple_node(pos1) and is_valid_dest(pos2) then
move_node(pos, pos1, pos2, max_speed, handover, height)
else
if not is_simple_node(pos1) then
meta:set_string("status", S("No valid node at the start position"))
else
meta:set_string("status", S("No valid destination position"))
end
end
else
if minetest.is_protected(pos1, owner) then
meta:set_string("status", S("Start position is protected"))
else
meta:set_string("status", S("Destination position is protected"))
end
return false
end
end
else
meta:set_string("status", S("Position list error"))
return false
end
local info = techage.get_node_info(handover)
if info and info.name == "techage:ta4_movecontroller" then
local mem = techage.get_mem(info.pos)
mem.num_entities = #lpos1
end
return true
end
local function moveon_nodes(pos, lpos1, lpos2, handover)
local meta = M(pos)
local owner = meta:get_string("owner")
local max_speed = meta:contains("max_speed") and meta:get_int("max_speed") or MAX_SPEED
if #lpos1 == #lpos2 then
for idx = 1, #lpos1 do
local pos1 = lpos1[idx]
local pos2 = lpos2[idx]
if not minetest.is_protected(pos1, owner) and not minetest.is_protected(pos2, owner) then
if is_valid_dest(pos2) then
local dir = determine_dir(pos1, pos2)
local obj = capture_entity(pos1)
if obj then
obj:get_luaentity().handover = handover
move_entity(obj, pos2, dir, max_speed)
end
else
if not is_simple_node(pos1) then
meta:set_string("status", S("No valid node at the start position"))
else
meta:set_string("status", S("No valid destination position"))
end
end
else
if minetest.is_protected(pos1, owner) then
meta:set_string("status", S("Start position is protected"))
else
meta:set_string("status", S("Destination position is protected"))
end
return false
end
end
else
meta:set_string("status", S("Position list error"))
return false
end
local info = techage.get_node_info(handover)
if info and info.name == "techage:ta4_movecontroller" then
local mem = techage.get_mem(info.pos)
mem.num_entities = #lpos1
end
return true
end
local function move_to_other_pos(pos)
local meta = M(pos)
local nvm = techage.get_nvm(pos)
if nvm.pos_2to1 then
local lpos1 = nvm.lpos1 or {}
local lpos2 = nvm.lpos2 or {}
nvm.pos_2to1 = false
local handover = meta:contains("handoverA") and meta:get_string("handoverA")
return move_nodes(pos, lpos2, lpos1, handover)
else
local lpos1 = nvm.lpos1 or {}
local lpos2 = nvm.lpos2 or {}
nvm.pos_2to1 = true
local handover = meta:contains("handoverB") and meta:get_string("handoverB")
return move_nodes(pos, lpos1, lpos2, handover)
end
end
local function takeover(pos)
local meta = M(pos)
local nvm = techage.get_nvm(pos)
local mem = techage.get_mem(pos)
mem.entities_are_there = nil
if nvm.pos_2to1 then
local lpos1 = nvm.lpos1 or {}
local lpos2 = nvm.lpos2 or {}
nvm.pos_2to1 = false
local handover = meta:contains("handoverA") and meta:get_string("handoverA")
return moveon_nodes(pos, lpos2, lpos1, handover)
else
local lpos1 = nvm.lpos1 or {}
local lpos2 = nvm.lpos2 or {}
nvm.pos_2to1 = true
local handover = meta:contains("handoverB") and meta:get_string("handoverB")
return moveon_nodes(pos, lpos1, lpos2, handover)
end
end
minetest.register_node("techage:ta4_movecontroller", {
description = S("TA4 Move Controller"),
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta4.png^techage_frame_ta4_top.png",
"techage_filling_ta4.png^techage_frame_ta4_top.png",
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_movecontroller.png",
},
after_place_node = function(pos, placer, itemstack)
local meta = M(pos)
techage.logic.after_place_node(pos, placer, "techage:ta4_movecontroller", S("TA4 Move Controller"))
techage.logic.infotext(meta, S("TA4 Move Controller"))
local nvm = techage.get_nvm(pos)
meta:set_string("formspec", formspec(nvm, meta))
end,
on_receive_fields = function(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
local meta = M(pos)
local nvm = techage.get_nvm(pos)
if fields.record then
nvm.lpos1 = nil
nvm.lpos2 = nil
nvm.pos_2to1 = false
meta:set_string("status", S("Recording..."))
local name = player:get_player_name()
minetest.chat_send_player(name, S("Click on all blocks that shall be moved"))
MarkedNodes[name] = {}
meta:set_string("formspec", formspec(nvm, meta))
elseif fields.ready then
local name = player:get_player_name()
local pos_list = get_poslist(name)
local text = #pos_list.." "..S("block positions are stored.")
meta:set_string("status", text)
meta:set_string("distance", fields.distance)
nvm.lpos1 = pos_list
nvm.lpos2 = table_add(pos_list, to_vector(fields.distance))
nvm.pos_2to1 = false
unmark_all(name)
meta:set_string("formspec", formspec(nvm, meta))
elseif fields.store then
local dist = to_vector(fields.distance)
local l = math.hypot(dist.x, math.hypot(dist.y, dist.z))
if l <= 100 then
meta:set_string("distance", fields.distance)
nvm.lpos2 = table_add(nvm.lpos1, to_vector(fields.distance))
nvm.pos_2to1 = false
else
meta:set_string("status", S("Error: Distance > 100 m !!"))
end
meta:set_string("formspec", formspec(nvm, meta))
elseif fields.moveAB then
meta:set_string("status", "")
nvm.pos_2to1 = false
if move_to_other_pos(pos) then
meta:set_string("formspec", formspec(nvm, meta))
local name = player:get_player_name()
MarkedNodes[name] = nil
end
elseif fields.moveBA then
meta:set_string("status", "")
nvm.pos_2to1 = true
if move_to_other_pos(pos) then
meta:set_string("formspec", formspec(nvm, meta))
local name = player:get_player_name()
MarkedNodes[name] = nil
end
end
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
local name = digger:get_player_name()
unmark_all(name)
techage.remove_node(pos, oldnode, oldmetadata)
end,
ta4_formspec = WRENCH_MENU,
paramtype2 = "facedir",
groups = {choppy=2, cracky=2, crumbly=2},
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})
local INFO = [[Commands: 'a2b', 'b2a', 'move']]
techage.register_node({"techage:ta4_movecontroller"}, {
on_recv_message = function(pos, src, topic, payload)
if topic == "info" then
return INFO
elseif topic == "a2b" then
local nvm = techage.get_nvm(pos)
nvm.pos_2to1 = false
return move_to_other_pos(pos)
elseif topic == "b2a" then
local nvm = techage.get_nvm(pos)
nvm.pos_2to1 = true
return move_to_other_pos(pos)
elseif topic == "move" then
return move_to_other_pos(pos)
elseif topic == "handover" then
return takeover(pos)
end
return false
end,
})
minetest.register_craft({
output = "techage:ta4_movecontroller",
recipe = {
{"default:steel_ingot", "dye:blue", "default:steel_ingot"},
{"default:mese_crystal_fragment", "techage:ta4_wlanchip", "default:mese_crystal_fragment"},
{"group:wood", "basic_materials:gear_steel", "group:wood"},
},
})
minetest.register_on_joinplayer(function(player)
unlock_player(player)
end)
minetest.register_on_leaveplayer(function(player)
if unlock_player(player) then
detach_player(player)
end
end)
minetest.register_on_dieplayer(function(player)
if unlock_player(player) then
detach_player(player)
end
end)

View File

@ -103,7 +103,9 @@ techage.register_node({"techage:ta3_repeater"}, {
return false return false
else else
local numbers = M(pos):get_string("numbers") or "" local numbers = M(pos):get_string("numbers") or ""
techage.counting_start(M(pos):get_string("owner"))
techage.send_multi(src, numbers, topic, payload) techage.send_multi(src, numbers, topic, payload)
techage.counting_stop()
end end
end, end,
on_node_load = function(pos) on_node_load = function(pos)

View File

@ -60,7 +60,7 @@ local function formspec_help()
"label[0,1;Define a sequence of commands\nto control other machines.]".. "label[0,1;Define a sequence of commands\nto control other machines.]"..
"label[0,2.2;Numbers(s) are the node numbers,\nthe command shall sent to.]".. "label[0,2.2;Numbers(s) are the node numbers,\nthe command shall sent to.]"..
"label[0,3.4;The commands 'on'/'off' are used\n for machines and other nodes.]".. "label[0,3.4;The commands 'on'/'off' are used\n for machines and other nodes.]"..
"label[0,4.6;Offset is the time to the\nnext line in seconds (1..999).]".. "label[0,4.6;Offset is the time to the\nnext line in seconds (0.2 to 999).]"..
"label[0,5.8;If endless is set, the Sequencer\nrestarts again and again.]".. "label[0,5.8;If endless is set, the Sequencer\nrestarts again and again.]"..
"label[0,7;The command ' ' does nothing,\nonly consuming the offset time.]".. "label[0,7;The command ' ' does nothing,\nonly consuming the offset time.]"..
"button[3,8;2,1;exit;close]" "button[3,8;2,1;exit;close]"
@ -106,6 +106,7 @@ local function check_rules(pos, elapsed)
nvm.running = nvm.running or false nvm.running = nvm.running or false
nvm.index = nvm.index or 1 nvm.index = nvm.index or 1
nvm.endless = nvm.endless or false nvm.endless = nvm.endless or false
techage.counting_start(M(pos):get_string("owner"))
while true do -- process all rules as long as offs == 0 while true do -- process all rules as long as offs == 0
local rule = nvm.rules[nvm.index] local rule = nvm.rules[nvm.index]
local offs = tonumber(nvm.rules[nvm.index].offs or 1) local offs = tonumber(nvm.rules[nvm.index].offs or 1)
@ -119,12 +120,15 @@ local function check_rules(pos, elapsed)
if offs > 0 then if offs > 0 then
-- we can't restart the timer within the function om_timer -- we can't restart the timer within the function om_timer
minetest.after(0, restart_timer, pos, offs) minetest.after(0, restart_timer, pos, offs)
techage.counting_stop()
return false return false
end end
else else
techage.counting_stop()
return stop_the_sequencer(pos) return stop_the_sequencer(pos)
end end
end end
techage.counting_stop()
return false return false
end end

View File

@ -0,0 +1,318 @@
--[[
TechAge
=======
Copyright (C) 2017-2021 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA4 Sequencer
]]--
-- for lazy programmers
local M = minetest.get_meta
local S = techage.S
local logic = techage.logic
local HELP = S("Syntax:\n") ..
S("'[<num>] <command>'\n") ..
S("\n") ..
S("<num> is a number from 1 to 50000 and is\n") ..
S("the timeslot when the command is executed.\n") ..
S(" - 1 corresponds to 100 ms\n") ..
S(" - 50000 corresponds to 4 game days\n") ..
S("\n") ..
S("<command> is one of the following:\n") ..
S(" - 'send <node num> <cmnd>' (techage command)\n") ..
S(" - 'goto <num>' (jump to another line)\n") ..
S(" - 'stop' (stop the execution)\n") ..
S("\n") ..
S("Example:\n") ..
" -- move controller commands\n" ..
" [1] send 1234 a2b\n" ..
" [30] send 1234 b2a\n" ..
" [60] goto 1 -- keep going"
local function strsplit(text)
text = text:gsub("\r\n", "\n")
text = text:gsub("\r", "\n")
return string.split(text, "\n", true)
end
local function trim(s)
return (s:gsub("^%s*(.-)%s*$", "%1"))
end
local function command(s)
local num, cmd, pld = unpack(string.split(s, " ", false, 2))
if not num or not cmd then
return S("Invalid command!")
end
return {number = num, cmnd = cmd, payload = pld}
end
local function add_error(text, line_num)
local tbl = {}
for idx, line in ipairs(strsplit(text)) do
if idx == line_num and not string.find(line, '--<<== error') then
tbl[#tbl+1] = line.." --<<== error"
else
tbl[#tbl+1] = line
end
end
return table.concat(tbl, "\n")
end
local function exception(tRes, line, s)
if tRes then
tRes.line = line
tRes.error = s
end
end
local function compile(s, tRes)
local tCode = {}
local old_idx = 0
local start_idx
for i, line in ipairs(strsplit(s)) do
line = trim(line)
line = string.split(line, "--", true, 1)[1] or ""
if line ~= "" then
local idx, cmnd1, cmnd2 = unpack(string.split(line, " ", false, 2))
idx = tonumber(string.match(idx, "^%[(%d+)%]$"))
if not idx then
return exception(tRes, i, "Syntax error!")
end
if idx > 50000 then
return exception(tRes, i, "Order error!")
end
if idx <= old_idx then
return exception(tRes, i, "Order error!")
end
start_idx = start_idx or idx
if old_idx ~= 0 and not tCode[old_idx].next_idx then
tCode[old_idx].next_idx = idx
end
if cmnd1 == "send" then
local res = command(cmnd2)
if type(res) == "string" then
return exception(tRes, i, res)
end
tCode[idx] = res
elseif cmnd1 == "goto" then
tCode[idx] = {next_idx = tonumber(cmnd2) or 1}
elseif cmnd1 == "stop" then
tCode[idx] = false
elseif cmnd1 == nil then
tCode[idx] = {}
end
old_idx = idx
end
end
-- Returns:
-- {
-- start_idx = 1,
-- tCode = {
-- <idx> = {number = <number>, cmnd = <string>, payload = <data>, next_idx = <idx>},
-- ...
-- },
-- }
return {start_idx=start_idx, tCode=tCode}
end
local function check_syntax(meta)
local tRes = {}
local res = compile(meta:get_string("text"), tRes)
if not res then
meta:set_string("err_msg", tRes.error)
meta:set_string("text", add_error(meta:get_string("text"), tRes.line))
return false
else
meta:set_string("err_msg", "")
return true
end
end
local function formspec(nvm, meta)
local text = meta:get_string("text")
text = minetest.formspec_escape(text)
local bttn = nvm.running and ("stop;" .. S("Stop")) or ("start;" .. S("Start"))
local style = nvm.running and "style_type[textarea;font=mono;textcolor=#888888;border=false]" or
"style_type[textarea;font=mono;textcolor=#FFFFFF;border=false]"
local textarea = nvm.running and "textarea[0.3,0.2;10,8.3;;;"..text.."]" or
"textarea[0.3,0.2;10,8.3;text;;"..text.."]"
return "size[10,8]" ..
style ..
"tabheader[0,0;tab;edit,help;1;;true]" ..
"label[0.1,-0.2;" .. S("Commands") .. ":]" ..
textarea ..
"background[0.1,0.3;9.8,7.0;techage_form_mask.png]" ..
"label[0.1,7.5;" .. meta:get_string("err_msg") .. "]" ..
"button_exit[3.4,7.5;2.2,1;cancel;" .. S("Cancel") .. "]" ..
"button[5.6,7.5;2.2,1;save;" .. S("Save") .. "]" ..
"button[7.8,7.5;2.2,1;" .. bttn .. "]"
end
local function formspec_help(meta)
local text = "" --minetest.formspec_escape("hepl")
return "size[10,8]"..
"style_type[textarea;font=mono;textcolor=#FFFFFF;border=false]"..
"tabheader[0,0;tab;edit,help;2;;true]"..
"textarea[0.3,0.3;10,9;;" .. S("Help") .. ":;"..minetest.formspec_escape(HELP).."]" ..
"background[0.1,0.3;9.8,8.0;techage_form_mask.png]"
end
local function restart_timer(pos, time)
local timer = minetest.get_node_timer(pos)
if timer:is_started() then
timer:stop()
end
timer:start(time / 10)
end
local function node_timer(pos, elapsed)
local nvm = techage.get_nvm(pos)
if nvm.running then
local mem = techage.get_mem(pos)
mem.code = mem.code or compile(M(pos):get_string("text"))
if mem.code then
mem.idx = mem.idx or mem.code.start_idx
local code = mem.code.tCode[mem.idx]
if code and code.cmnd then
local src = M(pos):get_string("node_number")
techage.counting_start(M(pos):get_string("owner"))
techage.send_single(src, code.number, code.cmnd, code.payload)
techage.counting_stop()
end
if code and code.next_idx then
local offs = code.next_idx - mem.idx
minetest.after(0, restart_timer, pos, math.max(offs, 1))
mem.idx = code.next_idx
else
nvm.running = false
local meta = M(pos)
meta:set_string("formspec", formspec(nvm, meta))
logic.infotext(meta, S("TA4 Sequencer"), S("stopped"))
end
end
end
return false
end
local function on_receive_fields(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
local meta = M(pos)
local nvm = techage.get_nvm(pos)
local mem = techage.get_mem(pos)
nvm.running = nvm.running or false
print(1, dump(fields))
if fields.stop then
nvm.running = false
minetest.get_node_timer(pos):stop()
logic.infotext(meta, S("TA4 Sequencer"), S("stopped"))
elseif not nvm.running then
print(2)
if fields.tab == "2" then
print(3)
meta:set_string("formspec", formspec_help(meta))
return
elseif fields.tab == "1" then
meta:set_string("formspec", formspec(nvm, meta))
return
end
if fields.save then
nvm.running = false
meta:set_string("text", fields.text or "")
mem.code = nil
mem.idx = nil
elseif fields.start then
if check_syntax(meta) then
nvm.running = true
meta:set_string("text", fields.text or "")
mem.code = nil
mem.idx = nil
minetest.get_node_timer(pos):start(0.5)
logic.infotext(meta, S("TA4 Sequencer"), S("running"))
end
end
end
meta:set_string("formspec", formspec(nvm, meta))
end
minetest.register_node("techage:ta4_sequencer", {
description = S("TA4 Sequencer"),
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta4.png^techage_frame_ta4_top.png",
"techage_filling_ta4.png^techage_frame_ta4_top.png",
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_sequencer.png",
},
after_place_node = function(pos, placer)
local meta = M(pos)
local nvm = techage.get_nvm(pos)
logic.after_place_node(pos, placer, "techage:ta4_sequencer", S("TA4 Sequencer"))
logic.infotext(meta, S("TA4 Sequencer"), S("stopped"))
nvm.running = false
meta:set_string("formspec", formspec(nvm, meta))
end,
on_receive_fields = on_receive_fields,
after_dig_node = function(pos, oldnode, oldmetadata)
techage.remove_node(pos, oldnode, oldmetadata)
techage.del_mem(pos)
end,
on_timer = node_timer,
paramtype2 = "facedir",
groups = {choppy=2, cracky=2, crumbly=2},
is_ground_content = false,
sounds = default.node_sound_stone_defaults(),
})
minetest.register_craft({
output = "techage:ta4_sequencer",
recipe = {
{"default:steel_ingot", "dye:blue", "default:steel_ingot"},
{"techage:ta4_ramchip", "default:mese_crystal", "techage:ta4_wlanchip"},
{"techage:aluminum", "group:wood", "techage:aluminum"},
},
})
local INFO = [[Commands: 'goto <num>', 'stop']]
techage.register_node({"techage:ta4_sequencer"}, {
on_recv_message = function(pos, src, topic, payload)
local nvm = techage.get_nvm(pos)
if topic == "goto" and not nvm.running then
local mem = techage.get_mem(pos)
nvm.running = true
mem.idx = tonumber(payload or 1) or 1
restart_timer(pos, 0.1)
logic.infotext(M(pos), S("TA4 Sequencer"), S("running"))
elseif topic == "stop" then
nvm.running = false
minetest.get_node_timer(pos):stop()
logic.infotext(M(pos), S("TA4 Sequencer"), S("stopped"))
elseif topic == "info" then
return INFO
else
return "unsupported"
end
end,
})

View File

@ -201,6 +201,7 @@ local function register_terminal(num, tiles, node_box, selection_box)
meta:set_string("command", S("commands like: help")) meta:set_string("command", S("commands like: help"))
meta:set_string("formspec", formspec2(meta)) meta:set_string("formspec", formspec2(meta))
meta:set_string("owner", placer:get_player_name()) meta:set_string("owner", placer:get_player_name())
meta:set_string("infotext", S("TA3 Terminal") .. " " .. number)
end, end,
on_receive_fields = function(pos, formname, fields, player) on_receive_fields = function(pos, formname, fields, player)

View File

@ -403,7 +403,8 @@ local function call_loop(pos, meta, elapsed)
local code = Cache[number].code local code = Cache[number].code
local res = safer_lua.run_loop(pos, elapsed, code, error) local res = safer_lua.run_loop(pos, elapsed, code, error)
if res then if res then
t = minetest.get_us_time() - t -- Don't count thread changes
t = math.min(minetest.get_us_time() - t, 1000)
cpu = math.floor(((cpu * 20) + t) / 21) cpu = math.floor(((cpu * 20) + t) / 21)
meta:set_int("cpu", cpu) meta:set_int("cpu", cpu)
meta:set_string("infotext", "Controller "..number..": running ("..cpu.."us)") meta:set_string("infotext", "Controller "..number..": running ("..cpu.."us)")

View File

@ -695,6 +695,7 @@ Detektoren scannen ihre Umgebung ab und senden ein `on`-Kommando, wenn das Gesuc
Der Detektor ist eine spezieller Röhrenblock, der erkennt, wenn Items über die Röhre weitergegeben werden. Es muss dazu auf beiden Seiten mit der Röhre verbunden sein. Werden Items mit einem Schieber in den Detektor geschoben, gibt er diese automatisch weiter. Der Detektor ist eine spezieller Röhrenblock, der erkennt, wenn Items über die Röhre weitergegeben werden. Es muss dazu auf beiden Seiten mit der Röhre verbunden sein. Werden Items mit einem Schieber in den Detektor geschoben, gibt er diese automatisch weiter.
Er sendet ein `on`, wenn ein Item erkannt wird, gefolgt von einem `off` eine Sekunde später. Er sendet ein `on`, wenn ein Item erkannt wird, gefolgt von einem `off` eine Sekunde später.
Danach werden weitere Kommando für 8 Sekunden blockiert. Danach werden weitere Kommando für 8 Sekunden blockiert.
Die Wartezeit, sowie die Items, die ein Kommando auslösen sollen, können über das Gabelschlüssel-Menü konfiguriert werden.
[ta3_detector|image] [ta3_detector|image]

View File

@ -690,6 +690,7 @@ Detectors scan their surroundings and send an `on` command when the search is re
The detector is a special tube block that detects when items are passed on through the tube. To do this, it must be connected to tubes on both sides. If items are pushed into the detector with a pusher, they are automatically passed on. The detector is a special tube block that detects when items are passed on through the tube. To do this, it must be connected to tubes on both sides. If items are pushed into the detector with a pusher, they are automatically passed on.
It sends an `on` when an item is recognized, followed by an `off` a second later. It sends an `on` when an item is recognized, followed by an `off` a second later.
Then further commands are blocked for 8 seconds. Then further commands are blocked for 8 seconds.
The waiting time and the items that should trigger a command can be configured using the open-ended wrench menu.
[ta3_detector|image] [ta3_detector|image]
@ -810,7 +811,7 @@ The processing power is up to 8 times one item every 4 seconds.
### Techage Info Tool ### Techage Info Tool
The Techage Info Tool (wrench) has several functions. It shows the time, position, temperature and biome when an unknown block is clicked on. The Techage Info Tool (open-ended wrench) has several functions. It shows the time, position, temperature and biome when an unknown block is clicked on.
If you click on a TechAge block with command interface, all available data will be shown (see also "Logic / switching blocks"). If you click on a TechAge block with command interface, all available data will be shown (see also "Logic / switching blocks").
With Shift + right click an extended menu can be opened for some blocks. Depending on the block, further data can be called up or special settings can be made here. In the case of a generator, for example, the charging curve/switch-off can be programmed. With Shift + right click an extended menu can be opened for some blocks. Depending on the block, further data can be called up or special settings can be made here. In the case of a generator, for example, the charging curve/switch-off can be programmed.

View File

@ -470,6 +470,12 @@ Beim TA4 Taster/Schalter hat sich nur das Aussehen geändert. Die Funktionalitä
[ta4_button|image] [ta4_button|image]
### TA4 4x Taster / 4x Button
Dieser Block hat vier Taster, die über das Schraubenschlüssel-Menü individuell konfiguriert werden können. Für jeden Taster kann die Beschriftung und die Zielblockadresse konfiguriert werden. Zusätzlich kann für jeden Taster das Kommando konfiguriert werden, welches gesendet werden soll.
[ta4_button_4x|image]
### TA4 Spieler Detektor / Player Detector ### TA4 Spieler Detektor / Player Detector
Beim TA4 Spieler Detektor hat sich nur das Aussehen geändert. Die Funktionalität ist gleich wie beim TA3 Spieler Detektor. Beim TA4 Spieler Detektor hat sich nur das Aussehen geändert. Die Funktionalität ist gleich wie beim TA3 Spieler Detektor.
@ -489,6 +495,60 @@ Diesen Zähler kann man über das Kommando 'count' abfragen und über 'reset' zu
[ta4_detector|image] [ta4_detector|image]
### TA4 Move Controller
Der TA4 Move Controller ist ähnlich zum "Door Controller 2", aber die ausgewählten Blöcke werden nicht entfernt, sondern können bewegt werden.
Da die bewegten Blöcke Spieler und Mobs mitnehmen können, die auf dem Block stehen, können damit Fahrstühle und ähnliche Transportsysteme gebaut werden.
Anleitung:
- Controller setzen und die Blöcke, die bewegt werden sollen, über das Menü an-trainieren (Es können bis zu 16 Blöcke an-trainiert werden)
- die "Flugstrecke" muss über eine x,y,z Angabe (relativ) eingegeben werden (die maximale Distanz beträgt 100 m)
- mit den Menü-Tasten "Bewege A-B" sowie "Bewege B-A" kann die Bewegung getestet werden
- man kann auch durch Wände oder andere Blöcke fliegen
- auch die Zielposition für die Blöcke kann belegt sein. Die Blöcke werden in diesem Falle "unsichtbar" gespeichert. Dies ist für Schiebetüren und ähnliches gedacht
- Über das Gabelschlüssel-Menü kann im Controller auch ein "handover" programmiert werden. Durch Eingabe einer Blocknummer werden die Blöcke dann an den nächsten Move Controller übergeben. So lassen sich auch zusammenhängende Bewegungen über mehrere Move Controller realisieren.
Der Move Controller unterstützt folgende techage Kommandos:
- `a2b` Bewege Block von A nach B
- `b2a` Bewege Block von B nach A
- `move` Bewege Block auf die andere Seite
[ta4_movecontroller|image]
### TA4 Sequenzer
über den TA4 Sequenzer können ganze Abläufe programmiert werden. Hier ein Beispiel:
```
-- this is a comment
[1] send 1234 a2b
[30] send 1234 b2a
[60] goto 1
```
- Jede Zeile beginnt mit einem Nummer, welche einem Zeitpunkt entspricht `[<num>]`
- Für Zeitpunkte sind Werte von 1 bis 50000 zulässig
- 1 entspricht 100 ms, 50000 entspricht in etwa 4 Spieltagen
- Leerzeilen oder Kommentare sind erlaubt (`-- comment`)
- Mit `send <num> <command> <data>` kann man ein Kommando an einen Block senden
- Mit `goto <num>` kann man an eine andere Zeile/Zeitpunkt springen
- Mit `stop` kann man den Sequenzer verzögert stoppen, so dass er kein neues Kommando
von einem Taster oder anderem Block annimmt (um eine Bewegung abzuschließen)
Ohne `stop` geht der Sequenzer sofort nach dem letzten Kommando in den stopped Modus.
Der TA4 Sequenzer unterstützt folgende techage Kommandos:
- `goto <num>` Zu einer Kommandozeile springen und damit den Sequenzer starten
- `stop` Den Sequenzer anhalten
Das `goto` Kommando wird nur angenommen, wenn der Sequenzer gestoppt ist.
[ta4_sequencer|image]
## TA4 Lampen ## TA4 Lampen

View File

@ -463,6 +463,12 @@ Only the appearance of the TA4 button/switch has changed. The functionality is t
[ta4_button|image] [ta4_button|image]
### TA4 4x Button
This block has four buttons that can be individually configured using the wrench menu. The labeling and the target block address can be configured for each button. In addition, the command that is to be sent can be configured for each button.
[ta4_button_4x|image]
### TA4 Player Detector ### TA4 Player Detector
Only the appearance of the TA4 player detector has changed. The functionality is the same as with the TA3 player detector. Only the appearance of the TA4 player detector has changed. The functionality is the same as with the TA3 player detector.
@ -482,6 +488,60 @@ This counter can be queried with the 'count' command and reset with 'reset'.
[ta4_detector|image] [ta4_detector|image]
### TA4 Move Controller
The TA4 Move Controller is similar to "Door Controller 2", but the selected blocks are not removed, but can be moved.
Since the moving blocks can take players and mobs standing on the block with them, elevators and similar transport systems can be built with them.
Instructions:
- Set the controller and train the blocks to be moved via the menu (up to 16 blocks can be trained)
- the "flight route" must be entered via an x, y, z specification (relative) (the maximum distance is 100 m)
- The movement can be tested with the menu buttons "Move A-B" and "Move B-A"
- you can also fly through walls or other blocks
- The target position for the blocks can also be occupied. In this case, the blocks are saved "invisibly". This is intended for sliding doors and the like
- A "handover" can also be programmed in the controller via the open-ended wrench menu. By entering a block number, the blocks are then transferred to the next move controller. In this way, connected movements can also be implemented using several Move Controllers.
The Move Controller supports the following techage commands:
- `a2b` Move block from A to B.
- `b2a` Move block from B to A.
- `move` Move block to the other side
[ta4_movecontroller|image]
### TA4 Sequencer
Entire processes can be programmed using the TA4 sequencer. Here's an example:
```
-- this is a comment
[1] send 1234 a2b
[30] send 1234 b2a
[60] goto 1
```
- Each line begins with a number which corresponds to a point in time `[<num>]`
- Values from 1 to 50000 are permitted for times
- 1 corresponds to 100 ms, 50000 corresponds to about 4 game days
- Empty lines or comments are allowed (`-- comment`)
- With `send <num> <command> <data>` you can send a command to a block
- With `goto <num>` you can jump to another line / point in time
- With `stop` you can stop the sequencer with a delay so that it does not receive a new command
accepts from a button or other block (to complete a movement)
Without `stop`, the sequencer goes into stopped mode immediately after the last command.
The TA4 sequencer supports the following techage commands:
- `goto <num>` Jump to a command line and start the sequencer
- `stop` Stop the sequencer
The `goto` command is only accepted when the sequencer is stopped.
[ta4_sequencer|image]
## TA4 Lamps ## TA4 Lamps

View File

@ -182,9 +182,12 @@
- [TA4 Lua Controller Terminal](./manual_ta4_DE.md#ta4-lua-controller-terminal) - [TA4 Lua Controller Terminal](./manual_ta4_DE.md#ta4-lua-controller-terminal)
- [TA4 Logik-/Schalt-Module](./manual_ta4_DE.md#ta4-logik-schalt-module) - [TA4 Logik-/Schalt-Module](./manual_ta4_DE.md#ta4-logik-schalt-module)
- [TA4 Taster/Schalter / Button/Switch](./manual_ta4_DE.md#ta4-tasterschalter--buttonswitch) - [TA4 Taster/Schalter / Button/Switch](./manual_ta4_DE.md#ta4-tasterschalter--buttonswitch)
- [TA4 4x Taster / 4x Button](./manual_ta4_DE.md#ta4-4x-taster--4x-button)
- [TA4 Spieler Detektor / Player Detector](./manual_ta4_DE.md#ta4-spieler-detektor--player-detector) - [TA4 Spieler Detektor / Player Detector](./manual_ta4_DE.md#ta4-spieler-detektor--player-detector)
- [TA4 Zustandssammler / State Collector](./manual_ta4_DE.md#ta4-zustandssammler--state-collector) - [TA4 Zustandssammler / State Collector](./manual_ta4_DE.md#ta4-zustandssammler--state-collector)
- [TA4 Detektor / Detector](./manual_ta4_DE.md#ta4-detektor--detector) - [TA4 Detektor / Detector](./manual_ta4_DE.md#ta4-detektor--detector)
- [TA4 Move Controller](./manual_ta4_DE.md#ta4-move-controller)
- [TA4 Sequenzer](./manual_ta4_DE.md#ta4-sequenzer)
- [TA4 Lampen](./manual_ta4_DE.md#ta4-lampen) - [TA4 Lampen](./manual_ta4_DE.md#ta4-lampen)
- [TA4 LED Pflanzenlampe / TA4 LED Grow Light](./manual_ta4_DE.md#ta4-led-pflanzenlampe--ta4-led-grow-light) - [TA4 LED Pflanzenlampe / TA4 LED Grow Light](./manual_ta4_DE.md#ta4-led-pflanzenlampe--ta4-led-grow-light)
- [TA4 LED Straßenlampe / TA4 LED Street Lamp](./manual_ta4_DE.md#ta4-led-straßenlampe--ta4-led-street-lamp) - [TA4 LED Straßenlampe / TA4 LED Street Lamp](./manual_ta4_DE.md#ta4-led-straßenlampe--ta4-led-street-lamp)

View File

@ -182,9 +182,12 @@
- [TA4 Lua Controller Terminal](./manual_ta4_EN.md#ta4-lua-controller-terminal) - [TA4 Lua Controller Terminal](./manual_ta4_EN.md#ta4-lua-controller-terminal)
- [TA4 Logic/Switching Modules](./manual_ta4_EN.md#ta4-logicswitching-modules) - [TA4 Logic/Switching Modules](./manual_ta4_EN.md#ta4-logicswitching-modules)
- [TA4 Button/Switch](./manual_ta4_EN.md#ta4-buttonswitch) - [TA4 Button/Switch](./manual_ta4_EN.md#ta4-buttonswitch)
- [TA4 4x Button](./manual_ta4_EN.md#ta4-4x-button)
- [TA4 Player Detector](./manual_ta4_EN.md#ta4-player-detector) - [TA4 Player Detector](./manual_ta4_EN.md#ta4-player-detector)
- [TA4 State Collector](./manual_ta4_EN.md#ta4-state-collector) - [TA4 State Collector](./manual_ta4_EN.md#ta4-state-collector)
- [TA4 Detector](./manual_ta4_EN.md#ta4-detector) - [TA4 Detector](./manual_ta4_EN.md#ta4-detector)
- [TA4 Move Controller](./manual_ta4_EN.md#ta4-move-controller)
- [TA4 Sequencer](./manual_ta4_EN.md#ta4-sequencer)
- [TA4 Lamps](./manual_ta4_EN.md#ta4-lamps) - [TA4 Lamps](./manual_ta4_EN.md#ta4-lamps)
- [TA4 LED Grow Light](./manual_ta4_EN.md#ta4-led-grow-light) - [TA4 LED Grow Light](./manual_ta4_EN.md#ta4-led-grow-light)
- [TA4 Street Lamp](./manual_ta4_EN.md#ta4-street-lamp) - [TA4 Street Lamp](./manual_ta4_EN.md#ta4-street-lamp)

View File

@ -253,6 +253,12 @@ minetest.register_node("techage:oilexplorer", {
end, end,
after_dig_node = function(pos, oldnode, oldmetadata, digger) after_dig_node = function(pos, oldnode, oldmetadata, digger)
techage.unmark_region(digger:get_player_name()) techage.unmark_region(digger:get_player_name())
local xpos = (math.floor(pos.x / 16) * 16)
local ypos = (math.floor(pos.y / 16) * 16)
local zpos = (math.floor(pos.z / 16) * 16)
local pos1 = {x=xpos, y=ypos, z=zpos}
local pos2 = {x=xpos+15, y=ypos+15, z=zpos+15}
techage.mark_region(digger:get_player_name(), pos1, pos2)
end, end,
is_ground_content = false, is_ground_content = false,
groups = {snappy=2,cracky=2,oddly_breakable_by_hand=2}, groups = {snappy=2,cracky=2,oddly_breakable_by_hand=2},

View File

@ -178,7 +178,7 @@ minetest.register_craft({
}) })
techage.ElectricCable = Cable techage.ElectricCable = Cable
techage.ELE1_MAX_CABLE_LENGTH = ELE1_MAX_CABLE_LENGTH techage.ELE1_MAX_CABLE_LENGTH = ELE1_MAX_CABLE_LENGHT
for idx, color in ipairs({ "white", "grey", "black", "brown", "yellow", "red", "dark_green", "blue" }) do for idx, color in ipairs({ "white", "grey", "black", "brown", "yellow", "red", "dark_green", "blue" }) do

View File

@ -165,6 +165,11 @@ end
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
-- API formspec functions -- API formspec functions
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
function techage.wrench_image(x, y)
return "image["..x.."," .. y .. ";0.5,0.5;techage_inv_wrench.png]" ..
"tooltip["..x.."," .. y .. ";0.5,0.5;" .. S("Block has a wrench menu") .. ";#0C3D32;#FFFFFF]"
end
function techage.storage_formspec(self, pos, nvm, label, netw_data, curr_load, max_load) function techage.storage_formspec(self, pos, nvm, label, netw_data, curr_load, max_load)
return "size[6.3,4]" .. return "size[6.3,4]" ..
default.gui_bg .. default.gui_bg ..

View File

@ -26,3 +26,7 @@ techage_use_marshal (use lua-marshal as serialize/deserialize functions) bool fa
# Use the external library 'lsqlite3' for for faster storing of data. # Use the external library 'lsqlite3' for for faster storing of data.
# See also 'README.md'. # See also 'README.md'.
techage_use_sqlite (use sqlite database) bool false techage_use_sqlite (use sqlite database) bool false
# To reduce the server CPU load, the number of sent techage commands
# per player and minute can be limited.
techage_command_limit (Max. number of commands sent per minute) int 1200

View File

@ -130,6 +130,7 @@ end
local function after_dig_node(pos, oldnode, oldmetadata, digger) local function after_dig_node(pos, oldnode, oldmetadata, digger)
local outdir = tonumber(oldmetadata.fields.outdir or 0) local outdir = tonumber(oldmetadata.fields.outdir or 0)
Cable:after_dig_node(pos, {outdir}) Cable:after_dig_node(pos, {outdir})
techage.remove_node(pos, oldnode, oldmetadata)
techage.del_mem(pos) techage.del_mem(pos)
end end

Binary file not shown.

After

Width:  |  Height:  |  Size: 642 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 B

View File

@ -76,7 +76,7 @@ local function read_state(itemstack, user, pointed_thing)
if ndef and ndef.description then if ndef and ndef.description then
local info = techage.send_single("0", number, "info", nil) local info = techage.send_single("0", number, "info", nil)
if info and info ~= "" and info ~= "unsupported" then if info and info ~= "" and info ~= "unsupported" then
info = dump(info) info = tostring(info)
minetest.chat_send_player(user:get_player_name(), ndef.description.." "..number..":\n"..info.." ") minetest.chat_send_player(user:get_player_name(), ndef.description.." "..number..":\n"..info.." ")
end end
local state = techage.send_single("0", number, "state", nil) local state = techage.send_single("0", number, "state", nil)
@ -136,6 +136,16 @@ end
local context = {} local context = {}
local function settings_menu(pos, playername) local function settings_menu(pos, playername)
if minetest.is_protected(pos, playername) then
return
end
-- Check node settings in addition
local access = M(pos):get_string("access")
local owner = M(pos):get_string("owner")
if access == "private" and playername ~= owner then
return
end
local number = techage.get_node_number(pos) local number = techage.get_node_number(pos)
local node = minetest.get_node(pos) local node = minetest.get_node(pos)
local ndef = minetest.registered_nodes[node.name] local ndef = minetest.registered_nodes[node.name]
@ -143,7 +153,8 @@ local function settings_menu(pos, playername)
context[playername] = pos context[playername] = pos
if form_def then if form_def then
minetest.show_formspec(playername, "techage:ta_formspec", menu.generate_formspec(pos, ndef, form_def)) minetest.show_formspec(playername, "techage:ta_formspec",
menu.generate_formspec(pos, ndef, form_def, playername))
end end
end end
@ -162,11 +173,15 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
local form_def = ndef and (ndef.ta3_formspec or ndef.ta4_formspec) local form_def = ndef and (ndef.ta3_formspec or ndef.ta4_formspec)
if form_def then if form_def then
if menu.eval_input(pos, ndef, form_def, fields) then if menu.eval_input(pos, form_def, fields, playername) then
--context[playername] = pos --context[playername] = pos
minetest.after(0.2, function() minetest.after(0.2, function()
minetest.show_formspec(playername, "techage:ta_formspec", menu.generate_formspec(pos, ndef, form_def)) minetest.show_formspec(playername, "techage:ta_formspec",
menu.generate_formspec(pos, ndef, form_def, playername))
end) end)
if ndef.ta_after_formspec then
ndef.ta_after_formspec(pos, fields, playername)
end
end end
end end
end end

View File

@ -22,10 +22,25 @@ local function index(list, x)
return nil return nil
end end
local function allow_put(inv, listname, index, stack, player)
local list = inv:get_list(listname)
stack:set_count(1)
inv:set_stack(listname, index, stack)
return 0
end
local function allow_take(inv, listname, index, stack, player)
local list = inv:get_list(listname)
stack:set_count(0)
inv:set_stack(listname, index, stack)
return 0
end
-- generate the formspec string to be placed into a container frame -- generate the formspec string to be placed into a container frame
local function generate_formspec_substring(pos, meta, form_def) local function generate_formspec_substring(pos, meta, form_def, player_name)
local tbl = {} local tbl = {}
local player_inv_needed = false
if meta and form_def then if meta and form_def then
local nvm = techage.get_nvm(pos) local nvm = techage.get_nvm(pos)
@ -97,6 +112,9 @@ local function generate_formspec_substring(pos, meta, form_def)
local idx = index(l, val) or 1 local idx = index(l, val) or 1
tbl[#tbl+1] = "dropdown[4.72," .. (offs) .. ";5.5,1.4;" .. elem.name .. ";" .. elem.choices .. ";" .. idx .. "]" tbl[#tbl+1] = "dropdown[4.72," .. (offs) .. ";5.5,1.4;" .. elem.name .. ";" .. elem.choices .. ";" .. idx .. "]"
end end
elseif elem.type == "items" then
tbl[#tbl+1] = "list[detached:" .. minetest.formspec_escape(player_name) .. "_techage_wrench_menu;cfg;4.75," .. offs .. ";" .. elem.size .. ",1;]"
player_inv_needed = true
end end
end end
if nvm.running or techage.is_running(nvm) then if nvm.running or techage.is_running(nvm) then
@ -104,17 +122,18 @@ local function generate_formspec_substring(pos, meta, form_def)
tbl[#tbl+1] = "label[0," .. offs .. ";" .. S("Note: You can't change any values while the block is running!") .. "]" tbl[#tbl+1] = "label[0," .. offs .. ";" .. S("Note: You can't change any values while the block is running!") .. "]"
end end
end end
return table.concat(tbl, "")
return player_inv_needed, table.concat(tbl, "")
end end
local function value_check(elem, value) local function value_check(elem, value)
if elem.check then if elem.check then
return elem.check(value) return elem.check(value)
end end
return true return value ~= nil
end end
local function evaluate_data(pos, meta, form_def, fields) local function evaluate_data(pos, meta, form_def, fields, player_name)
local res = true local res = true
if meta and form_def then if meta and form_def then
@ -125,7 +144,9 @@ local function evaluate_data(pos, meta, form_def, fields)
for idx,elem in ipairs(form_def) do for idx,elem in ipairs(form_def) do
if elem.type == "number" then if elem.type == "number" then
if fields[elem.name] then if fields[elem.name] then
if fields[elem.name]:find("^[%d ]+$") then if fields[elem.name] == "" then
meta:set_string(elem.name, "")
elseif fields[elem.name]:find("^[%d ]+$") then
local val = tonumber(fields[elem.name]) local val = tonumber(fields[elem.name])
if value_check(elem, val) then if value_check(elem, val) then
meta:set_int(elem.name, val) meta:set_int(elem.name, val)
@ -139,14 +160,18 @@ local function evaluate_data(pos, meta, form_def, fields)
end end
elseif elem.type == "numbers" then elseif elem.type == "numbers" then
if fields[elem.name] then if fields[elem.name] then
if fields[elem.name]:find("^[%d ]+$") and value_check(elem, fields[elem.name]) then if fields[elem.name] == "" then
meta:set_string(elem.name, "")
elseif fields[elem.name]:find("^[%d ]+$") and value_check(elem, fields[elem.name]) then
meta:set_string(elem.name, fields[elem.name]) meta:set_string(elem.name, fields[elem.name])
else else
res = false res = false
end end
end end
elseif elem.type == "float" then elseif elem.type == "float" then
if fields[elem.name] then if fields[elem.name] == ""then
meta:set_string(elem.name, "")
elseif fields[elem.name] then
local val = tonumber(fields[elem.name]) local val = tonumber(fields[elem.name])
if val and value_check(elem, val) then if val and value_check(elem, val) then
meta:set_string(elem.name, val) meta:set_string(elem.name, val)
@ -155,7 +180,9 @@ local function evaluate_data(pos, meta, form_def, fields)
end end
end end
elseif elem.type == "ascii" then elseif elem.type == "ascii" then
if fields[elem.name] then if fields[elem.name] == ""then
meta:set_string(elem.name, "")
elseif fields[elem.name] then
if value_check(elem, fields[elem.name]) then if value_check(elem, fields[elem.name]) then
meta:set_string(elem.name, fields[elem.name]) meta:set_string(elem.name, fields[elem.name])
else else
@ -166,22 +193,72 @@ local function evaluate_data(pos, meta, form_def, fields)
if fields[elem.name] ~= nil then if fields[elem.name] ~= nil then
meta:set_string(elem.name, fields[elem.name]) meta:set_string(elem.name, fields[elem.name])
end end
elseif elem.type == "items" then
local inv_name = minetest.formspec_escape(player_name) .. "_techage_wrench_menu"
local dinv = minetest.get_inventory({type = "detached", name = inv_name})
local ninv = minetest.get_inventory({type = "node", pos = pos})
if dinv and ninv then
for i = 1, ninv:get_size("cfg") do
ninv:set_stack("cfg", i, dinv:get_stack("cfg", i))
end
end
end end
end end
end end
return res return res
end end
function menu.generate_formspec(pos, ndef, form_def) function menu.generate_formspec(pos, ndef, form_def, player_name)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
local number = techage.get_node_number(pos) local number = techage.get_node_number(pos)
local mem = techage.get_mem(pos) local mem = techage.get_mem(pos)
mem.star = ((mem.star or 0) + 1) % 2 mem.star = ((mem.star or 0) + 1) % 2
local star = mem.star == 1 and "*" or "" local star = mem.star == 1 and "*" or ""
local inv_name = minetest.formspec_escape(player_name) .. "_techage_wrench_menu"
minetest.create_detached_inventory(inv_name, {
allow_put = allow_put,
allow_take = allow_take})
local dinv = minetest.get_inventory({type = "detached", name = inv_name})
local ninv = minetest.get_inventory({type = "node", pos = pos})
if dinv and ninv then
dinv:set_size('cfg', ninv:get_size("cfg"))
for i = 1, ninv:get_size("cfg") do
dinv:set_stack("cfg", i, ninv:get_stack("cfg", i))
end
end
if meta and number and ndef and form_def then if meta and number and ndef and form_def then
local title = ndef.description .. " (" .. number .. ")" local title = ndef.description .. " (" .. number .. ")"
local player_inv_needed, text = generate_formspec_substring(pos, meta, form_def, player_name)
local buttons
if player_inv_needed then
buttons = "button[0.5,6.2;3,1;refresh;" .. S("Refresh") .. "]" ..
"button_exit[3.5,6.2;3,1;cancel;" .. S("Cancel") .. "]" ..
"button[6.5,6.2;3,1;save;" .. S("Save") .. "]" ..
"list[current_player;main;1,7.2;8,2;]"
else
buttons = "button[0.5,8.4;3,1;refresh;" .. S("Refresh") .. "]" ..
"button_exit[3.5,8.4;3,1;cancel;" .. S("Cancel") .. "]" ..
"button[6.5,8.4;3,1;save;" .. S("Save") .. "]"
end
if #form_def > 8 then
local size = (#form_def * 10) - 60
return "size[10,9]" ..
default.gui_bg ..
default.gui_bg_img ..
default.gui_slots ..
"box[0,-0.1;9.8,0.5;#c6e8ff]" ..
"label[0.2,-0.1;" .. minetest.colorize( "#000000", title) .. "]" ..
"label[9.5,-0.1;" .. minetest.colorize( "#000000", star) .. "]" ..
"scrollbaroptions[max=" .. size .. "]" ..
"scrollbar[9.4,0.6;0.4,7.7;vertical;wrenchmenu;]" ..
"scroll_container[0,1;12,9;wrenchmenu;vertical;]" ..
text ..
"scroll_container_end[]" ..
buttons
else
return "size[10,9]" .. return "size[10,9]" ..
default.gui_bg .. default.gui_bg ..
default.gui_bg_img .. default.gui_bg_img ..
@ -190,20 +267,19 @@ function menu.generate_formspec(pos, ndef, form_def)
"label[0.2,-0.1;" .. minetest.colorize( "#000000", title) .. "]" .. "label[0.2,-0.1;" .. minetest.colorize( "#000000", title) .. "]" ..
"label[9.5,-0.1;" .. minetest.colorize( "#000000", star) .. "]" .. "label[9.5,-0.1;" .. minetest.colorize( "#000000", star) .. "]" ..
"container[0,1]" .. "container[0,1]" ..
generate_formspec_substring(pos, meta, form_def) .. text ..
"container_end[]" .. "container_end[]" ..
"button[0.5,8.4;3,1;refresh;" .. S("Refresh") .. "]" .. buttons
"button_exit[3.5,8.4;3,1;cancel;" .. S("Cancel") .. "]" .. end
"button[6.5,8.4;3,1;save;" .. S("Save") .. "]"
end end
return "" return ""
end end
function menu.eval_input(pos, ndef, form_def, fields) function menu.eval_input(pos, form_def, fields, player_name)
--print(dump(fields)) --print(dump(fields))
if fields.save then if fields.save then
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
evaluate_data(pos, meta, form_def, fields) evaluate_data(pos, meta, form_def, fields, player_name)
end end
return fields.refresh or fields.save return fields.refresh or fields.save
end end