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

View File

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

View File

@ -593,7 +593,7 @@ return {
"\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"..
" Über die Taste \"Austauschen\" kann die Funktion des Controllers von Hand getestet werden.\n"..
"\n"..
"Wird ein 'on' / 'off' Kommando an den Tür Controller II gesendet\\, entfernt bzw. setzt er die Blöcke ebenfalls.\n"..
"\n"..
@ -607,6 +607,8 @@ return {
"\n"..
"Die Slot-Nummer des Inventars (1 .. 16) muss in allen drei Fällen als payload übergeben werden.\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"..
"\n"..
"\n"..

View File

@ -592,7 +592,7 @@ return {
"\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"..
"With '$send_cmnd(node_number\\, \"exchange\"\\, 2)' individual blocks can be set\\, removed or replaced by other blocks from the inventory. \n"..
"\n"..
@ -604,6 +604,8 @@ return {
"\n"..
"The slot number of the inventory (1 .. 16) must be passed as payload in all three cases.\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"..
"\n"..
"\n"..

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -59,6 +59,8 @@ local WRENCH_MENU = {
},
}
local delayed_start = false
local function cycle_time(pos)
local mem = techage.get_mem(pos)
if not mem.cycletime then
@ -208,6 +210,16 @@ local function restart_timer(pos, ticks)
timer:start(ticks * cycle_time(pos))
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 nvm = techage.get_nvm(pos)
if nvm.running then
@ -329,7 +341,7 @@ local INFO = [[Commands: 'goto <num>', 'stop', 'on', 'off']]
techage.register_node({"techage:ta4_sequencer"}, {
on_recv_message = function(pos, src, topic, payload)
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)
nvm.running = true
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)
local nvm = techage.get_nvm(pos)
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)
nvm.running = true
mem.idx = tonumber(payload or 1) or 1
@ -364,4 +376,23 @@ techage.register_node({"techage:ta4_sequencer"}, {
end
return 2
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.
Ü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.
@ -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.
Mit `$send_cmnd(node_number, "reset")` wird der Tür Controller zurückgesetzt.
Damit lassen sich auch ausfahrbare Treppen und ähnliches simulieren.
[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
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.
@ -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.
With `$send_cmnd(node_number, "reset")` the door controller is reset.
This can also be used to simulate extendable stairs and the like.
[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 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 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 | 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 |

View File

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

View File

@ -3,7 +3,7 @@
TechAge
=======
Copyright (C) 2020-2023 Joachim Stolberg
Copyright (C) 2020-2025 Joachim Stolberg
AGPL v3
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 S = techage.S
local MP = minetest.get_modpath("techage")
local mark = dofile(MP .. "/basis/mark_lib.lua")
local logic = techage.logic
local fly = techage.flylib
local NUMSLOTS = 16
local MarkedNodes = {} -- t[player] = {{entity, pos},...}
local CurrentPos -- to mark punched entities
--------------------------------------------------------------------------
-- helper functions
--------------------------------------------------------------------------
local function count_nodes(tbl, name)
if tbl[name] then
tbl[name] = tbl[name] + 1
else
tbl[name] = 1
local function get_positions(nvm)
local lpos = {}
for idx,cfg in ipairs(nvm.config) do
lpos[idx] = cfg.pos
end
end
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
return lpos
end
local function get_node_name(nvm, slot)
nvm.pos_list = nvm.pos_list or {}
local pos = nvm.pos_list[slot]
if pos then
return techage.get_node_lvm(pos).name
nvm.config = nvm.config or {}
local cfg = nvm.config[slot]
if cfg then
return techage.get_node_lvm(cfg.pos).name
end
return "unknown"
end
local function is_simple_node(name)
local ndef = minetest.registered_nodes[name]
return name ~= "air" and techage.can_dig_node(name, ndef)
local function is_simple_node(pos, name)
if not minecart.is_rail(pos, name) then
local ndef = minetest.registered_nodes[name]
return techage.can_dig_node(name, ndef) or minecart.is_cart(name)
end
return false
end
--------------------------------------------------------------------------
-- Marker
--------------------------------------------------------------------------
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
-- Slot Configuration {
-- pos, -- pos from the node in the inventory
-- param2, -- param2 from the node in the inventory
-- state, -- false = block is dug/slot is filled, true = block is set/slot is empty
-- }
local function gen_config(pos, pos_list)
local nvm = techage.get_nvm(pos)
nvm.config = {}
for idx,pos in ipairs(pos_list) do
local node = techage.get_node_lvm(pos)
nvm.config[idx] = {pos = pos, param2 = node.param2, state = true}
end
end
local function unmark_all(name)
for _,item in ipairs(MarkedNodes[name] or {}) do
item.entity:remove()
local function gen_config_initial(pos)
local inv = M(pos):get_inventory()
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
MarkedNodes[name] = nil
nvm.pos_list = nil
nvm.param2_list = 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: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
--------------------------------------------------------------------------
@ -165,191 +93,90 @@ local function formspec1(nvm, meta)
local play_sound = dump(nvm.play_sound or false)
return "size[8,7]"..
"tabheader[0,0;tab;"..S("Ctrl,Inv")..";1;;true]"..
"button[0.7,0.2;3,1;record;"..S("Record").."]"..
"button[4.3,0.2;3,1;ready;"..S("Done").."]"..
"button[0.7,1.2;3,1;reset;"..S("Reset").."]"..
"button[4.3,1.2;3,1;exchange;"..S("Exchange").."]"..
"checkbox[4.3,2.1;play_sound;"..S("with door sound")..";"..play_sound.."]"..
"label[0.5,2.3;"..status.."]"..
"button[0.7,0.0;3,1;record;"..S("Record").."]"..
"button[4.3,0.0;3,1;ready;"..S("Done").."]"..
"button[0.7,0.9;3,1;reset;"..S("Reset").."]"..
"button[4.3,0.9;3,1;exchange;"..S("Exchange").."]"..
"button[0.7,1.8;3,1;show;"..S("Show positions").."]"..
"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;]"
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]"..
"tabheader[0,0;tab;"..S("Ctrl,Inv")..";2;;true]"..
"label[0.3,0.0;1]"..
"label[7.3,0.0;8]"..
"label[0.3,2.4;9]"..
"label[7.3,2.4;16]"..
table.concat(lbls, "")..
"list[context;main;0,0.5;8,2;]"..
"list[current_player;main;0,3.3;8,4;]"..
"listring[context;main]"..
"listring[current_player;main]"
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
--------------------------------------------------------------------------
local function exchange_node(pos, item, param2)
local node = minetest.get_node_or_nil(pos)
if node and (is_simple_node(node.name) or node.name == "air") then
if item and is_simple_node(item:get_name()) then
fly.exchange_node(pos, item:get_name(), param2)
local function exchange_node(cfg, item)
local node = techage.get_node_lvm(cfg.pos)
if is_simple_node(cfg.pos, node.name) then
local name = item:get_count() > 0 and item:get_name() or "air"
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
fly.remove_node(pos)
end
if not techage.is_air_like(node.name) then
return ItemStack(node.name), node.param2
else
return ItemStack(), param2
return ItemStack()
end
end
return item, param2
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
return item
end
local function exchange_nodes(pos, nvm, slot, force)
local meta = M(pos)
local inv = meta:get_inventory()
local inv = M(pos):get_inventory()
local item_list = inv:get_list("main")
local res = false
nvm.pos_list = nvm.pos_list or {}
nvm.param2_list = nvm.param2_list or {}
nvm.expected_nodenames = nvm.expected_nodenames or {}
nvm.config = nvm.config or {}
local len = #nvm.config
for idx = (slot or 1), (slot or NUMSLOTS) do
local pos = nvm.pos_list[idx]
for idx = (slot or 1), (slot or len) do
local cfg = nvm.config[idx]
local item = item_list[idx]
if pos then
if (force == nil)
or (force == "exch")
or (force == "dig" and item:get_count() == 0)
or (force == "set" and item:get_count() > 0) then
if expected_node(pos, nvm, idx, force, get_new_nodename(item)) then
item_list[idx], nvm.param2_list[idx] = exchange_node(pos, item, nvm.param2_list[idx])
end
res = true
end
if (force == nil)
or (force == "exch")
or (force == "dig" and item:get_count() == 0)
or (force == "set" and item:get_count() > 0) then
item_list[idx] = exchange_node(cfg, item)
res = true
end
end
inv:set_list("main", item_list)
return res
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 nvm = techage.get_nvm(pos)
if not nvm.is_on then
@ -417,45 +244,48 @@ minetest.register_node("techage:ta3_doorcontroller2", {
local nvm = techage.get_nvm(pos)
if fields.tab == "2" then
meta:set_string("formspec", formspec2(meta))
meta:set_string("formspec", formspec2(nvm))
return
elseif fields.tab == "1" then
meta:set_string("formspec", formspec1(nvm, meta))
return
elseif fields.record then
local inv = meta:get_inventory()
nvm.pos_list = {}
nvm.recording = true
meta:set_string("status", S("Recording..."))
local name = player:get_player_name()
minetest.chat_send_player(name, S("Click on all the blocks that are part of the door/gate"))
nvm.expected_nodenames = {}
MarkedNodes[name] = {}
mark.unmark_all(name)
mark.start(name, NUMSLOTS)
meta:set_string("stored_config", "")
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 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.")
meta:set_string("status", text)
nvm.pos_list = pos_list
nvm.expected_nodenames = {}
unmark_all(name)
mark.unmark_all(name)
mark.stop(name)
meta:set_string("stored_config", "")
meta:set_string("formspec", formspec1(nvm, meta))
elseif fields.exchange then
if exch_nodes(pos) then
store_config(pos, nvm)
meta:set_string("status", S("Blocks exchanged"))
meta:set_string("formspec", formspec1(nvm, meta))
local name = player:get_player_name()
MarkedNodes[name] = nil
mark.stop(name)
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
restore_config(pos, nvm)
reset_config(pos, nvm)
meta:set_string("status", S("Blocks reset"))
meta:set_string("formspec", formspec1(nvm, meta))
local name = player:get_player_name()
MarkedNodes[name] = nil
mark.stop(name)
elseif fields.play_sound then
nvm.play_sound = fields.play_sound == "true"
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
return 0
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
return 0
local meta = M(pos)
local nvm = techage.get_nvm(pos)
meta:set_string("formspec", formspec1(nvm, meta))
end,
can_dig = function(pos, player)
@ -495,7 +331,7 @@ minetest.register_node("techage:ta3_doorcontroller2", {
after_dig_node = function(pos, oldnode, oldmetadata, digger)
local name = digger:get_player_name()
unmark_all(name)
mark.unmark_all(name)
techage.remove_node(pos, oldnode, oldmetadata)
end,
@ -525,7 +361,7 @@ techage.register_node({"techage:ta3_doorcontroller2"}, {
return get_node_name(nvm, tonumber(payload))
elseif topic == "reset" then
local nvm = techage.get_nvm(pos)
return restore_config(pos, nvm)
return reset_config(pos, nvm)
end
return false
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
elseif topic == 9 and payload[1] == 3 then -- reset
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
return 2
end,
@ -557,23 +393,9 @@ techage.register_node({"techage:ta3_doorcontroller2"}, {
return 2, ""
end,
on_node_load = function(pos)
local meta = M(pos)
local nvm = techage.get_nvm(pos)
meta:set_string("status", "")
meta:set_string("formspec", formspec1(nvm, meta))
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", "")
if nvm.config == nil then
gen_config_initial(pos)
end
end,
})
@ -584,20 +406,6 @@ minetest.register_craft({
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 = {
"doors:door_steel",
"doors:prison_door",

View File

@ -258,6 +258,7 @@ techage.register_node({"techage:ta5_flycontroller"}, {
end,
on_node_load = function(pos, node)
M(pos):set_string("status", "")
techage.get_nvm(pos).running = false
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 buttons
if meta:get_string("opmode") == "move xyz" then
buttons = "field[0.4,2.5;3.8,1;path;" .. S("Move distance") .. ";" .. path .. "]" ..
"button_exit[4.1,2.2;3.8,1;move2;" .. S("Move") .. "]" ..
"button_exit[0.1,3.3;3.8,1;reset;" .. S("Reset") .. "]"
buttons = "field[0.4,2.3;3.8,1;path;" .. S("Move distance") .. ";" .. path .. "]" ..
"button_exit[4.1,2.0;3.8,1;move2;" .. S("Move") .. "]" ..
"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
buttons = "field[0.4,2.5;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[4.1,3.3;3.8,1;moveBA;" .. S("Move B-A") .. "]" ..
"button[4.1,2.2;3.8,1;store;" .. S("Store") .. "]"
buttons = "field[0.4,2.3;3.8,1;path;" .. S("Move distance (A to B)") .. ";" .. path .. "]" ..
"button_exit[0.1,3.0;3.8,1;moveAB;" .. S("Move A-B") .. "]" ..
"button_exit[4.1,3.0;3.8,1;moveBA;" .. S("Move B-A") .. "]" ..
"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
return "size[8,5]" ..
return "size[8,5.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;done;" .. S("Done") .. "]" ..
"button[0.1,0.7;3.8,1;record;" .. S("Record") .. "]" ..
"button[4.1,0.7;3.8,1;done;" .. S("Done") .. "]" ..
buttons ..
"label[0.3,4.3;" .. status .. "]"
"label[0.3,5.0;" .. status .. "]"
end
minetest.register_node("techage:ta4_movecontroller", {
@ -175,6 +178,9 @@ minetest.register_node("techage:ta4_movecontroller", {
end
elseif fields.reset then
fly.reset_move(pos)
elseif fields.show then
local name = player:get_player_name()
mark.mark_positions(name, nvm.lpos1, 300)
end
end,
@ -263,6 +269,7 @@ techage.register_node({"techage:ta4_movecontroller"}, {
on_node_load = function(pos, node)
M(pos):set_string("teleport_mode", "") -- delete not working (legacy) op mode
M(pos):set_string("status", "")
techage.get_nvm(pos).running = false
end,
})