Add 'exchange' command to the door controller

This commit is contained in:
Joachim Stolberg 2021-02-26 11:25:22 +01:00
parent b178801acb
commit e12262172b
7 changed files with 107 additions and 56 deletions

View File

@ -997,10 +997,18 @@ techage.manual_DE.aText = {
"\n".. "\n"..
"\n".. "\n"..
"\n", "\n",
"Der Tür Controller II kann alle Arten von Blöcken entfernen und wieder setzen. Um den Tür Controller II anzulernen\\, muss der \"Aufzeichnen\" Button gedrückt werden. Dann müssen alle Blöcke angeklickt werden\\, die Teil der Tür / des Tores sein sollen. Danach muss der \"Fertig\" Button gedrückt werden. Es können bis zu 16 Blöcke ausgewählt werden. Die entfernten Blöcke werden im Inventar des Controllers gespeichert. Über die Tasten \"Entfernen\" bzw. \"Setzen\" kann die Funktion des Controllers von Hand getestet werden.\n".. "Der Tür Controller II kann alle Arten von Blöcken entfernen und wieder setzen. Um den Tür Controller II anzulernen\\, muss der \"Aufzeichnen\" Button gedrückt werden. Dann müssen alle Blöcke angeklickt werden\\, die Teil der Tür / des Tores sein sollen. Danach muss der \"Fertig\" Button gedrückt werden. Es können bis zu 16 Blöcke ausgewählt werden. Die entfernten Blöcke werden im Inventar des Controllers gespeichert.\n"..
"\n"..
" Über die Tasten \"Entfernen\" bzw. \"Setzen\" kann die Funktion des Controllers von Hand getestet werden.\n"..
"\n".. "\n"..
"Wird ein 'on' / 'off' Kommando an den Tür Controller II gesendet\\, entfernt bzw. setzt er die Blöcke ebenfalls.\n".. "Wird ein 'on' / 'off' Kommando an den Tür Controller II gesendet\\, entfernt bzw. setzt er die Blöcke ebenfalls.\n"..
"\n".. "\n"..
"Über ein 'exchange' Kommando können einzelne Böcke gesetzt\\, entfernt\\, bzw. durch andere Blöcke ersetzt werden. Die Slot-Nummer des Inventars (1 .. 16) muss als payload übergeben werden\\, also:\n"..
"\n"..
" $send_cmnd(node_number\\, \"exchange\"\\, 2)\n"..
"\n"..
"Damit lassen sich auch ausfahrbare Treppen und ähnliches simulieren.\n"..
"\n"..
"\n".. "\n"..
"\n", "\n",
"Der Mesecons Umsetzer dient zur Umwandlung von Techage on/off Kommandos in Mesecons Signale und umgekehrt.\n".. "Der Mesecons Umsetzer dient zur Umwandlung von Techage on/off Kommandos in Mesecons Signale und umgekehrt.\n"..

View File

@ -988,6 +988,12 @@ techage.manual_EN.aText = {
"\n", "\n",
"The Door Controller II can remove and set all types of blocks. To teach in the Door Controller II\\, the \"Record\" button must be pressed. Then all blocks that should be part of the door / gate must be clicked. Then the \"Done\" button must be pressed. Up to 16 blocks can be selected. The removed blocks are saved in the controller's inventory. The function of the controller can be tested manually using the \"Remove\" or \"Set\" buttons. If an 'on' /'off' command is sent to the Door Controller II\\, it removes or sets the blocks as well.\n".. "The Door Controller II can remove and set all types of blocks. To teach in the Door Controller II\\, the \"Record\" button must be pressed. Then all blocks that should be part of the door / gate must be clicked. Then the \"Done\" button must be pressed. Up to 16 blocks can be selected. The removed blocks are saved in the controller's inventory. The function of the controller can be tested manually using the \"Remove\" or \"Set\" buttons. If an 'on' /'off' command is sent to the Door Controller II\\, it removes or sets the blocks as well.\n"..
"\n".. "\n"..
"Individual blocks can be set\\, removed or replaced by other blocks via an 'exchange' command. The slot number of the inventory (1 .. 16) must be transferred as payload\\, i.e.:\n"..
"\n"..
" $send_cmnd(node_number\\, \"exchange\"\\, 2)\n"..
"\n"..
"This can also be used to simulate extendable stairs and the like. \n"..
"\n"..
"\n".. "\n"..
"\n", "\n",
"The Mesecons converter is used to convert Techage on/off commands into Mesecons signals and vice versa.\n".. "The Mesecons converter is used to convert Techage on/off commands into Mesecons signals and vice versa.\n"..

View File

@ -3,7 +3,7 @@
TechAge TechAge
======= =======
Copyright (C) 2020 Joachim Stolberg Copyright (C) 2020-2021 Joachim Stolberg
AGPL v3 AGPL v3
See LICENSE.txt for more information See LICENSE.txt for more information
@ -19,23 +19,43 @@ local S = techage.S
local logic = techage.logic local logic = techage.logic
local MarkedNodes = {} -- t[player][hash] = entity local MarkedNodes = {} -- t[player] = {{entity, pos},...}
local CurrentPos -- to mark punched entities local CurrentPos -- to mark punched entities
local RegisteredNodes = {} -- to be checked before removed/placed
local function is_simple_node(name)
-- special handling
if RegisteredNodes[name] ~= nil then
return RegisteredNodes[name]
end
local ndef = minetest.registered_nodes[name]
if not ndef or name == "air" then return true end
if ndef.groups and ndef.groups.techage_door == 1 then return true end
-- don't remove nodes with some intelligence or undiggable nodes
if ndef.drop == "" then return false end
if ndef.diggable == false then return false end
if ndef.after_dig_node then return false end
return true
end
local function unmark_position(name, pos) local function unmark_position(name, pos)
MarkedNodes[name] = MarkedNodes[name] or {}
pos = vector.round(pos) pos = vector.round(pos)
local hash = minetest.hash_node_position(pos) for idx,item in ipairs(MarkedNodes[name] or {}) do
if MarkedNodes[name][hash] then if vector.equals(pos, item.pos) then
MarkedNodes[name][hash]:remove() item.entity:remove()
MarkedNodes[name][hash] = nil table.remove(MarkedNodes[name], idx)
CurrentPos = hash CurrentPos = pos
return
end
end end
end end
local function unmark_all(name) local function unmark_all(name)
for _,entity in pairs(MarkedNodes[name] or {}) do for _,item in ipairs(MarkedNodes[name] or {}) do
entity:remove() item.entity:remove()
end end
MarkedNodes[name] = nil MarkedNodes[name] = nil
end end
@ -43,12 +63,11 @@ end
local function mark_position(name, pos) local function mark_position(name, pos)
MarkedNodes[name] = MarkedNodes[name] or {} MarkedNodes[name] = MarkedNodes[name] or {}
pos = vector.round(pos) pos = vector.round(pos)
local hash = minetest.hash_node_position(pos) if not CurrentPos or not vector.equals(pos, CurrentPos) then -- entity not punched?
if hash ~= CurrentPos then -- entity not punched?
local entity = minetest.add_entity(pos, "techage:marker") local entity = minetest.add_entity(pos, "techage:marker")
if entity ~= nil then if entity ~= nil then
entity:get_luaentity().player_name = name entity:get_luaentity().player_name = name
MarkedNodes[name][hash] = entity table.insert(MarkedNodes[name], {pos = pos, entity = entity})
end end
CurrentPos = nil CurrentPos = nil
return true return true
@ -56,11 +75,10 @@ local function mark_position(name, pos)
CurrentPos = nil CurrentPos = nil
end end
local function table_to_poslist(name) local function get_poslist(name)
local lst = {} local lst = {}
for hash,_ in pairs(MarkedNodes[name] or {}) do for _,item in ipairs(MarkedNodes[name] or {}) do
local pos = minetest.get_position_from_hash(hash) table.insert(lst, item.pos)
table.insert(lst, pos)
end end
return lst return lst
end end
@ -100,21 +118,25 @@ minetest.register_entity(":techage:marker", {
local function formspec1(meta) local function formspec1(meta)
local status = meta:get_string("status") local status = meta:get_string("status")
return "size[8,6.5]".. return "size[8,7]"..
"tabheader[0,0;tab;"..S("Ctrl,Inv")..";1;;true]".. "tabheader[0,0;tab;"..S("Ctrl,Inv")..";1;;true]"..
"button[0.7,0;3,1;record;"..S("Record").."]".. "button[0.7,0.5;3,1;record;"..S("Record").."]"..
"button[4.3,0;3,1;ready;"..S("Done").."]".. "button[4.3,0.5;3,1;ready;"..S("Done").."]"..
"button[0.7,1;3,1;show;"..S("Set").."]".. "button[0.7,1.5;3,1;show;"..S("Set").."]"..
"button[4.3,1;3,1;hide;"..S("Remove").."]".. "button[4.3,1.5;3,1;hide;"..S("Remove").."]"..
"label[0.5,2;"..status.."]".. "label[0.5,2.5;"..status.."]"..
"list[current_player;main;0,2.8;8,4;]" "list[current_player;main;0,3.3;8,4;]"
end end
local function formspec2() local function formspec2()
return "size[8,6.5]".. return "size[8,7]"..
"tabheader[0,0;tab;"..S("Ctrl,Inv")..";2;;true]".. "tabheader[0,0;tab;"..S("Ctrl,Inv")..";2;;true]"..
"list[context;main;0,0;8,2;]".. "label[0.3,0.0;1]"..
"list[current_player;main;0,2.8;8,4;]".. "label[7.3,0.0;8]"..
"label[0.3,2.4;9]"..
"label[7.3,2.4;16]"..
"list[context;main;0,0.5;8,2;]"..
"list[current_player;main;0,3.3;8,4;]"..
"listring[context;main]".. "listring[context;main]"..
"listring[current_player;main]" "listring[current_player;main]"
end end
@ -128,22 +150,22 @@ end
local function exchange_node(pos, item, param2) local function exchange_node(pos, item, param2)
local node = minetest.get_node_or_nil(pos) local node = minetest.get_node_or_nil(pos)
local meta = minetest.get_meta(pos) if node and is_simple_node(node.name) then
if node and (not meta or not next((meta:to_table()).fields)) or if item and item:get_name() ~= "" then
minetest.get_item_group(node.name, "techage_door") then
if item and item:get_name() ~= "" and param2 then
minetest.swap_node(pos, {name = item:get_name(), param2 = param2}) minetest.swap_node(pos, {name = item:get_name(), param2 = param2})
else else
minetest.remove_node(pos) minetest.remove_node(pos)
end end
if node.name ~= "air" then if node.name ~= "air" then
return ItemStack(node.name), node.param2 return ItemStack(node.name), node.param2
else
return ItemStack(), nil
end end
end end
return ItemStack(), nil return item, param2
end end
local function exchange_nodes(pos, nvm) local function exchange_nodes(pos, nvm, slot)
local meta = M(pos) local meta = M(pos)
local inv = meta:get_inventory() local inv = meta:get_inventory()
@ -153,7 +175,7 @@ local function exchange_nodes(pos, nvm)
nvm.pos_list = nvm.pos_list or {} nvm.pos_list = nvm.pos_list or {}
nvm.param2_list = nvm.param2_list or {} nvm.param2_list = nvm.param2_list or {}
for idx = 1, 16 do for idx = (slot or 1), (slot or 16) do
local pos = nvm.pos_list[idx] local pos = nvm.pos_list[idx]
if pos and not minetest.is_protected(pos, owner) then if pos and not minetest.is_protected(pos, owner) then
item_list[idx], nvm.param2_list[idx] = exchange_node(pos, item_list[idx], nvm.param2_list[idx]) item_list[idx], nvm.param2_list[idx] = exchange_node(pos, item_list[idx], nvm.param2_list[idx])
@ -213,22 +235,18 @@ minetest.register_node("techage:ta3_doorcontroller2", {
return return
elseif fields.record then elseif fields.record then
local inv = meta:get_inventory() local inv = meta:get_inventory()
if not inv:is_empty("main") then local nvm = techage.get_nvm(pos)
meta:set_string("status", S("Error: Inventory already in use")) nvm.pos_list = nil
else nvm.is_on = false
local nvm = techage.get_nvm(pos) meta:set_string("status", S("Recording..."))
nvm.pos_list = nil local name = player:get_player_name()
nvm.is_on = false minetest.chat_send_player(name, S("Click on all the blocks that are part of the door/gate"))
meta:set_string("status", S("Recording...")) MarkedNodes[name] = {}
local name = player:get_player_name()
minetest.chat_send_player(name, S("Click on all the blocks that are part of the door/gate"))
MarkedNodes[name] = {}
end
meta:set_string("formspec", formspec1(meta)) meta:set_string("formspec", formspec1(meta))
elseif fields.ready then elseif fields.ready then
local nvm = techage.get_nvm(pos) local nvm = techage.get_nvm(pos)
local name = player:get_player_name() local name = player:get_player_name()
local pos_list = table_to_poslist(name) local pos_list = get_poslist(name)
local text = #pos_list.." "..S("block positions are stored.") local text = #pos_list.." "..S("block positions are stored.")
meta:set_string("status", text) meta:set_string("status", text)
nvm.pos_list = pos_list nvm.pos_list = pos_list
@ -258,7 +276,7 @@ minetest.register_node("techage:ta3_doorcontroller2", {
if minetest.is_protected(pos, player:get_player_name()) then if minetest.is_protected(pos, player:get_player_name()) then
return 0 return 0
end end
return 0 return 1
end, end,
allow_metadata_inventory_take = function(pos, listname, index, stack, player) allow_metadata_inventory_take = function(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then if minetest.is_protected(pos, player:get_player_name()) then
@ -270,10 +288,7 @@ minetest.register_node("techage:ta3_doorcontroller2", {
if minetest.is_protected(pos, player:get_player_name()) then if minetest.is_protected(pos, player:get_player_name()) then
return 0 return 0
end end
if is_simple_node(stack:get_name()) then
local inv = minetest.get_inventory({type="node", pos=pos})
local pos_list = minetest.deserialize(M(pos):get_string("pos_list")) or {}
if pos_list[index] and inv:get_stack(listname, index):get_count() == 0 then
return 1 return 1
end end
return 0 return 0
@ -301,9 +316,12 @@ minetest.register_node("techage:ta3_doorcontroller2", {
techage.register_node({"techage:ta3_doorcontroller2"}, { techage.register_node({"techage:ta3_doorcontroller2"}, {
on_recv_message = function(pos, src, topic, payload) on_recv_message = function(pos, src, topic, payload)
if topic == "on" then if topic == "on" then
return hide_nodes(pos, nil) return hide_nodes(pos)
elseif topic == "off" then elseif topic == "off" then
return show_nodes(pos) return show_nodes(pos)
elseif topic == "exchange" then
local nvm = techage.get_nvm(pos)
return exchange_nodes(pos, nvm, tonumber(payload))
end end
return false return false
end, end,
@ -345,4 +363,4 @@ minetest.register_on_punchnode(function(pos, node, puncher, pointed_thing)
mark_position(name, pointed_thing.under) mark_position(name, pointed_thing.under)
end end
end) end)

View File

@ -636,10 +636,20 @@ Der Tür Controller dient zur Ansteuerung der TA3 Tür/Tor Blöcke. Beim Tür Co
### TA3 Tür Controller II / Door Controller II ### TA3 Tür Controller II / Door Controller II
Der Tür Controller II kann alle Arten von Blöcken entfernen und wieder setzen. Um den Tür Controller II anzulernen, muss der "Aufzeichnen" Button gedrückt werden. Dann müssen alle Blöcke angeklickt werden, die Teil der Tür / des Tores sein sollen. Danach muss der "Fertig" Button gedrückt werden. Es können bis zu 16 Blöcke ausgewählt werden. Die entfernten Blöcke werden im Inventar des Controllers gespeichert. Über die Tasten "Entfernen" bzw. "Setzen" kann die Funktion des Controllers von Hand getestet werden. Der Tür Controller II kann alle Arten von Blöcken entfernen und wieder setzen. Um den Tür Controller II anzulernen, muss der "Aufzeichnen" Button gedrückt werden. Dann müssen alle Blöcke angeklickt werden, die Teil der Tür / des Tores sein sollen. Danach muss der "Fertig" Button gedrückt werden. Es können bis zu 16 Blöcke ausgewählt werden. Die entfernten Blöcke werden im Inventar des Controllers gespeichert.
Über die Tasten "Entfernen" bzw. "Setzen" kann die Funktion des Controllers von Hand getestet werden.
Wird ein `on` / `off` Kommando an den Tür Controller II gesendet, entfernt bzw. setzt er die Blöcke ebenfalls. Wird ein `on` / `off` Kommando an den Tür Controller II gesendet, entfernt bzw. setzt er die Blöcke ebenfalls.
Über ein `exchange` Kommando können einzelne Böcke gesetzt, entfernt, bzw. durch andere Blöcke ersetzt werden. Die Slot-Nummer des Inventars (1 .. 16) muss als payload übergeben werden, also:
```
$send_cmnd(node_number, "exchange", 2)
```
Damit lassen sich auch ausfahrbare Treppen und ähnliches simulieren.
[ta3_doorcontroller|image] [ta3_doorcontroller|image]
### TA3 Mesecons Umsetzer / TA3 Mesecons Converter ### TA3 Mesecons Umsetzer / TA3 Mesecons Converter

View File

@ -621,7 +621,15 @@ The door controller is used to control the TA3 door/gate blocks. With the door c
### TA3 Door Controller II ### TA3 Door Controller II
The Door Controller II can remove and set all types of blocks. To teach in the Door Controller II, the "Record" button must be pressed. Then all blocks that should be part of the door / gate must be clicked. Then the "Done" button must be pressed. Up to 16 blocks can be selected. The removed blocks are saved in the controller's inventory. The function of the controller can be tested manually using the "Remove" or "Set" buttons. If an `on` /` off` command is sent to the Door Controller II, it removes or sets the blocks as well. The Door Controller II can remove and set all types of blocks. To teach in the Door Controller II, the "Record" button must be pressed. Then all blocks that should be part of the door / gate must be clicked. Then the "Done" button must be pressed. Up to 16 blocks can be selected. The removed blocks are saved in the controller's inventory. The function of the controller can be tested manually using the "Remove" or "Set" buttons. If an `on` /`off` command is sent to the Door Controller II, it removes or sets the blocks as well.
Individual blocks can be set, removed or replaced by other blocks via an `exchange` command. The slot number of the inventory (1 .. 16) must be transferred as payload, i.e.:
```
$send_cmnd(node_number, "exchange", 2)
```
This can also be used to simulate extendable stairs and the like.
[ta3_doorcontroller|image] [ta3_doorcontroller|image]

View File

@ -390,6 +390,7 @@ Please note, that this is not a technical distinction, only a logical.
| "reset" | nil | Reset the item counter of the TA4 Item Detector block | | "reset" | nil | Reset the item counter of the TA4 Item Detector block |
| "pull" | item string | Start the TA4 pusher to pull/push items.<br /> Example: `default:dirt 8` | | "pull" | item string | Start the TA4 pusher to pull/push items.<br /> Example: `default:dirt 8` |
| "config" | item string | Configure the TA4 pusher.<br />Example: `wool:blue` | | "config" | item string | Configure the TA4 pusher.<br />Example: `wool:blue` |
| "exchange" | inventory slot number | place/remove/exchange an block by means of the TA3 Door Controller II (techage:ta3_doorcontroller2) |

Binary file not shown.