Improve door and fly controller

This commit is contained in:
Joachim Stolberg 2025-01-03 16:38:21 +01:00
parent e9c868e264
commit 5425e10e91
17 changed files with 259 additions and 368 deletions

View File

@ -60,6 +60,7 @@ local function set_node(item, playername)
minetest.set_node(dest_pos, {name=name, param2=param2}) minetest.set_node(dest_pos, {name=name, param2=param2})
meta:from_table(item.metadata or {}) meta:from_table(item.metadata or {})
meta:set_string("ta_move_block", "") meta:set_string("ta_move_block", "")
-- Protect the doors from being opened by hand
meta:set_int("ta_door_locked", 1) meta:set_int("ta_door_locked", 1)
end end
return return
@ -623,6 +624,7 @@ end
-- for the attached object (player). -- for the attached object (player).
local function multi_move_nodes(pos, meta, nvm, lmove, max_speed, height, move2to1) local function multi_move_nodes(pos, meta, nvm, lmove, max_speed, height, move2to1)
local owner = meta:get_string("owner") local owner = meta:get_string("owner")
local running = false
techage.counting_add(owner, #lmove, #nvm.lpos1 * #lmove) techage.counting_add(owner, #lmove, #nvm.lpos1 * #lmove)
for idx = 1, #nvm.lpos1 do for idx = 1, #nvm.lpos1 do
@ -660,9 +662,12 @@ local function multi_move_nodes(pos, meta, nvm, lmove, max_speed, height, move2t
end end
return false return false
end end
running = true
end end
meta:set_string("status", S("Running")) if running then
return true meta:set_string("status", S("Running"))
end
return running
end end
-- Move the nodes from lpos1 to lpos2. -- Move the nodes from lpos1 to lpos2.
@ -681,11 +686,12 @@ local function move_nodes(pos, meta, lpos1, move, max_speed, height)
local pos1 = lpos1[idx] local pos1 = lpos1[idx]
local pos2 = vector.add(lpos1[idx], move) local pos2 = vector.add(lpos1[idx], move)
lpos2[idx] = pos2 lpos2[idx] = pos1
if not minetest.is_protected(pos1, owner) and not minetest.is_protected(pos2, owner) then 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 if is_simple_node(pos1) and is_valid_dest(pos2) then
move_node(pos, meta, pos1, {move}, max_speed, height) move_node(pos, meta, pos1, {move}, max_speed, height)
lpos2[idx] = pos2
else else
if not is_simple_node(pos1) then if not is_simple_node(pos1) then
meta:set_string("status", S("No valid node at the start position")) meta:set_string("status", S("No valid node at the start position"))
@ -829,7 +835,7 @@ function flylib.move_to_other_pos(pos, move2to1)
return nvm.running return nvm.running
end end
-- `move` the movement as a vector -- `move` is the movement as a vector
function flylib.move_to(pos, move) function flylib.move_to(pos, move)
local meta = M(pos) local meta = M(pos)
local nvm = techage.get_nvm(pos) local nvm = techage.get_nvm(pos)
@ -857,11 +863,19 @@ function flylib.reset_move(pos)
if nvm.running then return false end if nvm.running then return false end
if meta:get_string("teleport_mode") == "enable" then return false end if meta:get_string("teleport_mode") == "enable" then return false end
if nvm.lpos1 and nvm.lpos1[1] then if nvm.moveBA then -- A/B mode has no nvm.lastpos
local move = vector.subtract(nvm.lpos1[1], (nvm.lastpos or nvm.lpos1)[1]) if nvm.lpos2 and nvm.lpos2[1] then
local move = vector.subtract(nvm.lpos2[1], nvm.lpos1[1])
nvm.running, nvm.lastpos = move_nodes(pos, meta, nvm.lastpos or nvm.lpos1, move, max_speed, height) nvm.running, nvm.lastpos = move_nodes(pos, meta, nvm.lpos2, move, max_speed, height)
return nvm.running return nvm.running
end
else
if nvm.lpos1 and nvm.lpos1[1] then
local move = vector.subtract(nvm.lpos1[1], (nvm.lastpos or nvm.lpos2)[1])
local lpos = nvm.lastpos or nvm.lpos1
nvm.running, nvm.lastpos = move_nodes(pos, meta, lpos, move, max_speed, height)
return nvm.running
end
end end
return false return false
end end

View File

@ -26,7 +26,7 @@ local function unmark_position(name, pos)
item.entity:remove() item.entity:remove()
table.remove(MarkedNodes[name], idx) table.remove(MarkedNodes[name], idx)
CurrentPos = pos CurrentPos = pos
return return true
end end
end end
end end
@ -57,10 +57,15 @@ end
function marker.get_poslist(name) function marker.get_poslist(name)
local idx = 0 local idx = 0
local lst = {} local lst = {}
local hashlist = {}
for _,item in ipairs(MarkedNodes[name] or {}) do for _,item in ipairs(MarkedNodes[name] or {}) do
table.insert(lst, item.pos) local hash = minetest.hash_node_position(item.pos)
idx = idx + 1 if not hashlist[hash] then
if idx >= MAX_NUM then break end table.insert(lst, item.pos)
hashlist[hash] = true
idx = idx + 1
if idx >= MAX_NUM then break end
end
end end
return lst return lst
end end
@ -87,6 +92,16 @@ function marker.stop(name)
MaxNumber[name] = nil MaxNumber[name] = nil
end end
function marker.mark_positions(name, lpos, ttl)
for _,pos in ipairs(lpos or {}) do
local entity = minetest.add_entity(pos, "techage:block_marker")
if entity ~= nil then
entity:get_luaentity().player_name = name
entity:get_luaentity().ttl = ttl
end
end
end
minetest.register_on_leaveplayer(function(ObjectRef, timed_out) minetest.register_on_leaveplayer(function(ObjectRef, timed_out)
if ObjectRef and ObjectRef:is_player() then if ObjectRef and ObjectRef:is_player() then
local name = ObjectRef:get_player_name() local name = ObjectRef:get_player_name()
@ -110,19 +125,20 @@ minetest.register_entity(":techage:block_marker", {
visual_size = {x=1.1, y=1.1}, visual_size = {x=1.1, y=1.1},
collisionbox = {-0.55,-0.55,-0.55, 0.55,0.55,0.55}, collisionbox = {-0.55,-0.55,-0.55, 0.55,0.55,0.55},
glow = 8, glow = 8,
static_save = false,
}, },
on_step = function(self, dtime) on_step = function(self, dtime)
self.ttl = (self.ttl or 2400) - 1 self.ttl = (self.ttl or 2400) - 1
if self.ttl <= 0 then if self.ttl <= 0 then
local pos = self.object:get_pos() local pos = self.object:get_pos()
unmark_position(self.player_name, pos) if not unmark_position(self.player_name, pos) then self.object:remove() end
end end
end, end,
on_punch = function(self, hitter) on_punch = function(self, hitter)
local pos = self.object:get_pos() local pos = self.object:get_pos()
local name = hitter:get_player_name() local name = hitter:get_player_name()
if name == self.player_name then if name == self.player_name then
unmark_position(name, pos) if not unmark_position(self.player_name, pos) then self.object:remove() end
end end
end, end,
}) })

View File

@ -593,7 +593,7 @@ return {
"\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.\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".. "\n"..
" Über die Tasten \"Entfernen\" bzw. \"Setzen\" kann die Funktion des Controllers von Hand getestet werden.\n".. " Über die Taste \"Austauschen\" 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"..
@ -607,6 +607,8 @@ return {
"\n".. "\n"..
"Die Slot-Nummer des Inventars (1 .. 16) muss in allen drei Fällen als payload übergeben werden.\n".. "Die Slot-Nummer des Inventars (1 .. 16) muss in allen drei Fällen als payload übergeben werden.\n"..
"\n".. "\n"..
"Mit '$send_cmnd(node_number\\, \"reset\")' wird der Tür Controller zurückgesetzt. \n"..
"\n"..
"Damit lassen sich auch ausfahrbare Treppen und ähnliches simulieren.\n".. "Damit lassen sich auch ausfahrbare Treppen und ähnliches simulieren.\n"..
"\n".. "\n"..
"\n".. "\n"..

View File

@ -592,7 +592,7 @@ return {
"\n".. "\n"..
"\n".. "\n"..
"\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 \"Exchange\" button. If an 'on' /'off' command is sent to the Door Controller II\\, it removes or sets the blocks as well.\n"..
"\n".. "\n"..
"With '$send_cmnd(node_number\\, \"exchange\"\\, 2)' individual blocks can be set\\, removed or replaced by other blocks from the inventory. \n".. "With '$send_cmnd(node_number\\, \"exchange\"\\, 2)' individual blocks can be set\\, removed or replaced by other blocks from the inventory. \n"..
"\n".. "\n"..
@ -604,6 +604,8 @@ return {
"\n".. "\n"..
"The slot number of the inventory (1 .. 16) must be passed as payload in all three cases.\n".. "The slot number of the inventory (1 .. 16) must be passed as payload in all three cases.\n"..
"\n".. "\n"..
"With '$send_cmnd(node_number\\, \"reset\")' the door controller is reset.\n"..
"\n"..
"This can also be used to simulate extendable stairs and the like. \n".. "This can also be used to simulate extendable stairs and the like. \n"..
"\n".. "\n"..
"\n".. "\n"..

View File

@ -424,6 +424,7 @@ Recording...=Aufzeichnung...
### movecontroller.lua ### ### movecontroller.lua ###
Reset=Rücksetzen Reset=Rücksetzen
Show positions=Positionen anzeigen
### drillbox.lua ### ### drillbox.lua ###
@ -1601,6 +1602,3 @@ Remove detector=Entferne Detektor
TA4 Collider Detector Worker=TA4 Collider Detektor Worker TA4 Collider Detector Worker=TA4 Collider Detektor Worker
[TA4] Detector is being built!=[TA4] Detektor wird gebaut! [TA4] Detector is being built!=[TA4] Detektor wird gebaut!
[TA4] Detector is being removed!=[TA4] Detektor wird entfernt! [TA4] Detector is being removed!=[TA4] Detektor wird entfernt!
##### not used anymore #####

View File

@ -424,6 +424,7 @@ Recording...=Enregistrement...
### movecontroller.lua ### ### movecontroller.lua ###
Reset= Reset=
Show positions=
### drillbox.lua ### ### drillbox.lua ###

View File

@ -424,6 +424,7 @@ Recording...=Запись...
### movecontroller.lua ### ### movecontroller.lua ###
Reset=Переустановить Reset=Переустановить
Show positions=
### drillbox.lua ### ### drillbox.lua ###

View File

@ -424,6 +424,7 @@ Recording...=
### movecontroller.lua ### ### movecontroller.lua ###
Reset= Reset=
Show positions=
### drillbox.lua ### ### drillbox.lua ###

View File

@ -15,6 +15,7 @@
local M = minetest.get_meta local M = minetest.get_meta
local S = techage.S local S = techage.S
local SCREENSAVER_TIME = 60 * 5 local SCREENSAVER_TIME = 60 * 5
local CYCLE_TIME = 0.2
local Functions = {} local Functions = {}
local Actions = {} local Actions = {}
@ -301,7 +302,8 @@ minetest.register_node("techage:basic_terminal", {
on_timer = function(pos, elapsed) on_timer = function(pos, elapsed)
local nvm = techage.get_nvm(pos) local nvm = techage.get_nvm(pos)
--print("on_timer", nvm.status) --print("on_timer", nvm.status)
if (nvm.timeout or 0) > minetest.get_gametime() then if nvm.ttl and nvm.ttl > 1 then
nvm.ttl = nvm.ttl - 1
return true return true
end end
@ -315,14 +317,14 @@ minetest.register_node("techage:basic_terminal", {
nvm.status = "error" nvm.status = "error"
nvm.bttns = {"Edit", "", "", "", "", "Stop", "", ""} nvm.bttns = {"Edit", "", "", "", "", "Stop", "", ""}
nvm.input = "" nvm.input = ""
nvm.timeout = 0 nvm.ttl = nil
local text = nanobasic.get_screen_buffer(pos) local text = nanobasic.get_screen_buffer(pos)
M(pos):set_string("formspec", formspec(pos, text)) M(pos):set_string("formspec", formspec(pos, text))
elseif res == nanobasic.NB_END then elseif res == nanobasic.NB_END then
nvm.status = "stopped" nvm.status = "stopped"
nvm.bttns = {"Edit", "", "", "", "Run", "Stop", "", ""} nvm.bttns = {"Edit", "", "", "", "Run", "Stop", "", ""}
nvm.input = "" nvm.input = ""
nvm.timeout = 0 nvm.ttl = nil
local text = nanobasic.get_screen_buffer(pos) local text = nanobasic.get_screen_buffer(pos)
M(pos):set_string("formspec", formspec(pos, text)) M(pos):set_string("formspec", formspec(pos, text))
elseif res == nanobasic.NB_BREAK then elseif res == nanobasic.NB_BREAK then
@ -331,7 +333,7 @@ minetest.register_node("techage:basic_terminal", {
nvm.status = "break" nvm.status = "break"
nvm.bttns = {"", "", "", "", "", "Stop", "Continue", "List"} nvm.bttns = {"", "", "", "", "", "Stop", "Continue", "List"}
nvm.input = InputField nvm.input = InputField
nvm.timeout = 0 nvm.ttl = nil
local text = nanobasic.get_screen_buffer(pos) local text = nanobasic.get_screen_buffer(pos)
M(pos):set_string("formspec", formspec(pos, text)) M(pos):set_string("formspec", formspec(pos, text))
elseif res >= nanobasic.NB_XFUNC then elseif res >= nanobasic.NB_XFUNC then
@ -472,7 +474,7 @@ end)
register_ext_function("sleep", {nanobasic.NB_NUM}, nanobasic.NB_NONE, function(pos, nvm) register_ext_function("sleep", {nanobasic.NB_NUM}, nanobasic.NB_NONE, function(pos, nvm)
local t = nanobasic.pop_num(pos) or 0 local t = nanobasic.pop_num(pos) or 0
nvm.timeout = minetest.get_gametime() + t nvm.ttl = t / CYCLE_TIME
local text = nanobasic.get_screen_buffer(pos) local text = nanobasic.get_screen_buffer(pos)
M(pos):set_string("formspec", formspec(pos, text)) M(pos):set_string("formspec", formspec(pos, text))
return true return true
@ -700,8 +702,8 @@ register_action({"init", "edit", "stopped"}, "Run", function(pos, nvm, fields)
nvm.input = "" nvm.input = ""
nvm.variables = nanobasic.get_variable_list(pos) nvm.variables = nanobasic.get_variable_list(pos)
nvm.error_label_addr = nanobasic.get_label_address(pos, "65000") or 0 nvm.error_label_addr = nanobasic.get_label_address(pos, "65000") or 0
nvm.timeout = 0 nvm.ttl = nil
minetest.get_node_timer(pos):start(0.2) minetest.get_node_timer(pos):start(CYCLE_TIME)
return nanobasic.get_screen_buffer(pos) or "" return nanobasic.get_screen_buffer(pos) or ""
else else
nvm.status = "error" nvm.status = "error"
@ -715,7 +717,7 @@ register_action({"break"}, "Continue", function(pos, nvm, fields)
nvm.status = "running" nvm.status = "running"
nvm.bttns = {"", "", "", "", "", "Stop", "", ""} nvm.bttns = {"", "", "", "", "", "Stop", "", ""}
nvm.input = "" nvm.input = ""
minetest.get_node_timer(pos):start(0.2) minetest.get_node_timer(pos):start(CYCLE_TIME)
return nanobasic.get_screen_buffer(pos) or "" return nanobasic.get_screen_buffer(pos) or ""
end) end)
@ -798,7 +800,7 @@ register_action({"input_num"}, "Enter", function(pos, nvm, fields)
nvm.status = "running" nvm.status = "running"
nvm.bttns = {"", "", "", "", "", "Stop", "", ""} nvm.bttns = {"", "", "", "", "", "Stop", "", ""}
nvm.input = "" nvm.input = ""
minetest.get_node_timer(pos):start(0.2) minetest.get_node_timer(pos):start(CYCLE_TIME)
return nanobasic.get_screen_buffer(pos) or "" return nanobasic.get_screen_buffer(pos) or ""
end) end)
@ -808,7 +810,7 @@ register_action({"input_str"}, "Enter", function(pos, nvm, fields)
nvm.status = "running" nvm.status = "running"
nvm.bttns = {"", "", "", "", "", "Stop", "", ""} nvm.bttns = {"", "", "", "", "", "Stop", "", ""}
nvm.input = "" nvm.input = ""
minetest.get_node_timer(pos):start(0.2) minetest.get_node_timer(pos):start(CYCLE_TIME)
return nanobasic.get_screen_buffer(pos) or "" return nanobasic.get_screen_buffer(pos) or ""
end) end)
@ -818,7 +820,7 @@ techage.register_node({"techage:basic_terminal"}, {
nanobasic.vm_restore(pos) nanobasic.vm_restore(pos)
local nvm = techage.get_nvm(pos) local nvm = techage.get_nvm(pos)
if nvm.status == "running" then if nvm.status == "running" then
minetest.get_node_timer(pos):start(0.2) minetest.get_node_timer(pos):start(CYCLE_TIME)
end end
end, end,
}) })

View File

@ -59,6 +59,8 @@ local WRENCH_MENU = {
}, },
} }
local delayed_start = false
local function cycle_time(pos) local function cycle_time(pos)
local mem = techage.get_mem(pos) local mem = techage.get_mem(pos)
if not mem.cycletime then if not mem.cycletime then
@ -208,6 +210,16 @@ local function restart_timer(pos, ticks)
timer:start(ticks * cycle_time(pos)) timer:start(ticks * cycle_time(pos))
end end
local function start_delayed(pos, sec)
local timer = minetest.get_node_timer(pos)
if timer:is_started() then
timer:stop()
end
local nvm = techage.get_nvm(pos)
nvm.running = true
timer:start(sec)
end
local function node_timer(pos, elapsed) local function node_timer(pos, elapsed)
local nvm = techage.get_nvm(pos) local nvm = techage.get_nvm(pos)
if nvm.running then if nvm.running then
@ -329,7 +341,7 @@ local INFO = [[Commands: 'goto <num>', 'stop', 'on', 'off']]
techage.register_node({"techage:ta4_sequencer"}, { techage.register_node({"techage:ta4_sequencer"}, {
on_recv_message = function(pos, src, topic, payload) on_recv_message = function(pos, src, topic, payload)
local nvm = techage.get_nvm(pos) local nvm = techage.get_nvm(pos)
if (topic == "goto" or topic == "on") and not nvm.running then if (topic == "goto" or topic == "on") and not nvm.running and not delayed_start then
local mem = techage.get_mem(pos) local mem = techage.get_mem(pos)
nvm.running = true nvm.running = true
mem.idx = tonumber(payload or 1) or 1 mem.idx = tonumber(payload or 1) or 1
@ -348,7 +360,7 @@ techage.register_node({"techage:ta4_sequencer"}, {
on_beduino_receive_cmnd = function(pos, src, topic, payload) on_beduino_receive_cmnd = function(pos, src, topic, payload)
local nvm = techage.get_nvm(pos) local nvm = techage.get_nvm(pos)
if topic == 13 then if topic == 13 then
if payload[1] ~= 0 and not nvm.running then if payload[1] ~= 0 and not nvm.running and not delayed_start then
local mem = techage.get_mem(pos) local mem = techage.get_mem(pos)
nvm.running = true nvm.running = true
mem.idx = tonumber(payload or 1) or 1 mem.idx = tonumber(payload or 1) or 1
@ -364,4 +376,23 @@ techage.register_node({"techage:ta4_sequencer"}, {
end end
return 2 return 2
end, end,
on_node_load = function(pos, node)
local nvm = techage.get_nvm(pos)
if nvm.running and delayed_start then
nvm.running = false
minetest.get_node_timer(pos):stop()
minetest.after(30, function(pos)
local nvm = techage.get_nvm(pos)
nvm.running = true
minetest.get_node_timer(pos):start(1)
end, pos)
end
end,
}) })
core.register_on_mods_loaded(function()
delayed_start = true
minetest.after(30, function()
delayed_start = false
end)
end)

View File

@ -680,7 +680,7 @@ Der Tür Controller dient zur Ansteuerung der TA3 Tür/Tor Blöcke. Beim Tür Co
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. 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. Über die Taste "Austauschen" 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.
@ -694,6 +694,8 @@ Mit `$send_cmnd(node_number, "get", 2)` wird der Name des gesetzten Blocks zurü
Die Slot-Nummer des Inventars (1 .. 16) muss in allen drei Fällen als payload übergeben werden. Die Slot-Nummer des Inventars (1 .. 16) muss in allen drei Fällen als payload übergeben werden.
Mit `$send_cmnd(node_number, "reset")` wird der Tür Controller zurückgesetzt.
Damit lassen sich auch ausfahrbare Treppen und ähnliches simulieren. Damit lassen sich auch ausfahrbare Treppen und ähnliches simulieren.
[ta3_doorcontroller|image] [ta3_doorcontroller|image]

View File

@ -677,7 +677,7 @@ 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 "Exchange" button. If an `on` /`off` command is sent to the Door Controller II, it removes or sets the blocks as well.
With `$send_cmnd(node_number, "exchange", 2)` individual blocks can be set, removed or replaced by other blocks from the inventory. With `$send_cmnd(node_number, "exchange", 2)` individual blocks can be set, removed or replaced by other blocks from the inventory.
@ -689,6 +689,8 @@ The name of the set block is returned with `$send_cmnd(node_number, "get", 2)`.
The slot number of the inventory (1 .. 16) must be passed as payload in all three cases. The slot number of the inventory (1 .. 16) must be passed as payload in all three cases.
With `$send_cmnd(node_number, "reset")` the door controller is reset.
This can also be used to simulate extendable stairs and the like. This can also be used to simulate extendable stairs and the like.
[ta3_doorcontroller|image] [ta3_doorcontroller|image]

View File

@ -1465,6 +1465,7 @@ As payload data, these commands may require numeric values or a string value.
| DC2 Exchange Block | 9 | 0, idx | TA3 Door Controller II (techage:ta3_doorcontroller2). Exchange a block<br>`idx` is the inventory slot number (1..n) | | DC2 Exchange Block | 9 | 0, idx | TA3 Door Controller II (techage:ta3_doorcontroller2). Exchange a block<br>`idx` is the inventory slot number (1..n) |
| DC2 Set Block | 9 | 1, idx | TA3 Door Controller II (techage:ta3_doorcontroller2). Set/add a block<br>`idx` is the inventory slot number (1..n) with the block to be set | | DC2 Set Block | 9 | 1, idx | TA3 Door Controller II (techage:ta3_doorcontroller2). Set/add a block<br>`idx` is the inventory slot number (1..n) with the block to be set |
| DC2 Dig Block | 9 | 2, idx | TA3 Door Controller II (techage:ta3_doorcontroller2). Dig/remove a block<br>`idx` is the empty inventory slot number (1..n) for the block | | DC2 Dig Block | 9 | 2, idx | TA3 Door Controller II (techage:ta3_doorcontroller2). Dig/remove a block<br>`idx` is the empty inventory slot number (1..n) for the block |
| DC2 Reset | 9 | 3 | TA3 Door Controller II (techage:ta3_doorcontroller2). Reset the door controller |
| Autocrafter | 10 | num, idx | Set the TA4 Autocrafter recipe with a recipe from a TA4 Recipe Block.<br>`num` is the TA4 Recipe Block number<br>`idx` is the number of the recipe in the TA4 Recipe Block | | Autocrafter | 10 | num, idx | Set the TA4 Autocrafter recipe with a recipe from a TA4 Recipe Block.<br>`num` is the TA4 Recipe Block number<br>`idx` is the number of the recipe in the TA4 Recipe Block |
| Autocrafter | 11 | - | Move all items from input inventory to output inventory. Returns 1 if the input inventory was emptied in the process. Otherwise return 0 | | Autocrafter | 11 | - | Move all items from input inventory to output inventory. Returns 1 if the input inventory was emptied in the process. Otherwise return 0 |
| Move Contr. 1 | 11 | 1 | TA4 Move Controller command to move the block(s) from position A to B | | Move Contr. 1 | 11 | 1 | TA4 Move Controller command to move the block(s) from position A to B |

View File

@ -33,6 +33,8 @@ examples are written in lower case letters.
### Hello World ### Hello World
The following example prints "Hello World!" to the terminal.
```basic ```basic
10 for i=1 to 10 10 for i=1 to 10
20 print "Hello World!" 20 print "Hello World!"

View File

@ -3,7 +3,7 @@
TechAge TechAge
======= =======
Copyright (C) 2020-2023 Joachim Stolberg Copyright (C) 2020-2025 Joachim Stolberg
AGPL v3 AGPL v3
See LICENSE.txt for more information See LICENSE.txt for more information
@ -17,146 +17,74 @@ local M = minetest.get_meta
local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local S = techage.S local S = techage.S
local MP = minetest.get_modpath("techage")
local mark = dofile(MP .. "/basis/mark_lib.lua")
local logic = techage.logic local logic = techage.logic
local fly = techage.flylib local fly = techage.flylib
local NUMSLOTS = 16 local NUMSLOTS = 16
local MarkedNodes = {} -- t[player] = {{entity, pos},...}
local CurrentPos -- to mark punched entities
-------------------------------------------------------------------------- --------------------------------------------------------------------------
-- helper functions -- helper functions
-------------------------------------------------------------------------- --------------------------------------------------------------------------
local function count_nodes(tbl, name) local function get_positions(nvm)
if tbl[name] then local lpos = {}
tbl[name] = tbl[name] + 1 for idx,cfg in ipairs(nvm.config) do
else lpos[idx] = cfg.pos
tbl[name] = 1
end end
end return lpos
local function take_node(tbl, name)
if tbl[name] and tbl[name] > 0 then
tbl[name] = tbl[name] - 1
return true
end
end
local function next_node(tbl)
return function(tbl)
local name, cnt = next(tbl)
if cnt and cnt > 0 then
cnt = cnt - 1
if cnt == 0 then
tbl[name] = nil
else
tbl[name] = cnt
end
return name
end
end, tbl
end
local function get_new_nodename(item)
local name = item:get_name()
if name == "" then
return "air"
end
return name
end end
local function get_node_name(nvm, slot) local function get_node_name(nvm, slot)
nvm.pos_list = nvm.pos_list or {} nvm.config = nvm.config or {}
local pos = nvm.pos_list[slot] local cfg = nvm.config[slot]
if pos then if cfg then
return techage.get_node_lvm(pos).name return techage.get_node_lvm(cfg.pos).name
end end
return "unknown" return "unknown"
end end
local function is_simple_node(name) local function is_simple_node(pos, name)
local ndef = minetest.registered_nodes[name] if not minecart.is_rail(pos, name) then
return name ~= "air" and techage.can_dig_node(name, ndef) local ndef = minetest.registered_nodes[name]
return techage.can_dig_node(name, ndef) or minecart.is_cart(name)
end
return false
end end
-------------------------------------------------------------------------- -- Slot Configuration {
-- Marker -- pos, -- pos from the node in the inventory
-------------------------------------------------------------------------- -- param2, -- param2 from the node in the inventory
local function unmark_position(name, pos) -- state, -- false = block is dug/slot is filled, true = block is set/slot is empty
pos = vector.round(pos) -- }
for idx,item in ipairs(MarkedNodes[name] or {}) do local function gen_config(pos, pos_list)
if vector.equals(pos, item.pos) then local nvm = techage.get_nvm(pos)
item.entity:remove() nvm.config = {}
table.remove(MarkedNodes[name], idx) for idx,pos in ipairs(pos_list) do
CurrentPos = pos local node = techage.get_node_lvm(pos)
return nvm.config[idx] = {pos = pos, param2 = node.param2, state = true}
end
end end
end end
local function unmark_all(name) local function gen_config_initial(pos)
for _,item in ipairs(MarkedNodes[name] or {}) do local inv = M(pos):get_inventory()
item.entity:remove() local item_list = inv:get_list("main")
local nvm = techage.get_nvm(pos)
nvm.config = {}
nvm.pos_list = nvm.pos_list or {}
nvm.param2_list = nvm.param2_list or {}
local len = #nvm.pos_list
for idx = 1, len do
-- The status is not yet known. It is assumed that the block is set (status = true)
-- if the inventory is empty.
local item = item_list[idx]
local state = (item and item:get_count() > 0) == false
nvm.config[idx] = {pos = nvm.pos_list[idx], param2 = nvm.param2_list[idx], state = state}
end end
MarkedNodes[name] = nil nvm.pos_list = nil
nvm.param2_list = nil
end 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: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 lst = {}
for _,item in ipairs(MarkedNodes[name] or {}) do
table.insert(lst, item.pos)
end
return lst
end
minetest.register_entity(":techage: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",
},
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,
})
-------------------------------------------------------------------------- --------------------------------------------------------------------------
-- formspec -- formspec
-------------------------------------------------------------------------- --------------------------------------------------------------------------
@ -165,191 +93,90 @@ local function formspec1(nvm, meta)
local play_sound = dump(nvm.play_sound or false) local play_sound = dump(nvm.play_sound or false)
return "size[8,7]".. 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.2;3,1;record;"..S("Record").."]".. "button[0.7,0.0;3,1;record;"..S("Record").."]"..
"button[4.3,0.2;3,1;ready;"..S("Done").."]".. "button[4.3,0.0;3,1;ready;"..S("Done").."]"..
"button[0.7,1.2;3,1;reset;"..S("Reset").."]".. "button[0.7,0.9;3,1;reset;"..S("Reset").."]"..
"button[4.3,1.2;3,1;exchange;"..S("Exchange").."]".. "button[4.3,0.9;3,1;exchange;"..S("Exchange").."]"..
"checkbox[4.3,2.1;play_sound;"..S("with door sound")..";"..play_sound.."]".. "button[0.7,1.8;3,1;show;"..S("Show positions").."]"..
"label[0.5,2.3;"..status.."]".. "checkbox[4.3,1.8;play_sound;"..S("with door sound")..";"..play_sound.."]"..
"label[0.5,2.8;"..status.."]"..
"list[current_player;main;0,3.3;8,4;]" "list[current_player;main;0,3.3;8,4;]"
end end
local function formspec2() local function formspec2(nvm)
local lbls = {}
for idx,item in ipairs(nvm.config or {}) do
local x = ((idx-1) % 8) + 0.3
local y = math.floor((idx-1) / 8) * 2.4
if item.state then
lbls[idx] = "label[" .. x .."," .. y .. ";" .. idx .. "]"
else
lbls[idx] = "label[" .. x .."," .. y .. ";" .. idx .. " *]"
end
end
return "size[8,7]".. return "size[8,7]"..
"tabheader[0,0;tab;"..S("Ctrl,Inv")..";2;;true]".. "tabheader[0,0;tab;"..S("Ctrl,Inv")..";2;;true]"..
"label[0.3,0.0;1]".. table.concat(lbls, "")..
"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[context;main;0,0.5;8,2;]"..
"list[current_player;main;0,3.3;8,4;]".. "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
local function play_sound(pos)
minetest.sound_play("techage_button", {
pos = pos,
gain = 1,
max_hear_distance = 15})
end
--------------------------------------------------------------------------
-- Configuration
--------------------------------------------------------------------------
-- Store the current state of inventory and placed nodes
local function store_config(pos, nvm)
local meta = M(pos)
local inv = meta:get_inventory()
local item_list = inv:get_list("main")
local nodes = {exp_nodes = {}, inv_nodes = {}}
nvm.pos_list = nvm.pos_list or {}
nvm.param2_list = nvm.param2_list or {}
for idx = 1, NUMSLOTS do
local pos = nvm.pos_list[idx]
if pos then
local param2 = nvm.param2_list[idx] or 0
local item = item_list[idx]
if item and item:get_count() > 0 then
nodes.inv_nodes[idx] = {name = item:get_name(), param2 = param2}
end
local node = techage.get_node_lvm(pos)
if is_simple_node(node.name) or node.name == "air" then
nodes.exp_nodes[idx] = techage.get_node_lvm(pos)
end
end
end
meta:set_string("stored_config", minetest.serialize(nodes))
end
-- Generate a table of currently available inventory and placed nodes
local function available_nodes(pos, nvm, item_list)
local nodes = {}
nvm.pos_list = nvm.pos_list or {}
for idx = 1, NUMSLOTS do
local item = item_list[idx]
if item and item:get_count() > 0 then
count_nodes(nodes, item:get_name())
end
local pos = nvm.pos_list[idx]
if pos then
local node = techage.get_node_lvm(pos)
if is_simple_node(node.name) then
count_nodes(nodes, node.name)
end
end
end
return nodes
end
local function restore_config(pos, nvm)
local meta = M(pos)
local inv = meta:get_inventory()
local item_list = inv:get_list("main")
local stock = available_nodes(pos, nvm, item_list)
local nodes = minetest.deserialize(meta:get_string("stored_config")) or {}
nvm.pos_list = nvm.pos_list or {}
inv:set_list("main", {})
item_list = inv:get_list("main")
for idx, node in pairs(nodes.inv_nodes or {}) do
if take_node(stock, node.name) then
item_list[idx] = ItemStack(node.name)
end
end
inv:set_list("main", item_list)
for idx, node in pairs(nodes.exp_nodes or {}) do
local pos = nvm.pos_list[idx]
if take_node(stock, node.name) then
local param2 = nvm.param2_list[idx] or 0
fly.exchange_node(pos, node.name, param2)
nvm.expected_nodenames[idx] = node.name
else
fly.remove_node(pos)
nvm.expected_nodenames[idx] = "air"
end
end
for name in next_node(stock) do
inv:add_item("main", ItemStack(name))
end
return true
end
-------------------------------------------------------------------------- --------------------------------------------------------------------------
-- Exchange nodes -- Exchange nodes
-------------------------------------------------------------------------- --------------------------------------------------------------------------
local function exchange_node(pos, item, param2) local function exchange_node(cfg, item)
local node = minetest.get_node_or_nil(pos) local node = techage.get_node_lvm(cfg.pos)
if node and (is_simple_node(node.name) or node.name == "air") then if is_simple_node(cfg.pos, node.name) then
if item and is_simple_node(item:get_name()) then local name = item:get_count() > 0 and item:get_name() or "air"
fly.exchange_node(pos, item:get_name(), param2) fly.exchange_node(cfg.pos, name, cfg.param2)
cfg.param2 = node.param2
cfg.state = not cfg.state
if node.name ~= "air" then
return ItemStack(node.name)
else else
fly.remove_node(pos) return ItemStack()
end
if not techage.is_air_like(node.name) then
return ItemStack(node.name), node.param2
else
return ItemStack(), param2
end end
end end
return item, param2 return item
end
local function expected_node(pos, nvm, idx, force, new_nodename)
local expected_name = force and nvm.expected_nodenames[idx] or nil
if expected_name then
local node = techage.get_node_lvm(pos)
if expected_name == node.name then
nvm.expected_nodenames[idx] = new_nodename
return true
else
return false
end
end
nvm.expected_nodenames[idx] = new_nodename
return true
end end
local function exchange_nodes(pos, nvm, slot, force) local function exchange_nodes(pos, nvm, slot, force)
local meta = M(pos) local inv = M(pos):get_inventory()
local inv = meta:get_inventory()
local item_list = inv:get_list("main") local item_list = inv:get_list("main")
local res = false local res = false
nvm.pos_list = nvm.pos_list or {} nvm.config = nvm.config or {}
nvm.param2_list = nvm.param2_list or {} local len = #nvm.config
nvm.expected_nodenames = nvm.expected_nodenames or {}
for idx = (slot or 1), (slot or NUMSLOTS) do for idx = (slot or 1), (slot or len) do
local pos = nvm.pos_list[idx] local cfg = nvm.config[idx]
local item = item_list[idx] local item = item_list[idx]
if pos then if (force == nil)
if (force == nil) or (force == "exch")
or (force == "exch") or (force == "dig" and item:get_count() == 0)
or (force == "dig" and item:get_count() == 0) or (force == "set" and item:get_count() > 0) then
or (force == "set" and item:get_count() > 0) then item_list[idx] = exchange_node(cfg, item)
if expected_node(pos, nvm, idx, force, get_new_nodename(item)) then res = true
item_list[idx], nvm.param2_list[idx] = exchange_node(pos, item, nvm.param2_list[idx])
end
res = true
end
end end
end end
inv:set_list("main", item_list) inv:set_list("main", item_list)
return res return res
end end
local function reset_config(pos, nvm)
local inv = M(pos):get_inventory()
local item_list = inv:get_list("main")
for idx, cfg in ipairs(nvm.config or {}) do
local item = item_list[idx]
if not cfg.state then
item_list[idx] = exchange_node(cfg, item)
end
end
inv:set_list("main", item_list)
end
local function show_nodes(pos) local function show_nodes(pos)
local nvm = techage.get_nvm(pos) local nvm = techage.get_nvm(pos)
if not nvm.is_on then if not nvm.is_on then
@ -417,45 +244,48 @@ minetest.register_node("techage:ta3_doorcontroller2", {
local nvm = techage.get_nvm(pos) local nvm = techage.get_nvm(pos)
if fields.tab == "2" then if fields.tab == "2" then
meta:set_string("formspec", formspec2(meta)) meta:set_string("formspec", formspec2(nvm))
return return
elseif fields.tab == "1" then elseif fields.tab == "1" then
meta:set_string("formspec", formspec1(nvm, meta)) meta:set_string("formspec", formspec1(nvm, meta))
return return
elseif fields.record then elseif fields.record then
local inv = meta:get_inventory() nvm.recording = true
nvm.pos_list = {}
meta:set_string("status", S("Recording...")) meta:set_string("status", S("Recording..."))
local name = player:get_player_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")) minetest.chat_send_player(name, S("Click on all the blocks that are part of the door/gate"))
nvm.expected_nodenames = {} mark.unmark_all(name)
MarkedNodes[name] = {} mark.start(name, NUMSLOTS)
meta:set_string("stored_config", "") meta:set_string("stored_config", "")
meta:set_string("formspec", formspec1(nvm, meta)) meta:set_string("formspec", formspec1(nvm, meta))
elseif fields.ready then elseif fields.ready and nvm.recording then
nvm.recording = false
local name = player:get_player_name() local name = player:get_player_name()
local pos_list = get_poslist(name) local pos_list = mark.get_poslist(name)
gen_config(pos, pos_list)
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 mark.unmark_all(name)
nvm.expected_nodenames = {} mark.stop(name)
unmark_all(name)
meta:set_string("stored_config", "") meta:set_string("stored_config", "")
meta:set_string("formspec", formspec1(nvm, meta)) meta:set_string("formspec", formspec1(nvm, meta))
elseif fields.exchange then elseif fields.exchange then
if exch_nodes(pos) then if exch_nodes(pos) then
store_config(pos, nvm)
meta:set_string("status", S("Blocks exchanged")) meta:set_string("status", S("Blocks exchanged"))
meta:set_string("formspec", formspec1(nvm, meta)) meta:set_string("formspec", formspec1(nvm, meta))
local name = player:get_player_name() local name = player:get_player_name()
MarkedNodes[name] = nil mark.stop(name)
end end
elseif fields.show then
local name = player:get_player_name()
local lpos = get_positions(nvm)
mark.mark_positions(name, lpos, 300)
elseif fields.reset then elseif fields.reset then
restore_config(pos, nvm) reset_config(pos, nvm)
meta:set_string("status", S("Blocks reset")) meta:set_string("status", S("Blocks reset"))
meta:set_string("formspec", formspec1(nvm, meta)) meta:set_string("formspec", formspec1(nvm, meta))
local name = player:get_player_name() local name = player:get_player_name()
MarkedNodes[name] = nil mark.stop(name)
elseif fields.play_sound then elseif fields.play_sound then
nvm.play_sound = fields.play_sound == "true" nvm.play_sound = fields.play_sound == "true"
meta:set_string("formspec", formspec1(nvm, meta)) meta:set_string("formspec", formspec1(nvm, meta))
@ -478,10 +308,16 @@ 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 return 1
return 1 end,
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
if not clicker or minetest.is_protected(pos, clicker:get_player_name()) then
return
end end
return 0 local meta = M(pos)
local nvm = techage.get_nvm(pos)
meta:set_string("formspec", formspec1(nvm, meta))
end, end,
can_dig = function(pos, player) can_dig = function(pos, player)
@ -495,7 +331,7 @@ minetest.register_node("techage:ta3_doorcontroller2", {
after_dig_node = function(pos, oldnode, oldmetadata, digger) after_dig_node = function(pos, oldnode, oldmetadata, digger)
local name = digger:get_player_name() local name = digger:get_player_name()
unmark_all(name) mark.unmark_all(name)
techage.remove_node(pos, oldnode, oldmetadata) techage.remove_node(pos, oldnode, oldmetadata)
end, end,
@ -525,7 +361,7 @@ techage.register_node({"techage:ta3_doorcontroller2"}, {
return get_node_name(nvm, tonumber(payload)) return get_node_name(nvm, tonumber(payload))
elseif topic == "reset" then elseif topic == "reset" then
local nvm = techage.get_nvm(pos) local nvm = techage.get_nvm(pos)
return restore_config(pos, nvm) return reset_config(pos, nvm)
end end
return false return false
end, end,
@ -545,7 +381,7 @@ techage.register_node({"techage:ta3_doorcontroller2"}, {
return exchange_nodes(pos, nvm, payload[2] or 1, "dig") and 0 or 3 return exchange_nodes(pos, nvm, payload[2] or 1, "dig") and 0 or 3
elseif topic == 9 and payload[1] == 3 then -- reset elseif topic == 9 and payload[1] == 3 then -- reset
local nvm = techage.get_nvm(pos) local nvm = techage.get_nvm(pos)
return restore_config(pos, nvm) and 0 or 3 return reset_config(pos, nvm) and 0 or 3
end end
return 2 return 2
end, end,
@ -557,23 +393,9 @@ techage.register_node({"techage:ta3_doorcontroller2"}, {
return 2, "" return 2, ""
end, end,
on_node_load = function(pos) on_node_load = function(pos)
local meta = M(pos)
local nvm = techage.get_nvm(pos) local nvm = techage.get_nvm(pos)
meta:set_string("status", "") if nvm.config == nil then
meta:set_string("formspec", formspec1(nvm, meta)) gen_config_initial(pos)
local pos_list = minetest.deserialize(meta:get_string("pos_list"))
if pos_list then
nvm.pos_list = pos_list
meta:set_string("pos_list", "")
local inv = meta:get_inventory()
if inv:is_empty("main") then
nvm.is_on = true
end
end
local param2_list = minetest.deserialize(meta:get_string("param2_list"))
if param2_list then
nvm.param2_list = param2_list
meta:set_string("param2_list", "")
end end
end, end,
}) })
@ -584,20 +406,6 @@ minetest.register_craft({
recipe = {"techage:ta3_doorcontroller"}, recipe = {"techage:ta3_doorcontroller"},
}) })
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
if not minetest.is_protected(pointed_thing.under, name) then
mark_position(name, pointed_thing.under)
end
end
end)
local Doors = { local Doors = {
"doors:door_steel", "doors:door_steel",
"doors:prison_door", "doors:prison_door",

View File

@ -258,6 +258,7 @@ techage.register_node({"techage:ta5_flycontroller"}, {
end, end,
on_node_load = function(pos, node) on_node_load = function(pos, node)
M(pos):set_string("status", "") M(pos):set_string("status", "")
techage.get_nvm(pos).running = false
end, end,
}) })

View File

@ -63,26 +63,29 @@ local function formspec(nvm, meta)
local path = minetest.formspec_escape(meta:contains("path") and meta:get_string("path") or "0,3,0") local path = minetest.formspec_escape(meta:contains("path") and meta:get_string("path") or "0,3,0")
local buttons local buttons
if meta:get_string("opmode") == "move xyz" then if meta:get_string("opmode") == "move xyz" then
buttons = "field[0.4,2.5;3.8,1;path;" .. S("Move distance") .. ";" .. path .. "]" .. buttons = "field[0.4,2.3;3.8,1;path;" .. S("Move distance") .. ";" .. path .. "]" ..
"button_exit[4.1,2.2;3.8,1;move2;" .. S("Move") .. "]" .. "button_exit[4.1,2.0;3.8,1;move2;" .. S("Move") .. "]" ..
"button_exit[0.1,3.3;3.8,1;reset;" .. S("Reset") .. "]" "button_exit[0.1,3.0;3.8,1;reset;" .. S("Reset") .. "]" ..
"button[4.1,3.0;3.8,1;show;" .. S("Show positions") .. "]"
else else
buttons = "field[0.4,2.5;3.8,1;path;" .. S("Move distance (A to B)") .. ";" .. path .. "]" .. buttons = "field[0.4,2.3;3.8,1;path;" .. S("Move distance (A to B)") .. ";" .. path .. "]" ..
"button_exit[0.1,3.3;3.8,1;moveAB;" .. S("Move A-B") .. "]" .. "button_exit[0.1,3.0;3.8,1;moveAB;" .. S("Move A-B") .. "]" ..
"button_exit[4.1,3.3;3.8,1;moveBA;" .. S("Move B-A") .. "]" .. "button_exit[4.1,3.0;3.8,1;moveBA;" .. S("Move B-A") .. "]" ..
"button[4.1,2.2;3.8,1;store;" .. S("Store") .. "]" "button[4.1,2.0;3.8,1;store;" .. S("Store") .. "]" ..
"button[0.1,4.0;3.8,1;show;" .. S("Show positions") .. "]" ..
"button_exit[4.1,4.0;3.8,1;reset;" .. S("Reset") .. "]"
end end
return "size[8,5]" .. return "size[8,5.5]" ..
default.gui_bg .. default.gui_bg ..
default.gui_bg_img .. default.gui_bg_img ..
default.gui_slots .. default.gui_slots ..
"box[0,-0.1;7.2,0.5;#c6e8ff]" .. "box[0,-0.1;7.2,0.5;#c6e8ff]" ..
"label[0.2,-0.1;" .. minetest.colorize( "#000000", S("TA4 Move Controller")) .. "]" .. "label[0.2,-0.1;" .. minetest.colorize( "#000000", S("TA4 Move Controller")) .. "]" ..
techage.wrench_image(7.4, -0.05) .. techage.wrench_image(7.4, -0.05) ..
"button[0.1,0.8;3.8,1;record;" .. S("Record") .. "]" .. "button[0.1,0.7;3.8,1;record;" .. S("Record") .. "]" ..
"button[4.1,0.8;3.8,1;done;" .. S("Done") .. "]" .. "button[4.1,0.7;3.8,1;done;" .. S("Done") .. "]" ..
buttons .. buttons ..
"label[0.3,4.3;" .. status .. "]" "label[0.3,5.0;" .. status .. "]"
end end
minetest.register_node("techage:ta4_movecontroller", { minetest.register_node("techage:ta4_movecontroller", {
@ -175,6 +178,9 @@ minetest.register_node("techage:ta4_movecontroller", {
end end
elseif fields.reset then elseif fields.reset then
fly.reset_move(pos) fly.reset_move(pos)
elseif fields.show then
local name = player:get_player_name()
mark.mark_positions(name, nvm.lpos1, 300)
end end
end, end,
@ -263,6 +269,7 @@ techage.register_node({"techage:ta4_movecontroller"}, {
on_node_load = function(pos, node) on_node_load = function(pos, node)
M(pos):set_string("teleport_mode", "") -- delete not working (legacy) op mode M(pos):set_string("teleport_mode", "") -- delete not working (legacy) op mode
M(pos):set_string("status", "") M(pos):set_string("status", "")
techage.get_nvm(pos).running = false
end, end,
}) })