mods that hopefully work for a TechAge-based pack
This commit is contained in:
1 parent
4e6b08d194
commit
c27db2a537
6234 files changed
+375578
No files matched your search
@@ -0,0 +1,871 @@
|
||||
--[[
|
||||
|
||||
Basic Terminal
|
||||
==============
|
||||
|
||||
Copyright (C) 2018-2025 Joachim Stolberg
|
||||
|
||||
AGPL v3
|
||||
See LICENSE.txt for more information
|
||||
|
||||
terminal.lua:
|
||||
|
||||
]]--
|
||||
|
||||
local M = minetest.get_meta
|
||||
local S = techage.S
|
||||
local SCREENSAVER_TIME = 60 * 5
|
||||
local CYCLE_TIME = 0.1
|
||||
|
||||
local Functions = {}
|
||||
local Actions = {}
|
||||
local Buttons = {"Edit", "Save", "Renum", "Cancel", "Run", "Stop", "Continue", "List"}
|
||||
local States = {"init", "edit", "stopped", "running", "error", "input_str", "input_num", "break"}
|
||||
local ErrorStr = {
|
||||
[1] = "Node not found",
|
||||
[2] = "Command not supported",
|
||||
[3] = "Command failed",
|
||||
[4] = "Access denied",
|
||||
[5] = "Wrong response type",
|
||||
[6] = "Wrong number of parameters",
|
||||
}
|
||||
|
||||
local InputField = "style_type[field;textcolor=#FFFFFF]" ..
|
||||
"field[1.5,0.8;7.4,0.7;input;;]" ..
|
||||
"field_close_on_enter[input;false]" ..
|
||||
"button[9,0.8;1.5,0.7;Enter;Enter]"
|
||||
|
||||
local WRENCH_MENU = {
|
||||
{
|
||||
type = "dropdown",
|
||||
choices = "all players,friends,me",
|
||||
name = "public",
|
||||
label = S("Access allowed for"),
|
||||
tooltip = S("Friends are players for whom this area is not protected"),
|
||||
default = "1",
|
||||
values = {1,2,0}
|
||||
},
|
||||
{
|
||||
type = "dropdown",
|
||||
choices = "terminal,basic",
|
||||
name = "opmode",
|
||||
label = S("Operational mode"),
|
||||
tooltip = S("Switch between TA3 terminal and BASIC computer"),
|
||||
default = "terminal",
|
||||
},
|
||||
}
|
||||
|
||||
local function register_ext_function(name, param_types, return_type, func)
|
||||
Functions[nanobasic.add_function(name, param_types, return_type)] = func
|
||||
end
|
||||
|
||||
local function register_action(states, key, func)
|
||||
for _,state in ipairs(states) do
|
||||
Actions[state] = Actions[state] or {}
|
||||
Actions[state][key] = func
|
||||
end
|
||||
end
|
||||
|
||||
local function font_size(nvm)
|
||||
nvm.trm_text_size = nvm.trm_text_size or 0
|
||||
return nvm.trm_text_size >= 0 and "+" .. nvm.trm_text_size or tostring(nvm.trm_text_size)
|
||||
end
|
||||
|
||||
local function fs_output_window(nvm, x, y, name, text)
|
||||
local font_size = font_size(nvm)
|
||||
local fs = {
|
||||
"container[", x, ",", y, "]",
|
||||
"box[0,0;12,7.5;#000000]",
|
||||
"style_type[textarea;font=mono;",
|
||||
"textcolor=#FFFFFF;border=false;",
|
||||
"font_size=", font_size, "]",
|
||||
"textarea[0,0;12,7.5;" .. name .. ";;",
|
||||
minetest.formspec_escape(text), "]",
|
||||
"container_end[]"
|
||||
}
|
||||
return table.concat(fs, "")
|
||||
end
|
||||
|
||||
local function fs_size_buttons(x, y)
|
||||
local fs = {
|
||||
"container[", x, ",", y, "]",
|
||||
"button[0.0,0;0.6,0.6;larger;+]",
|
||||
"button[0.6,0;0.6,0.6;smaller;-]",
|
||||
"container_end[]"
|
||||
}
|
||||
return table.concat(fs, "")
|
||||
end
|
||||
|
||||
local function key_rows(keys)
|
||||
local t = {}
|
||||
for i = 1, #keys do
|
||||
local x = (i - 1) * 1.5
|
||||
if keys[i] ~= "" then
|
||||
t[#t+1] = "button[" .. x .. ",0;1.5,0.7;" .. keys[i] .. ";" .. keys[i] .. "]"
|
||||
else
|
||||
t[#t+1] = "button[" .. x .. ",0;1.5,0.7;;---]"
|
||||
end
|
||||
end
|
||||
return table.concat(t, "")
|
||||
end
|
||||
|
||||
local function input_panel(nvm, x, y)
|
||||
local fs = {
|
||||
"container[", x, ",", y, "]",
|
||||
key_rows(nvm.bttns or Buttons),
|
||||
nvm.input or "",
|
||||
"container_end[]"
|
||||
}
|
||||
return table.concat(fs, "")
|
||||
end
|
||||
|
||||
local function get_action(nvm, fields)
|
||||
local keys = {"Edit", "Save", "Renum", "Cancel", "Run", "Stop", "Continue", "List", "Enter", "smaller", "larger"}
|
||||
nvm.status = nvm.status or "init"
|
||||
if nvm.status == "" then
|
||||
nvm.status = "init"
|
||||
end
|
||||
--print("get_action", nvm.status, dump(fields))
|
||||
for _,key in ipairs(keys) do
|
||||
if fields[key] and Actions[nvm.status] and Actions[nvm.status][key] then
|
||||
return Actions[nvm.status][key]
|
||||
end
|
||||
end
|
||||
return function(pos, nvm, fields)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
local function formspec(pos, text)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
local name = nvm.status == "edit" and "code" or ""
|
||||
return "formspec_version[4]" ..
|
||||
"size[12.8,10.5]" ..
|
||||
"label[0.5,0.6;Mode: " .. (nvm.status or "") .. "]" ..
|
||||
fs_size_buttons(10.6, 0.1) ..
|
||||
techage.wrench_image(11.9, 0.15) ..
|
||||
fs_output_window(nvm, 0.4, 0.8, name, text or "") ..
|
||||
input_panel(nvm, 0.4, 8.6)
|
||||
end
|
||||
|
||||
local function poweron_message(pos)
|
||||
local s = nanobasic.free_mem() or ""
|
||||
local ver = nanobasic.version()
|
||||
return "NanoBasic V" .. ver .. "\n" .. s .. "Ready.\n"
|
||||
end
|
||||
|
||||
-- Lines have line numbers at the beginning, like: "10 PRINT "Hello World"
|
||||
-- This function sorts the lines by the line numbers
|
||||
local function sort_lines(pos, nvm, code)
|
||||
local lines = {}
|
||||
local keys = {}
|
||||
for line in code:gmatch("[^\r\n]+") do
|
||||
local num = tonumber(line:match("^%s*(%d+)"))
|
||||
if num then
|
||||
if lines[num] then
|
||||
nanobasic.print(pos, "Line number " .. num .. " is already used\n")
|
||||
return
|
||||
end
|
||||
lines[num] = line
|
||||
keys[#keys + 1] = num
|
||||
else
|
||||
nanobasic.print(pos, "Line number missing in line '" .. line .. "'\n")
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
table.sort(keys)
|
||||
|
||||
local sorted = {}
|
||||
for i,num in ipairs(keys) do
|
||||
sorted[i] = lines[num]
|
||||
end
|
||||
return table.concat(sorted, "\n")
|
||||
end
|
||||
|
||||
local function replace_all_goto_refs(lines, new_nums)
|
||||
for num,line in pairs(lines) do
|
||||
local goto_num = line:match("GOTO%s+(%d+)")
|
||||
if goto_num then
|
||||
local new_num = new_nums[goto_num]
|
||||
if new_num then
|
||||
lines[num] = line:gsub("GOTO%s+%d+", "GOTO " .. new_num)
|
||||
end
|
||||
end
|
||||
goto_num = line:match("GOSUB%s+(%d+)")
|
||||
if goto_num then
|
||||
local new_num = new_nums[goto_num]
|
||||
if new_num then
|
||||
lines[num] = line:gsub("GOSUB%s+%d+", "GOSUB " .. new_num)
|
||||
end
|
||||
end
|
||||
goto_num = line:match("goto%s+(%d+)")
|
||||
if goto_num then
|
||||
local new_num = new_nums[goto_num]
|
||||
if new_num then
|
||||
lines[num] = line:gsub("goto%s+%d+", "goto " .. new_num)
|
||||
end
|
||||
end
|
||||
goto_num = line:match("gosub%s+(%d+)")
|
||||
if goto_num then
|
||||
local new_num = new_nums[goto_num]
|
||||
if new_num then
|
||||
lines[num] = line:gsub("gosub%s+%d+", "gosub " .. new_num)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function renumber_lines(pos, nvm, code)
|
||||
local lines = {}
|
||||
local new_nums = {}
|
||||
local num = 10
|
||||
for line in code:gmatch("[^\r\n]+") do
|
||||
local s = line:match("^%s*(%d+)")
|
||||
if s and tonumber(s) < num then
|
||||
lines[#lines + 1] = num .. line:sub(s:len() + 1)
|
||||
new_nums[s] = num
|
||||
num = num + 10
|
||||
else
|
||||
lines[#lines + 1] = line
|
||||
num = tonumber(s) + 10
|
||||
end
|
||||
end
|
||||
|
||||
replace_all_goto_refs(lines, new_nums)
|
||||
return table.concat(lines, "\n")
|
||||
end
|
||||
|
||||
minetest.register_node("techage:basic_terminal", {
|
||||
description = S("TA3 Terminal"),
|
||||
tiles = {-- up, down, right, left, back, front
|
||||
'techage_terminal2_top.png',
|
||||
'techage_terminal2_side.png',
|
||||
'techage_terminal2_side.png^[transformFX',
|
||||
'techage_terminal2_side.png',
|
||||
'techage_terminal2_back.png',
|
||||
"techage_terminal2_front.png",
|
||||
},
|
||||
drawtype = "nodebox",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{-12/32, -16/32, -16/32, 12/32, -14/32, 16/32},
|
||||
{-12/32, -14/32, -3/32, 12/32, 6/32, 16/32},
|
||||
{-10/32, -12/32, 14/32, 10/32, 4/32, 18/32},
|
||||
{-12/32, 4/32, -4/32, 12/32, 6/32, 16/32},
|
||||
{-12/32, -16/32, -4/32, -10/32, 6/32, 16/32},
|
||||
{ 10/32, -16/32, -4/32, 12/32, 6/32, 16/32},
|
||||
{-12/32, -14/32, -4/32, 12/32, -12/32, 16/32},
|
||||
},
|
||||
},
|
||||
selection_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{-12/32, -16/32, -4/32, 12/32, 6/32, 16/32},
|
||||
},
|
||||
},
|
||||
|
||||
after_place_node = function(pos, placer)
|
||||
local number = techage.add_node(pos, minetest.get_node(pos).name)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
local meta = M(pos)
|
||||
local text = poweron_message(pos)
|
||||
nvm.trm_ttl = 0
|
||||
nvm.status = "init"
|
||||
nvm.bttns = Buttons
|
||||
nvm.input = ""
|
||||
meta:set_int("public", 0)
|
||||
meta:set_string("formspec", formspec(pos, text))
|
||||
if placer then
|
||||
meta:set_string("owner", placer:get_player_name())
|
||||
end
|
||||
meta:set_string("infotext", S("TA3 Terminal"))
|
||||
end,
|
||||
|
||||
on_receive_fields = function(pos, formname, fields, player)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
local meta = M(pos)
|
||||
local public = meta:get_int("public")
|
||||
if public == 1 or
|
||||
public == 2 and not minetest.is_protected(pos, player:get_player_name()) or
|
||||
public == 0 and player:get_player_name() == meta:get_string("owner") then
|
||||
fields.Enter = fields.Enter or fields.key_enter_field
|
||||
local action = get_action(nvm, fields)
|
||||
local text = action(pos, nvm, fields, player)
|
||||
if text then
|
||||
meta:set_string("formspec", formspec(pos, text))
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
on_timer = function(pos, elapsed)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
if nvm.ttl and nvm.ttl > 1 then
|
||||
nvm.ttl = nvm.ttl - 1
|
||||
return true
|
||||
end
|
||||
|
||||
if nvm.status == "running" then
|
||||
local res = nanobasic.run(pos, 100)
|
||||
if res == nanobasic.NB_BUSY then
|
||||
if techage.is_activeformspec(pos) then
|
||||
local text = nanobasic.get_screen_buffer(pos)
|
||||
M(pos):set_string("formspec", formspec(pos, text))
|
||||
end
|
||||
return true
|
||||
elseif res == nanobasic.NB_ERROR then
|
||||
nvm.status = "error"
|
||||
nvm.bttns = {"Edit", "", "", "", "", "Stop", "", ""}
|
||||
nvm.input = ""
|
||||
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.ttl = nil
|
||||
local text = nanobasic.get_screen_buffer(pos)
|
||||
M(pos):set_string("formspec", formspec(pos, text))
|
||||
elseif res == nanobasic.NB_BREAK then
|
||||
local lineno = nanobasic.pop_num(pos);
|
||||
nanobasic.print(pos, string.format("Break in line %d\n", lineno));
|
||||
nvm.status = "break"
|
||||
nvm.bttns = {"", "", "", "", "", "Stop", "Continue", "List"}
|
||||
nvm.input = InputField
|
||||
nvm.ttl = nil
|
||||
local text = nanobasic.get_screen_buffer(pos)
|
||||
M(pos):set_string("formspec", formspec(pos, text))
|
||||
elseif res >= nanobasic.NB_XFUNC then
|
||||
return Functions[res] and Functions[res](pos, nvm) or false
|
||||
else
|
||||
print("res = ", res)
|
||||
return false
|
||||
end
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
on_rightclick = function(pos, node, clicker)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
local text
|
||||
nvm.trm_ttl = minetest.get_gametime() + SCREENSAVER_TIME
|
||||
if nvm.status == "edit" then
|
||||
text = M(pos):get_string("code")
|
||||
else
|
||||
text = nanobasic.get_screen_buffer(pos) or ""
|
||||
end
|
||||
techage.set_activeformspec(pos, clicker)
|
||||
M(pos):set_string("formspec", formspec(pos, text))
|
||||
end,
|
||||
|
||||
ta_after_formspec = function(pos, fields, playername)
|
||||
if fields.save then
|
||||
if M(pos):get_string("opmode") == "terminal" then
|
||||
local node = techage.get_node_lvm(pos)
|
||||
node.name = "techage:terminal2"
|
||||
minetest.swap_node(pos, node)
|
||||
local ndef = minetest.registered_nodes["techage:terminal2"]
|
||||
ndef.after_place_node(pos)
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
nanobasic.destroy(pos)
|
||||
end,
|
||||
|
||||
ta3_formspec = WRENCH_MENU,
|
||||
drop = "techage:terminal2",
|
||||
paramtype = "light",
|
||||
use_texture_alpha = "clip",
|
||||
sunlight_propagates = true,
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy=2, cracky=2, crumbly=2, not_in_creative_inventory=1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
})
|
||||
|
||||
--
|
||||
-- Register VM external/callback functions
|
||||
--
|
||||
local function get_params(pos)
|
||||
local payload3 = nanobasic.pop_num(pos) or 0
|
||||
if payload3 >= 0x8000000 then
|
||||
payload3 = payload3 - 0x100000000
|
||||
end
|
||||
local payload2 = nanobasic.pop_num(pos) or 0
|
||||
if payload2 >= 0x8000000 then
|
||||
payload2 = payload2 - 0x100000000
|
||||
end
|
||||
local payload1 = nanobasic.pop_num(pos) or 0
|
||||
if payload1 >= 0x8000000 then
|
||||
payload1 = payload1 - 0x100000000
|
||||
end
|
||||
local cmnd = nanobasic.pop_num(pos)
|
||||
local num = nanobasic.pop_num(pos) or 0
|
||||
local owner = M(pos):get_string("owner")
|
||||
local own_num = M(pos):get_string("node_number")
|
||||
return owner, num, own_num, {payload1, payload2, payload3}
|
||||
end
|
||||
|
||||
local function get_str_param(pos)
|
||||
local payload3 = nanobasic.pop_num(pos) -- dummy value
|
||||
local payload2 = nanobasic.pop_num(pos) -- dummy value
|
||||
local payload1 = nanobasic.pop_str(pos) or ""
|
||||
local cmnd = nanobasic.pop_num(pos)
|
||||
local num = nanobasic.pop_num(pos) or 0
|
||||
local owner = M(pos):get_string("owner")
|
||||
local own_num = M(pos):get_string("node_number")
|
||||
return owner, num, own_num, payload1
|
||||
end
|
||||
|
||||
local function error_handling(pos, num, sts)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
if sts > 0 and nvm.error_label_addr and nvm.error_label_addr > 0 then
|
||||
local err = ErrorStr[sts] or "unknown error"
|
||||
nanobasic.push_num(pos, num)
|
||||
nanobasic.push_str(pos, err)
|
||||
nanobasic.set_pc(pos, nvm.error_label_addr)
|
||||
end
|
||||
end
|
||||
|
||||
register_ext_function("input", {nanobasic.NB_STR}, nanobasic.NB_NUM, function(pos, nvm)
|
||||
nvm.status = "input_num"
|
||||
local s = nanobasic.pop_str(pos)
|
||||
nanobasic.print(pos, s .. "? ")
|
||||
nvm.bttns = {"", "", "", "", "", "Stop", "", ""}
|
||||
nvm.input = InputField
|
||||
local text = nanobasic.get_screen_buffer(pos) or ""
|
||||
M(pos):set_string("formspec", formspec(pos, text))
|
||||
return false -- stop execution
|
||||
end)
|
||||
|
||||
register_ext_function("input$", {nanobasic.NB_STR}, nanobasic.NB_STR, function(pos, nvm)
|
||||
nvm.status = "input_str"
|
||||
local s = nanobasic.pop_str(pos)
|
||||
nanobasic.print(pos, s .. "? ")
|
||||
nvm.bttns = {"", "", "", "", "", "Stop", "", ""}
|
||||
nvm.input = InputField
|
||||
local text = nanobasic.get_screen_buffer(pos) or ""
|
||||
M(pos):set_string("formspec", formspec(pos, text))
|
||||
return false -- stop execution
|
||||
end)
|
||||
|
||||
register_ext_function("sleep", {nanobasic.NB_NUM}, nanobasic.NB_NONE, function(pos, nvm)
|
||||
local t = nanobasic.pop_num(pos) or 0
|
||||
nvm.ttl = t / CYCLE_TIME
|
||||
if techage.is_activeformspec(pos) then
|
||||
local text = nanobasic.get_screen_buffer(pos)
|
||||
M(pos):set_string("formspec", formspec(pos, text))
|
||||
end
|
||||
return true
|
||||
end)
|
||||
|
||||
register_ext_function("time", {}, nanobasic.NB_NUM, function(pos, nvm)
|
||||
nanobasic.push_num(pos, minetest.get_gametime() or 0)
|
||||
return true
|
||||
end)
|
||||
|
||||
register_ext_function("daytime", {}, nanobasic.NB_NUM, function(pos, nvm)
|
||||
nanobasic.push_num(pos, math.floor(minetest.get_timeofday() * 1440) or 0)
|
||||
return true
|
||||
end)
|
||||
|
||||
register_ext_function("daytime$", {nanobasic.NB_NUM}, nanobasic.NB_STR, function(pos, nvm)
|
||||
local british = nanobasic.pop_num(pos) or 0
|
||||
local t = minetest.get_timeofday()
|
||||
local h = math.floor(t * 24) % 24
|
||||
local m = math.floor(t * 1440) % 60
|
||||
|
||||
if british == 1 then
|
||||
if h < 12 then
|
||||
nanobasic.push_str(pos, string.format("%02d:%02d am", h, m))
|
||||
else
|
||||
nanobasic.push_str(pos, string.format("%02d:%02d pm", h - 12, m))
|
||||
end
|
||||
else
|
||||
nanobasic.push_str(pos, string.format("%02d:%02d", h, m))
|
||||
end
|
||||
return true
|
||||
end)
|
||||
|
||||
register_ext_function("hold", {}, nanobasic.NB_NONE, function(pos, nvm)
|
||||
local own_num = M(pos):get_string("node_number")
|
||||
techage.cmnd_hold(own_num)
|
||||
return true
|
||||
end)
|
||||
|
||||
register_ext_function("release", {}, nanobasic.NB_NONE, function(pos, nvm)
|
||||
local own_num = M(pos):get_string("node_number")
|
||||
techage.cmnd_release(own_num)
|
||||
return true
|
||||
end)
|
||||
|
||||
-- num: cmd(num: node_num, num: cmnd, any: pyld1, num: pyld2, num: pyld3)
|
||||
register_ext_function("cmd", {nanobasic.NB_NUM, nanobasic.NB_NUM, nanobasic.NB_ANY, nanobasic.NB_ANY, nanobasic.NB_ANY}, nanobasic.NB_NUM, function(pos, nvm)
|
||||
local cmnd = nanobasic.peek_num(pos, 4) or 0
|
||||
if cmnd < 64 then -- command with payload as number(s)
|
||||
local owner, num, own_num, payload = get_params(pos)
|
||||
if techage.not_protected(tostring(num), owner) then
|
||||
techage.counting_add(owner, 1)
|
||||
local sts, resp = techage.beduino_send_cmnd(own_num, num, cmnd, payload)
|
||||
nanobasic.push_num(pos, sts)
|
||||
error_handling(pos, num, sts)
|
||||
else
|
||||
nanobasic.push_num(pos, 4)
|
||||
error_handling(pos, num, 4)
|
||||
end
|
||||
elseif cmnd < 128 then -- command with payload as string
|
||||
local owner, num, own_num, payload = get_str_param(pos)
|
||||
if techage.not_protected(tostring(num), owner) then
|
||||
techage.counting_add(owner, 1)
|
||||
local sts, resp = techage.beduino_send_cmnd(own_num, num, cmnd, payload)
|
||||
nanobasic.push_num(pos, sts)
|
||||
error_handling(pos, num, sts)
|
||||
else
|
||||
nanobasic.push_num(pos, 4)
|
||||
error_handling(pos, num, 4)
|
||||
end
|
||||
elseif cmnd < 192 then -- request with payload as number(s) and result as number
|
||||
local owner, num, own_num, payload = get_params(pos)
|
||||
if techage.not_protected(tostring(num), owner) then
|
||||
techage.counting_add(owner, 1)
|
||||
local sts, resp = techage.beduino_request_data(own_num, num, cmnd, payload)
|
||||
if type(resp) == "table" then
|
||||
nanobasic.push_num(pos, resp[1] or 0)
|
||||
else
|
||||
nanobasic.push_num(pos, 5)
|
||||
sts = 5
|
||||
end
|
||||
error_handling(pos, num, sts)
|
||||
else
|
||||
nanobasic.push_num(pos, 4)
|
||||
error_handling(pos, num, 4)
|
||||
end
|
||||
else
|
||||
local owner, num, own_num, payload = get_str_param(pos)
|
||||
if techage.not_protected(tostring(num), owner) then
|
||||
techage.counting_add(owner, 1)
|
||||
local sts, resp = techage.beduino_request_data(own_num, num, cmnd, payload)
|
||||
if type(resp) == "table" then
|
||||
nanobasic.push_num(pos, resp[1] or 0)
|
||||
else
|
||||
nanobasic.push_num(pos, 5)
|
||||
sts = 5
|
||||
end
|
||||
error_handling(pos, num, sts)
|
||||
else
|
||||
nanobasic.push_num(pos, 4)
|
||||
error_handling(pos, num, 4)
|
||||
end
|
||||
end
|
||||
return true
|
||||
end)
|
||||
|
||||
-- str: cmd(num: node_num, num: cmnd, any: pyld1, any: pyld2, num: pyld3)
|
||||
register_ext_function("cmd$", {nanobasic.NB_NUM, nanobasic.NB_NUM, nanobasic.NB_ANY, nanobasic.NB_ANY, nanobasic.NB_ANY}, nanobasic.NB_STR, function(pos, nvm)
|
||||
local cmnd = nanobasic.peek_num(pos, 4) or 0
|
||||
if cmnd >= 128 then -- request with payload as number(s) and result as string
|
||||
local owner, num, own_num, payload = get_params(pos)
|
||||
if techage.not_protected(tostring(num), owner) then
|
||||
techage.counting_add(owner, 1)
|
||||
local sts, resp = techage.beduino_request_data(own_num, num, cmnd, payload)
|
||||
if type(resp) == "string" then
|
||||
nanobasic.push_str(pos, resp)
|
||||
else
|
||||
nanobasic.push_str(pos, "")
|
||||
sts = 5
|
||||
end
|
||||
error_handling(pos, num, sts)
|
||||
else
|
||||
nanobasic.push_str(pos, "")
|
||||
error_handling(pos, num, 4)
|
||||
end
|
||||
end
|
||||
return true
|
||||
end)
|
||||
|
||||
-- none: chat(str: msg)
|
||||
register_ext_function("chat", {nanobasic.NB_STR}, nanobasic.NB_NONE, function(pos, nvm)
|
||||
local msg = nanobasic.pop_str(pos) or ""
|
||||
local owner = M(pos):get_string("owner")
|
||||
minetest.chat_send_player(owner, msg)
|
||||
return true
|
||||
end)
|
||||
|
||||
-- none: dputs(num: node_num, num: row, str: text)
|
||||
register_ext_function("dputs", {nanobasic.NB_NUM, nanobasic.NB_NUM, nanobasic.NB_STR}, nanobasic.NB_NONE, function(pos, nvm)
|
||||
local text = nanobasic.pop_str(pos) or ""
|
||||
local row = nanobasic.pop_num(pos) or 0
|
||||
local num = nanobasic.pop_num(pos) or 0
|
||||
local own_num = M(pos):get_string("node_number")
|
||||
local owner = M(pos):get_string("owner")
|
||||
if techage.not_protected(tostring(num), owner) then
|
||||
techage.counting_add(owner, 1)
|
||||
if row == 0 then -- add line
|
||||
techage.send_single(own_num, num, "add", text)
|
||||
else
|
||||
local payload = safer_lua.Store()
|
||||
payload.set("row", row)
|
||||
payload.set("str", text)
|
||||
techage.send_single(own_num, num, "set", payload)
|
||||
end
|
||||
end
|
||||
return true
|
||||
end)
|
||||
|
||||
-- none: dclr(num: node_num)
|
||||
register_ext_function("dclr", {nanobasic.NB_NUM}, nanobasic.NB_NONE, function(pos, nvm)
|
||||
local num = nanobasic.pop_num(pos) or 0
|
||||
local own_num = M(pos):get_string("node_number")
|
||||
local owner = M(pos):get_string("owner")
|
||||
if techage.not_protected(tostring(num), owner) then
|
||||
techage.counting_add(owner, 1)
|
||||
techage.send_single(own_num, num, "clear", nil)
|
||||
end
|
||||
return true
|
||||
end)
|
||||
|
||||
-- none: door(str: node_pos, str: state)
|
||||
register_ext_function("door", {nanobasic.NB_STR, nanobasic.NB_STR}, nanobasic.NB_NONE, function(pos, nvm)
|
||||
local state = nanobasic.pop_str(pos) or ""
|
||||
local spos = nanobasic.pop_str(pos) or 0
|
||||
local doorpos = minetest.string_to_pos("(" .. spos .. ")")
|
||||
local owner = M(pos):get_string("owner")
|
||||
if pos then
|
||||
local door = doors.get(doorpos)
|
||||
if door then
|
||||
techage.counting_add(owner, 1)
|
||||
local player = {
|
||||
get_player_name = function() return owner end,
|
||||
is_player = function() return true end,
|
||||
}
|
||||
if state == "open" then
|
||||
door:open(player)
|
||||
elseif state == "close" then
|
||||
door:close(player)
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
end)
|
||||
|
||||
-- str: iname(str: item_name)
|
||||
register_ext_function("iname$", {nanobasic.NB_STR}, nanobasic.NB_STR, function(pos, nvm)
|
||||
local item_name = nanobasic.pop_str(pos) or ""
|
||||
local item = minetest.registered_items[item_name]
|
||||
if item and item.description then
|
||||
local s = minetest.get_translated_string("en", item.description)
|
||||
nanobasic.push_str(pos, s or "")
|
||||
else
|
||||
nanobasic.push_str(pos, "")
|
||||
end
|
||||
return true
|
||||
end)
|
||||
|
||||
register_ext_function("reset", {}, nanobasic.NB_NONE, function(pos, nvm)
|
||||
nanobasic.reset(pos)
|
||||
return true
|
||||
end)
|
||||
|
||||
--
|
||||
-- Register user input actions: register_action(states, key, function)
|
||||
--
|
||||
register_action({"init", "stopped", "error", "break"}, "Edit", function(pos, nvm, fields)
|
||||
nvm.status = "edit"
|
||||
nvm.bttns = {"", "Save", "Renum", "Cancel", "Run", "", "", ""}
|
||||
nvm.input = ""
|
||||
return M(pos):get_string("code")
|
||||
end)
|
||||
|
||||
register_action({"edit"}, "Save", function(pos, nvm, fields)
|
||||
nanobasic.clear_screen(pos)
|
||||
local code = sort_lines(pos, nvm, fields.code)
|
||||
if code == nil then
|
||||
nvm.status = "error"
|
||||
nvm.bttns = {"Edit", "", "", "", "", "Stop", "", ""}
|
||||
nvm.input = ""
|
||||
M(pos):set_string("code", fields.code)
|
||||
return nanobasic.get_screen_buffer(pos) or ""
|
||||
end
|
||||
M(pos):set_string("code", code)
|
||||
return code
|
||||
end)
|
||||
|
||||
register_action({"edit"}, "Renum", function(pos, nvm, fields)
|
||||
nanobasic.clear_screen(pos)
|
||||
local code = sort_lines(pos, nvm, fields.code)
|
||||
if code == nil then
|
||||
nvm.status = "error"
|
||||
nvm.bttns = {"Edit", "", "", "", "", "Stop", "", ""}
|
||||
nvm.input = ""
|
||||
M(pos):set_string("code", fields.code)
|
||||
return nanobasic.get_screen_buffer(pos) or ""
|
||||
end
|
||||
code = renumber_lines(pos, nvm, code)
|
||||
M(pos):set_string("code", code)
|
||||
return code
|
||||
end)
|
||||
|
||||
register_action({"edit"}, "Cancel", function(pos, nvm, fields)
|
||||
nvm.status = "stopped"
|
||||
nvm.bttns = {"Edit", "", "", "", "Run", "Stop", "", ""}
|
||||
nvm.input = ""
|
||||
return nanobasic.get_screen_buffer(pos) or ""
|
||||
end)
|
||||
|
||||
register_action({"init", "edit", "stopped"}, "Run", function(pos, nvm, fields)
|
||||
if nvm.status == "edit" then
|
||||
M(pos):set_string("code", fields.code)
|
||||
end
|
||||
local code = M(pos):get_string("code")
|
||||
if nanobasic.create(pos, code) then
|
||||
nvm.status = "running"
|
||||
nvm.bttns = {"", "", "", "", "", "Stop", "", "List"}
|
||||
nvm.input = ""
|
||||
nvm.variables = nanobasic.get_variable_list(pos)
|
||||
nvm.onload_label_addr = nanobasic.get_label_address(pos, "64000") or 0
|
||||
nvm.error_label_addr = nanobasic.get_label_address(pos, "65000") or 0
|
||||
nvm.ttl = nil
|
||||
minetest.get_node_timer(pos):start(CYCLE_TIME)
|
||||
return nanobasic.get_screen_buffer(pos) or ""
|
||||
else
|
||||
nvm.status = "error"
|
||||
nvm.bttns = {"Edit", "", "", "", "", "Stop", "", ""}
|
||||
nvm.input = ""
|
||||
return nanobasic.get_screen_buffer(pos) or ""
|
||||
end
|
||||
end)
|
||||
|
||||
register_action({"break"}, "Continue", function(pos, nvm, fields)
|
||||
nvm.status = "running"
|
||||
nvm.bttns = {"", "", "", "", "", "Stop", "", "List"}
|
||||
nvm.input = ""
|
||||
minetest.get_node_timer(pos):start(CYCLE_TIME)
|
||||
return nanobasic.get_screen_buffer(pos) or ""
|
||||
end)
|
||||
|
||||
register_action({"break"}, "List", function(pos, nvm, fields)
|
||||
nvm.status = "break"
|
||||
nvm.bttns = {"", "", "", "", "", "Stop", "Continue", "List"}
|
||||
nvm.input = InputField
|
||||
return M(pos):get_string("code")
|
||||
end)
|
||||
|
||||
register_action({"running"}, "List", function(pos, nvm, fields, player)
|
||||
nvm.bttns = {"", "", "", "", "", "Stop", "Continue", ""}
|
||||
nvm.input = ""
|
||||
techage.reset_activeformspec(pos, player)
|
||||
return M(pos):get_string("code")
|
||||
end)
|
||||
|
||||
register_action({"running"}, "Continue", function(pos, nvm, fields, player)
|
||||
nvm.bttns = {"", "", "", "", "", "Stop", "", "List"}
|
||||
nvm.input = ""
|
||||
techage.set_activeformspec(pos, player)
|
||||
return nanobasic.get_screen_buffer(pos) or ""
|
||||
end)
|
||||
|
||||
register_action({"break"}, "Enter", function(pos, nvm, fields)
|
||||
nvm.status = "break"
|
||||
nvm.bttns = {"", "", "", "", "", "Stop", "Continue", "List"}
|
||||
nvm.input = InputField
|
||||
local s = fields.input:lower()
|
||||
local var_name, arr_idx = s:match('^(%w+)%s*,%s*([0-9]*)$')
|
||||
if var_name == nil then
|
||||
var_name, arr_idx = s, "0"
|
||||
end
|
||||
if nvm.variables[var_name] then
|
||||
arr_idx = tonumber(arr_idx)
|
||||
local var_type, var_idx = nvm.variables[var_name][1], nvm.variables[var_name][2]
|
||||
local val = nanobasic.read_variable(pos, var_type, var_idx, arr_idx)
|
||||
if var_type == nanobasic.NB_NUM then
|
||||
nanobasic.print(pos, string.format("%s = %u\n", var_name, val));
|
||||
elseif var_type == nanobasic.NB_STR then
|
||||
nanobasic.print(pos, string.format("%s = \"%s\"\n", var_name, val));
|
||||
else
|
||||
nanobasic.print(pos, string.format("%s(%u) = %u\n", var_name, arr_idx, val));
|
||||
end
|
||||
else
|
||||
nanobasic.print(pos, string.format("Variable '%s' is unknown\n", var_name));
|
||||
end
|
||||
return nanobasic.get_screen_buffer(pos) or ""
|
||||
end)
|
||||
|
||||
register_action({"stopped", "init"}, "Stop", function(pos, nvm, fields)
|
||||
nvm.status = "init"
|
||||
nanobasic.print(pos, "\nProgram stopped.\n")
|
||||
nvm.bttns = Buttons
|
||||
nvm.input = ""
|
||||
nanobasic.clear_screen(pos)
|
||||
return poweron_message(pos)
|
||||
end)
|
||||
|
||||
register_action({"running", "input_num", "input_str"}, "Stop", function(pos, nvm, fields)
|
||||
nvm.status = "stopped"
|
||||
nanobasic.print(pos, "\nProgram stopped.\n")
|
||||
nvm.bttns = {"Edit", "", "", "", "Run", "Stop", "", ""}
|
||||
nvm.input = ""
|
||||
return nanobasic.get_screen_buffer(pos) or ""
|
||||
end)
|
||||
|
||||
register_action({"break", "error"}, "Stop", function(pos, nvm, fields)
|
||||
nvm.status = "stopped"
|
||||
nanobasic.print(pos, "\nProgram stopped.\n")
|
||||
nvm.bttns = {"Edit", "", "", "", "Run", "Stop", "", ""}
|
||||
nvm.input = ""
|
||||
return nanobasic.get_screen_buffer(pos) or ""
|
||||
end)
|
||||
|
||||
register_action(States, "larger", function(pos, nvm, fields)
|
||||
nvm.trm_text_size = math.min((nvm.trm_text_size or 0) + 1, 8)
|
||||
return fields.code or nanobasic.get_screen_buffer(pos) or ""
|
||||
end)
|
||||
|
||||
register_action(States, "smaller", function(pos, nvm, fields)
|
||||
nvm.trm_text_size = math.max((nvm.trm_text_size or 0) - 1, -8)
|
||||
return fields.code or nanobasic.get_screen_buffer(pos) or ""
|
||||
end)
|
||||
|
||||
register_action(States, "quit", function(pos, nvm, fields)
|
||||
nvm.trm_ttl = 0
|
||||
return ""
|
||||
end)
|
||||
|
||||
register_action({"input_num"}, "Enter", function(pos, nvm, fields)
|
||||
nanobasic.print(pos, fields.input .. "\n")
|
||||
nanobasic.push_num(pos, tonumber(fields.input) or 0)
|
||||
nvm.status = "running"
|
||||
nvm.bttns = {"", "", "", "", "", "Stop", "", ""}
|
||||
nvm.input = ""
|
||||
minetest.get_node_timer(pos):start(CYCLE_TIME)
|
||||
return nanobasic.get_screen_buffer(pos) or ""
|
||||
end)
|
||||
|
||||
register_action({"input_str"}, "Enter", function(pos, nvm, fields)
|
||||
nanobasic.print(pos, fields.input .. "\n")
|
||||
nanobasic.push_str(pos, fields.input)
|
||||
nvm.status = "running"
|
||||
nvm.bttns = {"", "", "", "", "", "Stop", "", ""}
|
||||
nvm.input = ""
|
||||
minetest.get_node_timer(pos):start(CYCLE_TIME)
|
||||
return nanobasic.get_screen_buffer(pos) or ""
|
||||
end)
|
||||
|
||||
|
||||
techage.register_node({"techage:basic_terminal"}, {
|
||||
on_node_load = function(pos)
|
||||
nanobasic.vm_restore(pos)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
if nvm.status == "running" then
|
||||
if nvm.onload_label_addr and nvm.onload_label_addr > 0 then
|
||||
nanobasic.set_pc(pos, nvm.onload_label_addr)
|
||||
end
|
||||
minetest.get_node_timer(pos):start(CYCLE_TIME)
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
@@ -0,0 +1,516 @@
|
||||
--[[
|
||||
|
||||
TechAge
|
||||
=======
|
||||
|
||||
Copyright (C) 2017-2023 Joachim Stolberg
|
||||
|
||||
AGPL v3
|
||||
See LICENSE.txt for more information
|
||||
|
||||
TA3 & TA4 Logic button
|
||||
|
||||
]]--
|
||||
|
||||
-- for lazy programmers
|
||||
local M = minetest.get_meta
|
||||
local S = techage.S
|
||||
local NDEF = function(pos) return (minetest.registered_nodes[techage.get_node_lvm(pos).name] or {}) end
|
||||
|
||||
local logic = techage.logic
|
||||
|
||||
local WRENCH_MENU3 = {
|
||||
{
|
||||
type = "dropdown",
|
||||
choices = "switch,on button,button 1s,button 2s,button 4s,button 8s,button 16s,button 32s",
|
||||
name = "type",
|
||||
label = S("Type"),
|
||||
tooltip = S("Button or switch"),
|
||||
default = "1",
|
||||
},
|
||||
{
|
||||
type = "numbers",
|
||||
name = "numbers",
|
||||
label = S("Number"),
|
||||
tooltip = S("Destination block number(s)"),
|
||||
default = "",
|
||||
check = techage.check_numbers,
|
||||
},
|
||||
{
|
||||
type = "dropdown",
|
||||
choices = "private,protected,public",
|
||||
name = "access",
|
||||
label = S("Access"),
|
||||
tooltip = S("Button protection"),
|
||||
default = "1",
|
||||
},
|
||||
}
|
||||
|
||||
local WRENCH_MENU4 = {
|
||||
{
|
||||
type = "dropdown",
|
||||
choices = "switch,on button,button 1s,button 2s,button 4s,button 8s,button 16s,button 32s",
|
||||
name = "type",
|
||||
label = S("Type"),
|
||||
tooltip = S("Button or switch"),
|
||||
default = "1",
|
||||
},
|
||||
{
|
||||
type = "numbers",
|
||||
name = "numbers",
|
||||
label = S("Number"),
|
||||
tooltip = S("Destination block number(s)"),
|
||||
default = "",
|
||||
check = techage.check_numbers,
|
||||
},
|
||||
{
|
||||
type = "ascii",
|
||||
name = "command",
|
||||
label = S("Command"),
|
||||
tooltip = S("Command to be sent"),
|
||||
default = "on",
|
||||
},
|
||||
{
|
||||
type = "dropdown",
|
||||
choices = "private,protected,public",
|
||||
name = "access",
|
||||
label = S("Access"),
|
||||
tooltip = S("Button protection"),
|
||||
default = "1",
|
||||
},
|
||||
{
|
||||
type = "ascii",
|
||||
name = "decription",
|
||||
label = S("Infotext"),
|
||||
tooltip = S("Change the block name (infotext)"),
|
||||
default = "",
|
||||
},
|
||||
}
|
||||
|
||||
local function switch_on(pos, no_sound)
|
||||
local cycle_time = M(pos):get_int("cycle_time")
|
||||
local name = techage.get_node_lvm(pos).name
|
||||
if name == "techage:ta3_button_off" then
|
||||
logic.swap_node(pos, "techage:ta3_button_on")
|
||||
elseif name == "techage:ta4_button_off" then
|
||||
logic.swap_node(pos, "techage:ta4_button_on")
|
||||
end
|
||||
logic.guarded_action(pos, logic.send_cmnd, pos, "command", "on", cycle_time)
|
||||
if not no_sound then
|
||||
minetest.sound_play("techage_button", {
|
||||
pos = pos,
|
||||
gain = 0.5,
|
||||
max_hear_distance = 5,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
local function switch_off(pos, no_sound)
|
||||
local name = techage.get_node_lvm(pos).name
|
||||
if name == "techage:ta3_button_on" then
|
||||
logic.swap_node(pos, "techage:ta3_button_off")
|
||||
elseif name == "techage:ta4_button_on" then
|
||||
logic.swap_node(pos, "techage:ta4_button_off")
|
||||
end
|
||||
local meta = M(pos)
|
||||
if meta:get_string("off_command") ~= "true" and
|
||||
(not meta:contains("command") or meta:get_string("command") == "on") then
|
||||
logic.guarded_action(pos, logic.send_off, pos, M(pos))
|
||||
end
|
||||
if not no_sound then
|
||||
minetest.sound_play("techage_button", {
|
||||
pos = pos,
|
||||
gain = 0.5,
|
||||
max_hear_distance = 5,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
local function formspec(meta)
|
||||
local numbers = meta:get_string("numbers") or ""
|
||||
local idx = meta:get_int("cycle_idx") or 0
|
||||
if idx == 0 then idx = 1 end
|
||||
local access_idx = meta:get_string("public") == "true" and 3 or meta:get_string("protected") == "true" and 2 or 1
|
||||
return "size[7.5,6]"..
|
||||
"dropdown[0.2,0;3;type;switch,on button,button 1s,button 2s,button 4s,button 8s,button 16s,button 32s;"..idx.."]"..
|
||||
"field[0.5,2;7,1;numbers;"..S("Insert destination node number(s)")..";"..numbers.."]" ..
|
||||
"label[0.2,3;"..S("Access:").."]"..
|
||||
"dropdown[3,3;4;access;private,protected,public;"..access_idx.."]"..
|
||||
"button_exit[2,4;3,1;exit;"..S("Save").."]"
|
||||
end
|
||||
|
||||
local function store_fields_data(pos, fields)
|
||||
local meta = M(pos)
|
||||
meta:set_string("numbers", fields.numbers)
|
||||
meta:set_string("off_command", "")
|
||||
|
||||
if fields.access == "protected" then
|
||||
meta:set_string("protected", "true")
|
||||
meta:set_string("public", "")
|
||||
end
|
||||
if fields.access == "public" then
|
||||
meta:set_string("public", "true")
|
||||
meta:set_string("protected", "")
|
||||
end
|
||||
if fields.access == "private" then
|
||||
meta:set_string("public", "")
|
||||
meta:set_string("protected", "")
|
||||
end
|
||||
local cycle_time = nil
|
||||
if fields.type == "switch" then
|
||||
meta:set_int("cycle_idx", 1)
|
||||
cycle_time = 0
|
||||
elseif fields.type == "on button" then
|
||||
meta:set_int("cycle_idx", 2)
|
||||
meta:set_string("off_command", "true")
|
||||
cycle_time = 1
|
||||
elseif fields.type == "button 1s" then
|
||||
meta:set_int("cycle_idx", 3)
|
||||
cycle_time = 1
|
||||
elseif fields.type == "button 2s" then
|
||||
meta:set_int("cycle_idx", 4)
|
||||
cycle_time = 2
|
||||
elseif fields.type == "button 4s" then
|
||||
meta:set_int("cycle_idx", 5)
|
||||
cycle_time = 4
|
||||
elseif fields.type == "button 8s" then
|
||||
meta:set_int("cycle_idx", 6)
|
||||
cycle_time = 8
|
||||
elseif fields.type == "button 16s" then
|
||||
meta:set_int("cycle_idx", 7)
|
||||
cycle_time = 16
|
||||
elseif fields.type == "button 32s" then
|
||||
meta:set_int("cycle_idx", 8)
|
||||
cycle_time = 32
|
||||
end
|
||||
if cycle_time ~= nil then
|
||||
meta:set_int("cycle_time", cycle_time)
|
||||
end
|
||||
meta:set_string("access", fields.access)
|
||||
meta:set_string("type", fields.type)
|
||||
end
|
||||
|
||||
local function on_receive_fields(pos, formname, fields, player)
|
||||
if minetest.is_protected(pos, player:get_player_name()) then
|
||||
return
|
||||
end
|
||||
if not techage.check_numbers(fields.numbers, player:get_player_name()) then
|
||||
return
|
||||
end
|
||||
store_fields_data(pos, fields)
|
||||
|
||||
local meta = M(pos)
|
||||
logic.infotext(meta, NDEF(pos).description)
|
||||
if fields.exit then
|
||||
meta:set_string("formspec", "")
|
||||
meta:set_string("fixed" , "true")
|
||||
else
|
||||
meta:set_string("formspec", formspec(meta))
|
||||
end
|
||||
end
|
||||
|
||||
local function ta_after_formspec(pos, fields, playername)
|
||||
store_fields_data(pos, fields)
|
||||
local meta = M(pos)
|
||||
if fields.decription and fields.decription ~= "" then
|
||||
logic.infotext(meta, fields.decription)
|
||||
else
|
||||
logic.infotext(meta, NDEF(pos).description)
|
||||
end
|
||||
end
|
||||
|
||||
local function can_access(pos, player)
|
||||
local meta = M(pos)
|
||||
local public = meta:get_string("public") == "true"
|
||||
local protected = meta:get_string("protected") == "true"
|
||||
local owner = meta:get_string("owner")
|
||||
local name = player:get_player_name()
|
||||
return public or protected and not minetest.is_protected(pos, name) or owner == name
|
||||
end
|
||||
|
||||
local function on_rightclick_on(pos, node, clicker)
|
||||
local meta = M(pos)
|
||||
local fixed = meta:get_string("fixed")
|
||||
if fixed == "true" then
|
||||
if can_access(pos, clicker) then
|
||||
switch_on(pos)
|
||||
local mem = techage.get_mem(pos)
|
||||
mem.clicker = clicker and clicker:get_player_name()
|
||||
mem.time = math.floor(minetest.get_us_time() / 100000)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function on_rightclick_off(pos, node, clicker)
|
||||
local meta = M(pos)
|
||||
local numbers = meta:get_string("numbers")
|
||||
local cycle_time = meta:get_int("cycle_time") or 0
|
||||
if numbers ~= "" and numbers ~= nil and cycle_time == 0 then
|
||||
if can_access(pos, clicker) then
|
||||
switch_off(pos)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function techage_set_numbers(pos, numbers, player_name)
|
||||
local meta = M(pos)
|
||||
local res = logic.set_numbers(pos, numbers, player_name, NDEF(pos).description)
|
||||
meta:set_string("formspec", formspec(meta))
|
||||
return res
|
||||
end
|
||||
|
||||
local function after_dig_node(pos, oldnode, oldmetadata, digger)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
end
|
||||
|
||||
minetest.register_node("techage:ta3_button_off", {
|
||||
description = S("TA3 Button/Switch"),
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_button.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_button.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3.png^techage_button_off.png",
|
||||
},
|
||||
|
||||
after_place_node = function(pos, placer)
|
||||
local meta = M(pos)
|
||||
logic.after_place_node(pos, placer, "techage:ta3_button_off", S("TA3 Button/Switch"))
|
||||
logic.infotext(meta, S("TA3 Button/Switch"))
|
||||
meta:set_string("formspec", formspec(meta))
|
||||
meta:set_string("public", "false")
|
||||
meta:set_int("cycle_time", 0)
|
||||
end,
|
||||
|
||||
ta3_formspec = WRENCH_MENU3,
|
||||
ta_after_formspec = ta_after_formspec,
|
||||
on_receive_fields = on_receive_fields,
|
||||
on_rightclick = on_rightclick_on,
|
||||
techage_set_numbers = techage_set_numbers,
|
||||
after_dig_node = after_dig_node,
|
||||
|
||||
on_rotate = screwdriver.disallow,
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy=2, cracky=2, crumbly=2},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
})
|
||||
|
||||
minetest.register_node("techage:ta3_button_on", {
|
||||
description = ("TA3 Button/Switch"),
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_button.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_button.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3.png^techage_button_on.png",
|
||||
},
|
||||
|
||||
ta3_formspec = WRENCH_MENU3,
|
||||
ta_after_formspec = ta_after_formspec,
|
||||
on_rightclick = on_rightclick_off,
|
||||
on_timer = switch_off,
|
||||
on_rotate = screwdriver.disallow,
|
||||
techage_set_numbers = techage_set_numbers,
|
||||
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy=2, cracky=2, crumbly=2, not_in_creative_inventory=1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
drop = "techage:ta3_button_off",
|
||||
})
|
||||
|
||||
minetest.register_node("techage:ta4_button_off", {
|
||||
description = S("TA4 Button/Switch"),
|
||||
inventory_image = "techage_smartline_button_inv.png",
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"techage_smartline.png",
|
||||
"techage_smartline.png",
|
||||
"techage_smartline.png",
|
||||
"techage_smartline.png",
|
||||
"techage_smartline.png",
|
||||
"techage_smartline.png^techage_smartline_button_off.png",
|
||||
},
|
||||
|
||||
drawtype = "nodebox",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{ -6/32, -6/32, 14/32, 6/32, 6/32, 16/32},
|
||||
},
|
||||
},
|
||||
|
||||
after_place_node = function(pos, placer)
|
||||
local meta = M(pos)
|
||||
logic.after_place_node(pos, placer, "techage:ta4_button_off", S("TA4 Button/Switch"))
|
||||
logic.infotext(meta, S("TA4 Button/Switch"))
|
||||
meta:set_string("formspec", formspec(meta))
|
||||
meta:set_string("public", "false")
|
||||
meta:set_int("cycle_time", 0)
|
||||
end,
|
||||
|
||||
ta4_formspec = WRENCH_MENU4,
|
||||
ta_after_formspec = ta_after_formspec,
|
||||
on_receive_fields = on_receive_fields,
|
||||
on_rightclick = on_rightclick_on,
|
||||
techage_set_numbers = techage_set_numbers,
|
||||
after_dig_node = after_dig_node,
|
||||
|
||||
on_rotate = screwdriver.disallow,
|
||||
paramtype = "light",
|
||||
use_texture_alpha = techage.CLIP,
|
||||
sunlight_propagates = true,
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy=2, cracky=2, crumbly=2},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
})
|
||||
|
||||
minetest.register_node("techage:ta4_button_on", {
|
||||
description = ("TA4 Button/Switch"),
|
||||
inventory_image = "techage_smartline_button_inv.png",
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"techage_smartline.png",
|
||||
"techage_smartline.png",
|
||||
"techage_smartline.png",
|
||||
"techage_smartline.png",
|
||||
"techage_smartline.png",
|
||||
"techage_smartline.png^techage_smartline_button_on.png",
|
||||
},
|
||||
|
||||
drawtype = "nodebox",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{ -6/32, -6/32, 14/32, 6/32, 6/32, 16/32},
|
||||
},
|
||||
},
|
||||
|
||||
ta4_formspec = WRENCH_MENU4,
|
||||
ta_after_formspec = ta_after_formspec,
|
||||
on_rightclick = on_rightclick_off,
|
||||
on_timer = switch_off,
|
||||
on_rotate = screwdriver.disallow,
|
||||
techage_set_numbers = techage_set_numbers,
|
||||
|
||||
paramtype = "light",
|
||||
use_texture_alpha = techage.CLIP,
|
||||
sunlight_propagates = true,
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy=2, cracky=2, crumbly=2, not_in_creative_inventory=1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
drop = "techage:ta4_button_off",
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:ta3_button_off",
|
||||
recipe = {
|
||||
{"", "group:wood", ""},
|
||||
{"default:glass", "techage:vacuum_tube", ""},
|
||||
{"", "group:wood", ""},
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:ta4_button_off",
|
||||
recipe = {
|
||||
{"", "techage:aluminum", "dye:blue"},
|
||||
{"", "default:glass", "techage:ta4_wlanchip"},
|
||||
{"", "", ""},
|
||||
},
|
||||
})
|
||||
|
||||
techage.register_node({"techage:ta3_button_off", "techage:ta3_button_on"}, {
|
||||
on_recv_message = function(pos, src, topic, payload)
|
||||
if topic == "on" then
|
||||
switch_on(pos, true)
|
||||
return true
|
||||
elseif topic == "off" then
|
||||
switch_off(pos, true)
|
||||
return true
|
||||
elseif topic == "state" then
|
||||
local name = techage.get_node_lvm(pos).name
|
||||
return name == "techage:ta3_button_on" and "on" or "off"
|
||||
else
|
||||
return "unsupported"
|
||||
end
|
||||
end,
|
||||
on_beduino_receive_cmnd = function(pos, src, topic, payload)
|
||||
if topic == 1 and payload[1] == 1 then
|
||||
switch_on(pos, true)
|
||||
return 0
|
||||
elseif topic == 1 and payload[1] == 0 then
|
||||
switch_off(pos, true)
|
||||
return 0
|
||||
else
|
||||
return 2
|
||||
end
|
||||
end,
|
||||
on_beduino_request_data = function(pos, src, topic, payload)
|
||||
if topic == 131 then -- State
|
||||
local name = techage.get_node_lvm(pos).name
|
||||
return 0, name == "techage:ta3_button_on" and {1} or {0}
|
||||
else
|
||||
return 2, ""
|
||||
end
|
||||
end,
|
||||
}
|
||||
)
|
||||
|
||||
techage.register_node({
|
||||
"techage:ta4_button_off", "techage:ta4_button_on",
|
||||
}, {
|
||||
on_recv_message = function(pos, src, topic, payload)
|
||||
if topic == "on" then
|
||||
switch_on(pos, true)
|
||||
return true
|
||||
elseif topic == "off" then
|
||||
switch_off(pos, true)
|
||||
return true
|
||||
elseif topic == "state" then
|
||||
local name = techage.get_node_lvm(pos).name
|
||||
return name == "techage:ta4_button_on" and "on" or "off"
|
||||
elseif topic == "name" then
|
||||
local mem = techage.get_mem(pos)
|
||||
return mem.clicker or ""
|
||||
elseif topic == "time" then
|
||||
local mem = techage.get_mem(pos)
|
||||
return mem.time or 0
|
||||
else
|
||||
return "unsupported"
|
||||
end
|
||||
end,
|
||||
on_beduino_receive_cmnd = function(pos, src, topic, payload)
|
||||
if topic == 1 and payload[1] == 1 then
|
||||
switch_on(pos, true)
|
||||
return 0
|
||||
elseif topic == 1 and payload[1] == 0 then
|
||||
switch_off(pos, true)
|
||||
return 0
|
||||
else
|
||||
return 2
|
||||
end
|
||||
end,
|
||||
on_beduino_request_data = function(pos, src, topic, payload)
|
||||
if topic == 131 then -- State
|
||||
local name = techage.get_node_lvm(pos).name
|
||||
return 0, name == "techage:ta4_button_on" and {1} or {0}
|
||||
elseif topic == 144 then -- Player Name
|
||||
local mem = techage.get_mem(pos)
|
||||
return 0, mem.clicker
|
||||
elseif topic == 149 then --time
|
||||
local mem = techage.get_mem(pos)
|
||||
return 0, {mem.time or 0}
|
||||
else
|
||||
return 2, ""
|
||||
end
|
||||
end,
|
||||
}
|
||||
)
|
||||
@@ -0,0 +1,308 @@
|
||||
--[[
|
||||
|
||||
TechAge
|
||||
=======
|
||||
|
||||
Copyright (C) 2017-2021 Joachim Stolberg
|
||||
|
||||
AGPL v3
|
||||
See LICENSE.txt for more information
|
||||
|
||||
TA4 Logic twofold button
|
||||
|
||||
]]--
|
||||
|
||||
-- for lazy programmers
|
||||
local M = minetest.get_meta
|
||||
local S = techage.S
|
||||
local logic = techage.logic
|
||||
|
||||
local function get_button_num(pos, clicker, pointed_thing)
|
||||
-- use the node behind the button to get better results
|
||||
if clicker and pointed_thing then
|
||||
local offs = vector.subtract(pointed_thing.under, pointed_thing.above)
|
||||
pointed_thing.under = vector.add(pointed_thing.under, offs)
|
||||
pointed_thing.above = vector.add(pointed_thing.above, offs)
|
||||
local pos1 = minetest.pointed_thing_to_face_pos(clicker, pointed_thing)
|
||||
local y = pos1.y - pos.y
|
||||
|
||||
if y > 0.03 then
|
||||
return 1
|
||||
elseif y < -0.03 then
|
||||
return 2
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local WRENCH_MENU = {
|
||||
{
|
||||
type = "dropdown",
|
||||
choices = "button,switch",
|
||||
name = "type",
|
||||
label = S("Type"),
|
||||
tooltip = S("Momentary button or on/off switch"),
|
||||
default = "1",
|
||||
},
|
||||
{
|
||||
type = "ascii",
|
||||
name = "label1",
|
||||
label = S("Label") .. " 1",
|
||||
tooltip = S("Label for the button"),
|
||||
default = "1",
|
||||
},
|
||||
{
|
||||
type = "numbers",
|
||||
name = "dest_number1",
|
||||
label = S("Number") .. " 1",
|
||||
tooltip = S("Destination block number"),
|
||||
default = "",
|
||||
check = techage.check_numbers,
|
||||
},
|
||||
{
|
||||
type = "ascii",
|
||||
name = "command1",
|
||||
label = S("Command") .. " 1",
|
||||
tooltip = S("Command to be sent (ignored for switches)"),
|
||||
default = "1",
|
||||
},
|
||||
{
|
||||
type = "ascii",
|
||||
name = "label2",
|
||||
label = S("Label") .. " 2",
|
||||
tooltip = S("Label for the button"),
|
||||
default = "1",
|
||||
},
|
||||
{
|
||||
type = "numbers",
|
||||
name = "dest_number2",
|
||||
label = S("Number") .. " 2",
|
||||
tooltip = S("Destination block number"),
|
||||
default = "",
|
||||
check = techage.check_numbers,
|
||||
},
|
||||
{
|
||||
type = "ascii",
|
||||
name = "command2",
|
||||
label = S("Command") .. " 2",
|
||||
tooltip = S("Command to be sent (ignored for switches)"),
|
||||
default = "2",
|
||||
},
|
||||
{
|
||||
type = "dropdown",
|
||||
choices = "private,protected,public",
|
||||
name = "access",
|
||||
label = S("Access"),
|
||||
tooltip = S("Button protection"),
|
||||
default = "8",
|
||||
},
|
||||
}
|
||||
|
||||
local function send_cmnd(pos, num, cmd)
|
||||
local meta = M(pos)
|
||||
local own_num = meta:get_string("node_number")
|
||||
local dest = meta:get_string("dest_number" .. num)
|
||||
local command, payload = cmd, nil
|
||||
if not cmd then
|
||||
local s = meta:get_string("command" .. num)
|
||||
command, payload = unpack(string.split(s, " ", false, 1))
|
||||
end
|
||||
local owner = meta:get_string("owner")
|
||||
if techage.check_numbers(dest, owner) then
|
||||
techage.send_multi(own_num, dest, command, payload)
|
||||
end
|
||||
end
|
||||
|
||||
local function button_update(pos, objref)
|
||||
local meta = M(pos)
|
||||
pos = vector.round(pos)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
nvm.button = nvm.button or {}
|
||||
local tbl = {" ", " ", meta:get_string("label1"), " ", meta:get_string("label2")}
|
||||
local text = "< " .. table.concat(tbl, "\n< ")
|
||||
local texture = lcdlib.make_multiline_texture("default", text, 96, 96, 7, "top", "#000", 6)
|
||||
|
||||
if nvm.button[1] then
|
||||
texture = texture .. "^techage_smartline_button_4x_on2.png"
|
||||
end
|
||||
if nvm.button[2] then
|
||||
texture = texture .. "^techage_smartline_button_4x_on3.png"
|
||||
end
|
||||
objref:set_properties({ textures = {texture}, visual_size = {x=1, y=1} })
|
||||
end
|
||||
|
||||
local function switch_off(pos, num)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
nvm.button = nvm.button or {}
|
||||
nvm.button[num] = nil
|
||||
lcdlib.update_entities(pos)
|
||||
end
|
||||
|
||||
local function switch_on(pos, num)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
nvm.button = nvm.button or {}
|
||||
nvm.button[num] = true
|
||||
lcdlib.update_entities(pos)
|
||||
end
|
||||
|
||||
local lcd_box = {-8/16, -4/16, 7.75/16, 8/16, 4/16, 8/16}
|
||||
|
||||
local function can_access(pos, player)
|
||||
local meta = M(pos)
|
||||
local playername = player:get_player_name()
|
||||
local access = meta:get_string("access")
|
||||
local owner = meta:get_string("owner")
|
||||
local protected = minetest.is_protected(pos, playername)
|
||||
|
||||
if access == "private" and playername ~= owner then
|
||||
return false
|
||||
elseif access == "protected" and protected then
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
minetest.register_node("techage:ta4_button_2x", {
|
||||
description = S("TA4 2x Button"),
|
||||
inventory_image = 'techage_smartline_button_2x.png',
|
||||
tiles = {'techage_smartline_button_2x.png'},
|
||||
drawtype = "nodebox",
|
||||
paramtype = "light",
|
||||
use_texture_alpha = "clip",
|
||||
sunlight_propagates = true,
|
||||
paramtype2 = "facedir",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = lcd_box,
|
||||
},
|
||||
light_source = 6,
|
||||
|
||||
display_entities = {
|
||||
["techage:display_entity"] = { depth = 0.48,
|
||||
on_display_update = button_update},
|
||||
},
|
||||
|
||||
after_place_node = function(pos, placer)
|
||||
local number = techage.add_node(pos, "techage:ta4_button_2x")
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("node_number", number)
|
||||
meta:set_string("owner", placer:get_player_name())
|
||||
meta:set_string("infotext", "TA4 2x Button " .. number)
|
||||
meta:set_string("type", "button")
|
||||
meta:set_string("label1", "B1")
|
||||
meta:set_string("label2", "B2")
|
||||
lcdlib.update_entities(pos)
|
||||
end,
|
||||
|
||||
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
|
||||
if clicker and clicker:is_player() then
|
||||
-- Check access settings
|
||||
if not can_access(pos, clicker) then
|
||||
return
|
||||
end
|
||||
|
||||
local num = get_button_num(pos, clicker, pointed_thing)
|
||||
if num then
|
||||
local typ = M(pos):get_string("type")
|
||||
if typ == "switch" then
|
||||
local nvm = techage.get_nvm(pos)
|
||||
nvm.button = nvm.button or {}
|
||||
if nvm.button[num] then
|
||||
switch_off(pos, num)
|
||||
logic.guarded_action(pos, send_cmnd, pos, num, "off")
|
||||
else
|
||||
switch_on(pos, num)
|
||||
logic.guarded_action(pos, send_cmnd, pos, num, "on")
|
||||
end
|
||||
else
|
||||
switch_on(pos, num)
|
||||
logic.guarded_action(pos, send_cmnd, pos, num)
|
||||
minetest.after(0.5, switch_off, pos, num)
|
||||
end
|
||||
minetest.sound_play("techage_button", {
|
||||
pos = pos,
|
||||
gain = 0.5,
|
||||
max_hear_distance = 5,
|
||||
})
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
ta_after_formspec = function(pos, fields, playername)
|
||||
lcdlib.update_entities(pos)
|
||||
end,
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
end,
|
||||
|
||||
ta3_formspec = WRENCH_MENU,
|
||||
on_place = lcdlib.on_place,
|
||||
on_construct = lcdlib.on_construct,
|
||||
on_destruct = lcdlib.on_destruct,
|
||||
on_rotate = lcdlib.on_rotate,
|
||||
groups = {cracky=2, crumbly=2},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
})
|
||||
|
||||
techage.register_node({"techage:ta4_button_2x"}, {
|
||||
on_recv_message = function(pos, src, topic, payload)
|
||||
local num = math.min(tonumber(payload) or 0, 2)
|
||||
if topic == "on" then
|
||||
switch_on(pos, num)
|
||||
logic.guarded_action(pos, send_cmnd, pos, num)
|
||||
return true
|
||||
elseif topic == "off" then
|
||||
switch_off(pos, num)
|
||||
return true
|
||||
elseif topic == "state" then
|
||||
local nvm = techage.get_nvm(pos)
|
||||
nvm.button = nvm.button or {}
|
||||
return nvm.button[num] == true
|
||||
else
|
||||
return "unsupported"
|
||||
end
|
||||
end,
|
||||
on_beduino_receive_cmnd = function(pos, src, topic, payload)
|
||||
local num = math.min(payload[1], 2)
|
||||
if topic == 23 and payload[2] == 1 then
|
||||
switch_on(pos, num)
|
||||
logic.guarded_action(pos, send_cmnd, pos, num)
|
||||
return 0
|
||||
elseif topic == 23 and payload[2] == 0 then
|
||||
switch_off(pos, num)
|
||||
return 0
|
||||
else
|
||||
return 2
|
||||
end
|
||||
end,
|
||||
on_beduino_request_data = function(pos, src, topic, payload)
|
||||
if topic == 152 then -- State
|
||||
local num = math.min(payload[1], 2)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
nvm.button = nvm.button or {}
|
||||
return 0, nvm.button[num] and {1} or {0}
|
||||
else
|
||||
return 2, ""
|
||||
end
|
||||
end,
|
||||
}
|
||||
)
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:ta4_button_2x",
|
||||
recipe = {
|
||||
{"", "", ""},
|
||||
{"", "techage:ta4_button_off", "techage:ta4_button_off"},
|
||||
{"", "", ""},
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:ta4_button_off 2",
|
||||
recipe = {
|
||||
{"", "", ""},
|
||||
{"", "techage:ta4_button_2x", ""},
|
||||
{"", "", ""},
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,364 @@
|
||||
--[[
|
||||
|
||||
TechAge
|
||||
=======
|
||||
|
||||
Copyright (C) 2017-2021 Joachim Stolberg
|
||||
|
||||
AGPL v3
|
||||
See LICENSE.txt for more information
|
||||
|
||||
TA4 Logic fourfold button
|
||||
|
||||
]]--
|
||||
|
||||
-- for lazy programmers
|
||||
local M = minetest.get_meta
|
||||
local S = techage.S
|
||||
local logic = techage.logic
|
||||
|
||||
local function get_button_num(pos, clicker, pointed_thing)
|
||||
-- use the node behind the button to get better results
|
||||
if clicker and pointed_thing then
|
||||
local offs = vector.subtract(pointed_thing.under, pointed_thing.above)
|
||||
pointed_thing.under = vector.add(pointed_thing.under, offs)
|
||||
pointed_thing.above = vector.add(pointed_thing.above, offs)
|
||||
local pos1 = minetest.pointed_thing_to_face_pos(clicker, pointed_thing)
|
||||
local y = pos1.y - pos.y
|
||||
|
||||
if y < -0.3 then
|
||||
return 4
|
||||
elseif y < -0.03 and y > -0.22 then
|
||||
return 3
|
||||
elseif y > 0.03 and y < 0.22 then
|
||||
return 2
|
||||
elseif y > 0.3 then
|
||||
return 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local WRENCH_MENU = {
|
||||
{
|
||||
type = "dropdown",
|
||||
choices = "button,switch",
|
||||
name = "type",
|
||||
label = S("Type"),
|
||||
tooltip = S("Momentary button or on/off switch"),
|
||||
default = "1",
|
||||
},
|
||||
{
|
||||
type = "ascii",
|
||||
name = "label1",
|
||||
label = S("Label") .. " 1",
|
||||
tooltip = S("Label for the button"),
|
||||
default = "1",
|
||||
},
|
||||
{
|
||||
type = "numbers",
|
||||
name = "dest_number1",
|
||||
label = S("Number") .. " 1",
|
||||
tooltip = S("Destination block number"),
|
||||
default = "",
|
||||
check = techage.check_numbers,
|
||||
},
|
||||
{
|
||||
type = "ascii",
|
||||
name = "command1",
|
||||
label = S("Command") .. " 1",
|
||||
tooltip = S("Command to be sent (ignored for switches)"),
|
||||
default = "1",
|
||||
},
|
||||
{
|
||||
type = "ascii",
|
||||
name = "label2",
|
||||
label = S("Label") .. " 2",
|
||||
tooltip = S("Label for the button"),
|
||||
default = "1",
|
||||
},
|
||||
{
|
||||
type = "numbers",
|
||||
name = "dest_number2",
|
||||
label = S("Number") .. " 2",
|
||||
tooltip = S("Destination block number"),
|
||||
default = "",
|
||||
check = techage.check_numbers,
|
||||
},
|
||||
{
|
||||
type = "ascii",
|
||||
name = "command2",
|
||||
label = S("Command") .. " 2",
|
||||
tooltip = S("Command to be sent (ignored for switches)"),
|
||||
default = "2",
|
||||
},
|
||||
{
|
||||
type = "ascii",
|
||||
name = "label3",
|
||||
label = S("Label") .. " 3",
|
||||
tooltip = S("Label for the button"),
|
||||
default = "1",
|
||||
},
|
||||
{
|
||||
type = "numbers",
|
||||
name = "dest_number3",
|
||||
label = S("Number") .. " 3",
|
||||
tooltip = S("Destination block number"),
|
||||
default = "",
|
||||
check = techage.check_numbers,
|
||||
},
|
||||
{
|
||||
type = "ascii",
|
||||
name = "command3",
|
||||
label = S("Command") .. " 3",
|
||||
tooltip = S("Command to be sent (ignored for switches)"),
|
||||
default = "3",
|
||||
},
|
||||
{
|
||||
type = "ascii",
|
||||
name = "label4",
|
||||
label = S("Label") .. " 4",
|
||||
tooltip = S("Label for the button"),
|
||||
default = "1",
|
||||
},
|
||||
{
|
||||
type = "numbers",
|
||||
name = "dest_number4",
|
||||
label = S("Number") .. " 4",
|
||||
tooltip = S("Destination block number"),
|
||||
default = "",
|
||||
check = techage.check_numbers,
|
||||
},
|
||||
{
|
||||
type = "ascii",
|
||||
name = "command4",
|
||||
label = S("Command") .. " 4",
|
||||
tooltip = S("Command to be sent (ignored for switches)"),
|
||||
default = "4",
|
||||
},
|
||||
{
|
||||
type = "dropdown",
|
||||
choices = "private,protected,public",
|
||||
name = "access",
|
||||
label = S("Access"),
|
||||
tooltip = S("Button protection"),
|
||||
default = "8",
|
||||
},
|
||||
}
|
||||
|
||||
local function send_cmnd(pos, num, cmd)
|
||||
local meta = M(pos)
|
||||
local own_num = meta:get_string("node_number")
|
||||
local dest = meta:get_string("dest_number" .. num)
|
||||
local command, payload = cmd, nil
|
||||
if not cmd then
|
||||
local s = meta:get_string("command" .. num)
|
||||
command, payload = unpack(string.split(s, " ", false, 1))
|
||||
end
|
||||
local owner = meta:get_string("owner")
|
||||
if techage.check_numbers(dest, owner) then
|
||||
techage.send_multi(own_num, dest, command, payload)
|
||||
end
|
||||
end
|
||||
|
||||
local function button_update(pos, objref)
|
||||
local meta = M(pos)
|
||||
pos = vector.round(pos)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
nvm.button = nvm.button or {}
|
||||
local tbl = {meta:get_string("label1"), " ", meta:get_string("label2"), " ", meta:get_string("label3"), " ", meta:get_string("label4")}
|
||||
local text = "< " .. table.concat(tbl, "\n< ")
|
||||
local texture = lcdlib.make_multiline_texture("default", text, 96, 96, 7, "top", "#000", 6)
|
||||
|
||||
if nvm.button[1] then
|
||||
texture = texture .. "^techage_smartline_button_4x_on1.png"
|
||||
end
|
||||
if nvm.button[2] then
|
||||
texture = texture .. "^techage_smartline_button_4x_on2.png"
|
||||
end
|
||||
if nvm.button[3] then
|
||||
texture = texture .. "^techage_smartline_button_4x_on3.png"
|
||||
end
|
||||
if nvm.button[4] then
|
||||
texture = texture .. "^techage_smartline_button_4x_on4.png"
|
||||
end
|
||||
objref:set_properties({ textures = {texture}, visual_size = {x=1, y=1} })
|
||||
end
|
||||
|
||||
local function switch_off(pos, num)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
nvm.button = nvm.button or {}
|
||||
nvm.button[num] = nil
|
||||
lcdlib.update_entities(pos)
|
||||
end
|
||||
|
||||
local function switch_on(pos, num)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
nvm.button = nvm.button or {}
|
||||
nvm.button[num] = true
|
||||
lcdlib.update_entities(pos)
|
||||
end
|
||||
|
||||
local lcd_box = {-8/16, -8/16, 7.75/16, 8/16, 8/16, 8/16}
|
||||
|
||||
local function can_access(pos, player)
|
||||
local meta = M(pos)
|
||||
local playername = player:get_player_name()
|
||||
local access = meta:get_string("access")
|
||||
local owner = meta:get_string("owner")
|
||||
local protected = minetest.is_protected(pos, playername)
|
||||
|
||||
if access == "private" and playername ~= owner then
|
||||
return false
|
||||
elseif access == "protected" and protected then
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
minetest.register_node("techage:ta4_button_4x", {
|
||||
description = S("TA4 4x Button"),
|
||||
inventory_image = 'techage_smartline_button_4x.png',
|
||||
tiles = {'techage_smartline_button_4x.png'},
|
||||
drawtype = "nodebox",
|
||||
paramtype = "light",
|
||||
use_texture_alpha = "clip",
|
||||
sunlight_propagates = true,
|
||||
paramtype2 = "facedir",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = lcd_box,
|
||||
},
|
||||
light_source = 6,
|
||||
|
||||
display_entities = {
|
||||
["techage:display_entity"] = { depth = 0.48,
|
||||
on_display_update = button_update},
|
||||
},
|
||||
|
||||
after_place_node = function(pos, placer)
|
||||
local number = techage.add_node(pos, "techage:ta4_button_4x")
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("node_number", number)
|
||||
meta:set_string("owner", placer:get_player_name())
|
||||
meta:set_string("infotext", "TA4 4x Button " .. number)
|
||||
meta:set_string("type", "button")
|
||||
meta:set_string("label1", "B1")
|
||||
meta:set_string("label2", "B2")
|
||||
meta:set_string("label3", "B3")
|
||||
meta:set_string("label4", "B4")
|
||||
lcdlib.update_entities(pos)
|
||||
end,
|
||||
|
||||
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
|
||||
if clicker and clicker:is_player() then
|
||||
-- Check access settings
|
||||
if not can_access(pos, clicker) then
|
||||
return
|
||||
end
|
||||
|
||||
local num = get_button_num(pos, clicker, pointed_thing)
|
||||
if num then
|
||||
local typ = M(pos):get_string("type")
|
||||
if typ == "switch" then
|
||||
local nvm = techage.get_nvm(pos)
|
||||
nvm.button = nvm.button or {}
|
||||
if nvm.button[num] then
|
||||
switch_off(pos, num)
|
||||
logic.guarded_action(pos, send_cmnd, pos, num, "off")
|
||||
else
|
||||
switch_on(pos, num)
|
||||
logic.guarded_action(pos, send_cmnd, pos, num, "on")
|
||||
end
|
||||
else
|
||||
switch_on(pos, num)
|
||||
logic.guarded_action(pos, send_cmnd, pos, num)
|
||||
minetest.after(0.5, switch_off, pos, num)
|
||||
end
|
||||
minetest.sound_play("techage_button", {
|
||||
pos = pos,
|
||||
gain = 0.5,
|
||||
max_hear_distance = 5,
|
||||
})
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
ta_after_formspec = function(pos, fields, playername)
|
||||
lcdlib.update_entities(pos)
|
||||
end,
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
end,
|
||||
|
||||
ta3_formspec = WRENCH_MENU,
|
||||
on_place = lcdlib.on_place,
|
||||
on_construct = lcdlib.on_construct,
|
||||
on_destruct = lcdlib.on_destruct,
|
||||
on_rotate = lcdlib.on_rotate,
|
||||
groups = {cracky=2, crumbly=2},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
})
|
||||
|
||||
techage.register_node({"techage:ta4_button_4x"}, {
|
||||
on_recv_message = function(pos, src, topic, payload)
|
||||
local num = math.min(tonumber(payload) or 0, 4)
|
||||
if topic == "on" then
|
||||
switch_on(pos, num)
|
||||
logic.guarded_action(pos, send_cmnd, pos, num)
|
||||
return true
|
||||
elseif topic == "off" then
|
||||
switch_off(pos, num)
|
||||
return true
|
||||
elseif topic == "state" then
|
||||
local nvm = techage.get_nvm(pos)
|
||||
nvm.button = nvm.button or {}
|
||||
return nvm.button[num] == true
|
||||
else
|
||||
return "unsupported"
|
||||
end
|
||||
end,
|
||||
on_beduino_receive_cmnd = function(pos, src, topic, payload)
|
||||
local num = math.min(payload[1], 4)
|
||||
if topic == 23 and payload[2] == 1 then
|
||||
switch_on(pos, num)
|
||||
logic.guarded_action(pos, send_cmnd, pos, num)
|
||||
return 0
|
||||
elseif topic == 23 and payload[2] == 0 then
|
||||
switch_off(pos, num)
|
||||
return 0
|
||||
else
|
||||
return 2
|
||||
end
|
||||
end,
|
||||
on_beduino_request_data = function(pos, src, topic, payload)
|
||||
if topic == 152 then -- State
|
||||
local num = math.min(payload[1], 4)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
nvm.button = nvm.button or {}
|
||||
return 0, nvm.button[num] and {1} or {0}
|
||||
else
|
||||
return 2, ""
|
||||
end
|
||||
end,
|
||||
}
|
||||
)
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:ta4_button_4x",
|
||||
recipe = {
|
||||
{"", "techage:ta4_button_off", "techage:ta4_button_off"},
|
||||
{"", "techage:ta4_button_off", "techage:ta4_button_off"},
|
||||
{"", "", ""},
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:ta4_button_off 4",
|
||||
recipe = {
|
||||
{"", "", ""},
|
||||
{"", "techage:ta4_button_4x", ""},
|
||||
{"", "", ""},
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,182 @@
|
||||
--[[
|
||||
|
||||
TechAge
|
||||
=======
|
||||
|
||||
Copyright (C) 2019-2022 Joachim Stolberg
|
||||
|
||||
AGPL v3
|
||||
See LICENSE.txt for more information
|
||||
|
||||
Cart Detector/Starter
|
||||
|
||||
]]--
|
||||
|
||||
-- for lazy programmers
|
||||
local M = minetest.get_meta
|
||||
local S = techage.S
|
||||
local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end
|
||||
|
||||
local logic = techage.logic
|
||||
local CYCLE_TIME = 2
|
||||
|
||||
local function switch_off(pos)
|
||||
local node = minetest.get_node(pos)
|
||||
if node.name == "techage:ta3_cartdetector_on" then
|
||||
logic.swap_node(pos, "techage:ta3_cartdetector_off")
|
||||
logic.send_off(pos, M(pos))
|
||||
end
|
||||
end
|
||||
|
||||
local function switch_on(pos)
|
||||
logic.swap_node(pos, "techage:ta3_cartdetector_on")
|
||||
if logic.send_on(pos, M(pos)) then
|
||||
minetest.after(1, switch_off, pos)
|
||||
end
|
||||
end
|
||||
|
||||
local function node_timer(pos)
|
||||
if minecart.is_cart_available(pos, nil, 1.5) then
|
||||
switch_on(pos)
|
||||
else
|
||||
switch_off(pos)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local function formspec(meta)
|
||||
local numbers = meta:get_string("numbers") or ""
|
||||
return "size[7.5,4]"..
|
||||
default.gui_bg..
|
||||
default.gui_bg_img..
|
||||
default.gui_slots..
|
||||
"field[0.5,1;7,1;numbers;"..S("Insert destination node number(s)")..";"..numbers.."]" ..
|
||||
"button_exit[2,2.2;3,1;accept;"..S("accept").."]"
|
||||
end
|
||||
|
||||
local function on_receive_fields(pos, formname, fields, player)
|
||||
if minetest.is_protected(pos, player:get_player_name()) then
|
||||
return
|
||||
end
|
||||
|
||||
local meta = minetest.get_meta(pos)
|
||||
if fields.accept then
|
||||
if techage.check_numbers(fields.numbers, player:get_player_name()) then
|
||||
meta:set_string("numbers", fields.numbers)
|
||||
logic.infotext(M(pos), S("TA3 Cart Detector"))
|
||||
end
|
||||
meta:set_string("formspec", formspec(meta))
|
||||
end
|
||||
end
|
||||
|
||||
local function techage_set_numbers(pos, numbers, player_name)
|
||||
local meta = M(pos)
|
||||
local res = logic.set_numbers(pos, numbers, player_name, S("TA3 Cart Detector"))
|
||||
meta:set_string("formspec", formspec(meta))
|
||||
return res
|
||||
end
|
||||
|
||||
local function after_dig_node(pos, oldnode, oldmetadata, digger)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
end
|
||||
|
||||
minetest.register_node("techage:ta3_cartdetector_off", {
|
||||
description = S("TA3 Cart Detector"),
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png^techage_appl_arrow.png^[transformR90",
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_cartdetector.png",
|
||||
},
|
||||
after_place_node = function(pos, placer)
|
||||
local meta = M(pos)
|
||||
logic.after_place_node(pos, placer, "techage:ta3_cartdetector_off", S("TA3 Player Detector"))
|
||||
logic.infotext(meta, S("TA3 Cart Detector"))
|
||||
meta:set_string("formspec", formspec(meta))
|
||||
minetest.get_node_timer(pos):start(CYCLE_TIME)
|
||||
end,
|
||||
|
||||
on_receive_fields = on_receive_fields,
|
||||
on_timer = node_timer,
|
||||
techage_set_numbers = techage_set_numbers,
|
||||
after_dig_node = after_dig_node,
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy=2, cracky=2, crumbly=2},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
})
|
||||
|
||||
minetest.register_node("techage:ta3_cartdetector_on", {
|
||||
description = "TA3 Cart Detector",
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png^techage_appl_arrow.png^[transformR90",
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_cartdetector_on.png",
|
||||
},
|
||||
on_receive_fields = on_receive_fields,
|
||||
on_timer = node_timer,
|
||||
techage_set_numbers = techage_set_numbers,
|
||||
after_dig_node = after_dig_node,
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy=2, cracky=2, crumbly=2, not_in_creative_inventory=1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
drop = "techage:ta3_cartdetector_off"
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:ta3_cartdetector_off",
|
||||
recipe = {
|
||||
{"", "group:wood", "default:mese_crystal"},
|
||||
{"", "default:copper_ingot", "techage:vacuum_tube"},
|
||||
{"", "group:wood", "basic_materials:motor"},
|
||||
},
|
||||
})
|
||||
|
||||
techage.register_node({"techage:ta3_cartdetector_off", "techage:ta3_cartdetector_on"}, {
|
||||
on_recv_message = function(pos, src, topic, payload)
|
||||
if topic == "on" then
|
||||
local node = minetest.get_node(pos)
|
||||
local dir = minetest.facedir_to_dir(node.param2)
|
||||
minecart.punch_cart(pos, nil, 1.6, dir)
|
||||
elseif topic == "state" then
|
||||
local node = techage.get_node_lvm(pos)
|
||||
if node.name == "techage:ta3_cartdetector_on" then
|
||||
return "on"
|
||||
else
|
||||
return "off"
|
||||
end
|
||||
else
|
||||
return "unsupported"
|
||||
end
|
||||
end,
|
||||
on_beduino_receive_cmnd = function(pos, src, topic, payload)
|
||||
if topic == 1 then
|
||||
local node = minetest.get_node(pos)
|
||||
local dir = minetest.facedir_to_dir(node.param2)
|
||||
minecart.punch_cart(pos, nil, 1.6, dir)
|
||||
return 0
|
||||
else
|
||||
return 2
|
||||
end
|
||||
end,
|
||||
on_beduino_request_data = function(pos, src, topic, payload)
|
||||
if topic == 142 then -- Binary State
|
||||
local node = techage.get_node_lvm(pos)
|
||||
if node.name == "techage:ta3_cartdetector_on" then
|
||||
return 0, {1}
|
||||
else
|
||||
return 0, {0}
|
||||
end
|
||||
else
|
||||
return 2, ""
|
||||
end
|
||||
end,
|
||||
on_node_load = function(pos)
|
||||
minetest.get_node_timer(pos):start(CYCLE_TIME)
|
||||
end,
|
||||
})
|
||||
|
||||
-- Register default cart in addition
|
||||
minecart.tEntityNames["carts:cart"] = true
|
||||
@@ -0,0 +1,232 @@
|
||||
--[[
|
||||
|
||||
TechAge
|
||||
=======
|
||||
|
||||
Copyright (C) 2019-2023 Joachim Stolberg
|
||||
|
||||
AGPL v3
|
||||
See LICENSE.txt for more information
|
||||
|
||||
TA4 Energy storage charge detector
|
||||
|
||||
]]--
|
||||
|
||||
-- for lazy programmers
|
||||
local M = minetest.get_meta
|
||||
local S = techage.S
|
||||
local Cable = techage.ElectricCable
|
||||
local power = networks.power
|
||||
|
||||
local logic = techage.logic
|
||||
local CYCLE_TIME = 8
|
||||
local DESCR = S("TA4 Energy Storage Charge Detector")
|
||||
|
||||
local WRENCH_MENU = {
|
||||
{
|
||||
type = "numbers",
|
||||
name = "numbers",
|
||||
label = S("Number"),
|
||||
tooltip = S("Destination block number"),
|
||||
default = "",
|
||||
check = techage.check_numbers,
|
||||
},
|
||||
{
|
||||
type = "dropdown",
|
||||
choices = "10%,20%,30%,40%,50%,60%,70%,80%,90%",
|
||||
name = "switch_point",
|
||||
label = S("Switch point"),
|
||||
tooltip = S("Storage charge level switch point"),
|
||||
default = "50",
|
||||
values = {10, 20, 30, 40, 50, 60, 70, 80, 90}
|
||||
},
|
||||
{
|
||||
type = "ascii",
|
||||
name = "command1",
|
||||
label = '"<" ' .. S("Command"),
|
||||
tooltip = S("Command to send when the energy storage charge\nlevel falls below the specified switch point"),
|
||||
default = "off",
|
||||
},
|
||||
{
|
||||
type = "ascii",
|
||||
name = "command2",
|
||||
label = '">" ' .. S("Command"),
|
||||
tooltip = S("Command to send when the energy storage charge\nlevel rises above the specified switch point"),
|
||||
default = "on",
|
||||
},
|
||||
}
|
||||
|
||||
local function switch_on(pos)
|
||||
if logic.swap_node(pos, "techage:ta4_chargedetector_on") then
|
||||
logic.send_cmnd(pos, "command2", "on")
|
||||
end
|
||||
end
|
||||
|
||||
local function switch_off(pos)
|
||||
if logic.swap_node(pos, "techage:ta4_chargedetector_off") then
|
||||
logic.send_cmnd(pos, "command1", "off")
|
||||
end
|
||||
end
|
||||
|
||||
local function switch_point(pos)
|
||||
local mem = techage.get_mem(pos)
|
||||
if not mem.switch_point then
|
||||
mem.switch_point = tonumber(M(pos):get_string("switch_point")) or 50
|
||||
end
|
||||
return mem.switch_point
|
||||
end
|
||||
|
||||
local function above_switch_point(pos)
|
||||
local outdir = M(pos):get_int("outdir")
|
||||
local value = networks.power.get_storage_percent(pos, Cable, outdir)
|
||||
return value > switch_point(pos)
|
||||
end
|
||||
|
||||
local function techage_set_numbers(pos, numbers, player_name)
|
||||
local res = logic.set_numbers(pos, numbers, player_name, DESCR)
|
||||
return res
|
||||
end
|
||||
|
||||
local function after_dig_node(pos, oldnode, oldmetadata, digger)
|
||||
Cable:after_dig_node(pos)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
techage.del_mem(pos)
|
||||
end
|
||||
|
||||
local function ta_after_formspec(pos, fields, playername)
|
||||
local mem = techage.get_mem(pos)
|
||||
mem.switch_point = nil
|
||||
end
|
||||
|
||||
minetest.register_node("techage:ta4_chargedetector_off", {
|
||||
description = DESCR,
|
||||
inventory_image = 'techage_charge_detector_inv.png',
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"techage_smartline.png",
|
||||
"techage_smartline.png",
|
||||
"techage_smartline.png",
|
||||
"techage_smartline.png",
|
||||
"techage_smartline.png",
|
||||
"techage_smartline.png^techage_charge_detector_off.png",
|
||||
},
|
||||
|
||||
drawtype = "nodebox",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{ -6/32, -6/32, 14/32, 6/32, 6/32, 16/32},
|
||||
},
|
||||
},
|
||||
after_place_node = function(pos, placer)
|
||||
local meta = M(pos)
|
||||
logic.after_place_node(pos, placer, "techage:ta4_chargedetector_off", DESCR)
|
||||
logic.infotext(meta, DESCR)
|
||||
M(pos):set_int("outdir", networks.side_to_outdir(pos, "B"))
|
||||
Cable:after_place_node(pos)
|
||||
minetest.get_node_timer(pos):start(CYCLE_TIME)
|
||||
end,
|
||||
|
||||
on_timer = function (pos, elapsed)
|
||||
if not above_switch_point(pos) then
|
||||
switch_on(pos)
|
||||
end
|
||||
return true
|
||||
end,
|
||||
|
||||
techage_set_numbers = techage_set_numbers,
|
||||
after_dig_node = after_dig_node,
|
||||
ta_after_formspec = ta_after_formspec,
|
||||
ta4_formspec = WRENCH_MENU,
|
||||
paramtype = "light",
|
||||
sunlight_propagates = true,
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy=2, cracky=2, crumbly=2},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
})
|
||||
|
||||
minetest.register_node("techage:ta4_chargedetector_on", {
|
||||
description = DESCR,
|
||||
inventory_image = 'techage_charge_detector_inv.png',
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"techage_smartline.png",
|
||||
"techage_smartline.png",
|
||||
"techage_smartline.png",
|
||||
"techage_smartline.png",
|
||||
"techage_smartline.png",
|
||||
"techage_smartline.png^techage_charge_detector_on.png",
|
||||
},
|
||||
|
||||
drawtype = "nodebox",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{ -6/32, -6/32, 14/32, 6/32, 6/32, 16/32},
|
||||
},
|
||||
},
|
||||
on_timer = function (pos, elapsed)
|
||||
if above_switch_point(pos) then
|
||||
switch_off(pos)
|
||||
end
|
||||
return true
|
||||
end,
|
||||
|
||||
techage_set_numbers = techage_set_numbers,
|
||||
after_dig_node = after_dig_node,
|
||||
ta_after_formspec = ta_after_formspec,
|
||||
ta4_formspec = WRENCH_MENU,
|
||||
paramtype = "light",
|
||||
sunlight_propagates = true,
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy=2, cracky=2, crumbly=2, not_in_creative_inventory=1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
drop = "techage:ta4_chargedetector_off"
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:ta4_chargedetector_off",
|
||||
recipe = {
|
||||
{"", "", ""},
|
||||
{"basic_materials:plastic_sheet", "dye:blue", "techage:aluminum"},
|
||||
{"techage:ta4_wlanchip", "techage:electric_cableS", "default:copper_ingot"},
|
||||
},
|
||||
})
|
||||
|
||||
techage.register_node({
|
||||
"techage:ta4_chargedetector_off", "techage:ta4_chargedetector_on"
|
||||
}, {
|
||||
on_recv_message = function(pos, src, topic, payload)
|
||||
if topic == "state" then
|
||||
local node = techage.get_node_lvm(pos)
|
||||
if node.name == "techage:ta4_chargedetector_on" then
|
||||
return "on"
|
||||
else
|
||||
return "off"
|
||||
end
|
||||
else
|
||||
return "unsupported"
|
||||
end
|
||||
end,
|
||||
on_beduino_request_data = function(pos, src, topic, payload)
|
||||
if topic == 142 then -- Binary State
|
||||
local node = techage.get_node_lvm(pos)
|
||||
if node.name == "techage:ta4_chargedetector_on" then
|
||||
return 0, {1}
|
||||
else
|
||||
return 0, {0}
|
||||
end
|
||||
else
|
||||
return 2, ""
|
||||
end
|
||||
end,
|
||||
on_node_load = function(pos)
|
||||
minetest.get_node_timer(pos):start(CYCLE_TIME)
|
||||
end,
|
||||
}
|
||||
)
|
||||
|
||||
power.register_nodes({"techage:ta4_chargedetector_off", "techage:ta4_chargedetector_on"}, Cable, "con", {"B"})
|
||||
|
||||
@@ -0,0 +1,225 @@
|
||||
--[[
|
||||
|
||||
TechAge
|
||||
=======
|
||||
|
||||
Copyright (C) 2017-2022 Joachim Stolberg
|
||||
|
||||
AGPL v3
|
||||
See LICENSE.txt for more information
|
||||
|
||||
TA4 Collector
|
||||
Collects states from other nodes, acting as a state concentrator.
|
||||
|
||||
]]--
|
||||
|
||||
-- for lazy programmers
|
||||
local M = minetest.get_meta
|
||||
local S = techage.S
|
||||
local NDEF = function(pos) return (minetest.registered_nodes[techage.get_node_lvm(pos).name] or {}) end
|
||||
local logic = techage.logic
|
||||
|
||||
local CYCLE_TIME = 1
|
||||
|
||||
-- The numbering seems strange here, but I had to add the "running" state
|
||||
-- afterwards without changing the behavior of the block.
|
||||
local tStates = {stopped = 0, running = 1, standby = 2, blocked = 3, fault = 4, defect = 5}
|
||||
local tDropdownPos = {["1 standby"] = 1, ["2 blocked"] = 2, ["3 fault"] = 3, ["4 defect"] = 4}
|
||||
local lStates = {[0] = "stopped", "running", "standby", "blocked", "fault", "defect"}
|
||||
local tDropdownPos = {["1 standby"] = 1, ["2 blocked"] = 2, ["3 nopower"] = 3, ["4 fault"] = 4}
|
||||
local TaStates = {running = 1, blocked = 2, standby = 3, nopower = 4, fault = 5, stopped = 6}
|
||||
|
||||
local function formspec(nvm, meta)
|
||||
nvm.poll_numbers = nvm.poll_numbers or {}
|
||||
local poll_numbers = table.concat(nvm.poll_numbers, " ")
|
||||
local event_number = meta:get_string("event_number")
|
||||
local dropdown_pos = meta:get_int("dropdown_pos")
|
||||
if dropdown_pos == 0 then dropdown_pos = 1 end
|
||||
|
||||
return "size[9,6]"..
|
||||
default.gui_bg..
|
||||
default.gui_bg_img..
|
||||
default.gui_slots..
|
||||
"field[0.3,0.6;9,1;poll_numbers;"..S("Node numbers to read the states from")..":;"..poll_numbers.."]" ..
|
||||
"field[0.3,2;9,1;event_number;"..S("Node number to send the events to")..":;"..event_number.."]" ..
|
||||
"label[1.3,2.8;"..S("Send an event if state is equal or larger than")..":]"..
|
||||
"dropdown[1.2,3.4;7,4;severity;1 standby,2 blocked,3 nopower,4 fault;"..dropdown_pos.."]"..
|
||||
"button_exit[3,5;2,1;exit;Save]"
|
||||
end
|
||||
|
||||
|
||||
local function send_event(nvm, meta)
|
||||
local event_number = meta:get_string("event_number")
|
||||
if event_number ~= "" then
|
||||
local severity = meta:get_int("dropdown_pos")
|
||||
local own_number = meta:get_string("own_number")
|
||||
if nvm.common_state > severity then
|
||||
techage.send_multi(own_number, event_number, "on")
|
||||
else
|
||||
techage.send_multi(own_number, event_number, "off")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function request_state(nvm, meta)
|
||||
local number = nvm.poll_numbers and nvm.poll_numbers[nvm.idx]
|
||||
if number then
|
||||
local own_number = meta:get_string("own_number")
|
||||
local state = techage.send_single(own_number, number, "state", nil)
|
||||
if state then
|
||||
state = tStates[state] or 0
|
||||
nvm.common_state = math.max(nvm.common_state, state)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function on_timer(pos,elapsed)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
nvm.idx = (nvm.idx or 0) + 1
|
||||
nvm.common_state = nvm.common_state or 0
|
||||
|
||||
if not nvm.poll_numbers then
|
||||
local own_number = meta:get_string("own_number")
|
||||
meta:set_string("infotext", S("TA4 State Collector").." "..own_number..": stopped")
|
||||
nvm.common_state = 0
|
||||
nvm.idx = 1
|
||||
return false
|
||||
end
|
||||
|
||||
if nvm.idx > #nvm.poll_numbers then
|
||||
nvm.idx = 1
|
||||
if nvm.stored_state ~= nvm.common_state then
|
||||
send_event(nvm, meta)
|
||||
local own_number = meta:get_string("own_number")
|
||||
meta:set_string("infotext", S("TA4 State Collector").." "..own_number..': "'..lStates[nvm.common_state]..'"')
|
||||
nvm.stored_state = nvm.common_state
|
||||
end
|
||||
nvm.common_state = 0 -- reset for the next round
|
||||
end
|
||||
|
||||
request_state(nvm, meta)
|
||||
return true
|
||||
end
|
||||
|
||||
minetest.register_node("techage:ta4_collector", {
|
||||
description = S("TA4 State Collector"),
|
||||
inventory_image = "techage_smartline_collector_inv.png",
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"techage_smartline.png",
|
||||
"techage_smartline.png",
|
||||
"techage_smartline.png",
|
||||
"techage_smartline.png",
|
||||
"techage_smartline.png",
|
||||
"techage_smartline.png^techage_smartline_collector.png",
|
||||
},
|
||||
|
||||
drawtype = "nodebox",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{ -6/32, -6/32, 14/32, 6/32, 6/32, 16/32},
|
||||
},
|
||||
},
|
||||
|
||||
after_place_node = function(pos, placer)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local own_number = techage.add_node(pos, "techage:ta4_collector")
|
||||
meta:set_string("own_number", own_number)
|
||||
meta:set_string("formspec", formspec(nvm, meta))
|
||||
meta:set_string("infotext", S("TA4 State Collector").." "..own_number)
|
||||
meta:set_string("owner", placer:get_player_name())
|
||||
end,
|
||||
|
||||
on_receive_fields = function(pos, formname, fields, player)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local owner = meta:get_string("owner")
|
||||
if owner ~= player:get_player_name() then
|
||||
return
|
||||
end
|
||||
|
||||
local nvm = techage.get_nvm(pos)
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
local own_number = meta:get_string("own_number")
|
||||
|
||||
if fields.quit == "true" and fields.poll_numbers then
|
||||
if techage.check_numbers(fields.event_number, player:get_player_name()) then
|
||||
meta:set_string("event_number", fields.event_number)
|
||||
end
|
||||
if techage.check_numbers(fields.poll_numbers, player:get_player_name()) then
|
||||
nvm.poll_numbers = string.split(fields.poll_numbers, " ")
|
||||
nvm.idx = 0
|
||||
if not timer:is_started() then
|
||||
timer:start(CYCLE_TIME)
|
||||
end
|
||||
meta:set_string("infotext", S("TA4 State Collector").." "..own_number..": running")
|
||||
else
|
||||
if timer:is_started() then
|
||||
timer:stop()
|
||||
end
|
||||
meta:set_string("infotext", S("TA4 State Collector").." "..own_number..": stopped")
|
||||
nvm.common_state = 0
|
||||
nvm.stored_state = 0
|
||||
end
|
||||
if fields.severity then
|
||||
meta:set_int("dropdown_pos", tDropdownPos[fields.severity])
|
||||
end
|
||||
meta:set_string("formspec", formspec(nvm, meta))
|
||||
end
|
||||
end,
|
||||
|
||||
techage_set_numbers = function(pos, numbers, player_name)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
local meta = M(pos)
|
||||
local res = logic.set_numbers(pos, numbers, player_name, NDEF(pos).description)
|
||||
meta:set_string("formspec", formspec(nvm, meta))
|
||||
return res
|
||||
end,
|
||||
|
||||
on_timer = on_timer,
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
end,
|
||||
|
||||
paramtype = "light",
|
||||
sunlight_propagates = true,
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy=2, cracky=2, crumbly=2},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
})
|
||||
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:ta4_collector",
|
||||
recipe = {
|
||||
{"", "techage:aluminum", "dye:blue"},
|
||||
{"", "default:mese_crystal_fragment", "techage:ta4_wlanchip"},
|
||||
},
|
||||
})
|
||||
|
||||
techage.register_node({"techage:ta4_collector"}, {
|
||||
on_recv_message = function(pos, src, topic, payload)
|
||||
if topic == "state" then
|
||||
local nvm = techage.get_nvm(pos)
|
||||
return lStates[nvm.stored_state or 0]
|
||||
else
|
||||
return "unsupported"
|
||||
end
|
||||
end,
|
||||
on_beduino_request_data = function(pos, src, topic, payload)
|
||||
if topic == 129 then
|
||||
local nvm = techage.get_nvm(pos)
|
||||
return 0, {TaStates[lStates[nvm.stored_state or 0]]}
|
||||
else
|
||||
return 2, ""
|
||||
end
|
||||
end,
|
||||
on_node_load = function(pos)
|
||||
minetest.get_node_timer(pos):start(CYCLE_TIME)
|
||||
end,
|
||||
})
|
||||
@@ -0,0 +1,182 @@
|
||||
--[[
|
||||
|
||||
TechAge
|
||||
=======
|
||||
|
||||
Copyright (C) 2017-2023 Joachim Stolberg
|
||||
|
||||
AGPL v3
|
||||
See LICENSE.txt for more information
|
||||
|
||||
TA3 Commannd Converter
|
||||
|
||||
]]--
|
||||
|
||||
-- for lazy programmers
|
||||
local M = minetest.get_meta
|
||||
local S = techage.S
|
||||
local DESCR = S("TA3 Command Converter")
|
||||
|
||||
local logic = techage.logic
|
||||
|
||||
local sDelay = "0,1,2,3,4,5,7,10,15,20,30,45,60"
|
||||
|
||||
local function switch_on(pos)
|
||||
logic.swap_node(pos, "techage:ta3_command_converter_on")
|
||||
logic.send_cmnd(pos, "command_on", "")
|
||||
end
|
||||
|
||||
local function switch_off(pos)
|
||||
logic.swap_node(pos, "techage:ta3_command_converter_off")
|
||||
logic.send_cmnd(pos, "command_off", "")
|
||||
end
|
||||
|
||||
local function formspec(meta)
|
||||
local numbers = meta:get_string("numbers") or ""
|
||||
local command_on = meta:get_string("command_on")
|
||||
local command_off = meta:get_string("command_off")
|
||||
local delay_on = techage.dropdown_index(sDelay, meta:get_string("delay_on"))
|
||||
local delay_off = techage.dropdown_index(sDelay, meta:get_string("delay_off"))
|
||||
|
||||
return "formspec_version[4]size[10,6]"..
|
||||
"box[0.2,0.2;9.6,0.6;#c6e8ff]" ..
|
||||
"label[0.4,0.5;" .. minetest.colorize( "#000000", DESCR) .. "]" ..
|
||||
|
||||
"field[1.0,1.5;8,0.6;numbers;" .. S("Insert destination node number(s)") .. ";" .. numbers .. "]" ..
|
||||
|
||||
"label[0.6,2.7;" .. S("Receive") .. "]" ..
|
||||
"label[2.8,2.7;" .. S("Sent command") .. "]" ..
|
||||
"label[7.34,2.7;" .. S("Send delay (s)") .. "]" ..
|
||||
|
||||
"box[0.5,3.1;1.2,0.6;#888]" ..
|
||||
"label[0.6,3.4;on]" ..
|
||||
"field[2.7,3.1;3.5,0.6;command_on;;" .. command_on .. "]" ..
|
||||
"dropdown[7.2,3.1;2,0.6;delay_on;" .. sDelay .. ";" .. delay_on .. ";false]" ..
|
||||
|
||||
"box[0.5,4.0;1.2,0.6;#888]" ..
|
||||
"label[0.6,4.3;off]" ..
|
||||
"field[2.7,4.0;3.5,0.6;command_off;;" .. command_off .. "]" ..
|
||||
"dropdown[7.2,4.0;2,0.6;delay_off;" .. sDelay .. ";" .. delay_off .. ";false]" ..
|
||||
|
||||
"button_exit[3.5,5.2;3,0.6;exit;" .. S("Save") .. "]"
|
||||
end
|
||||
|
||||
local function techage_set_numbers(pos, numbers, player_name)
|
||||
local meta = M(pos)
|
||||
local res = logic.set_numbers(pos, numbers, player_name, DESCR)
|
||||
meta:set_string("formspec", formspec(meta))
|
||||
return true --res
|
||||
end
|
||||
|
||||
local function after_dig_node(pos, oldnode, oldmetadata, digger)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
techage.del_mem(pos)
|
||||
end
|
||||
|
||||
local function on_receive_fields(pos, formname, fields, player)
|
||||
if minetest.is_protected(pos, player:get_player_name()) then
|
||||
return
|
||||
end
|
||||
|
||||
local meta = minetest.get_meta(pos)
|
||||
if fields.exit and fields.exit ~= "" then
|
||||
if techage.check_numbers(fields.numbers, player:get_player_name()) then
|
||||
meta:set_string("numbers", fields.numbers)
|
||||
logic.infotext(M(pos), DESCR)
|
||||
end
|
||||
meta:set_string("command_on", fields.command_on)
|
||||
meta:set_string("command_off", fields.command_off)
|
||||
meta:set_int("delay_on", fields.delay_on or 0)
|
||||
meta:set_int("delay_off", fields.delay_off or 0)
|
||||
meta:set_string("formspec", formspec(meta))
|
||||
elseif fields.exit == "close" then
|
||||
meta:set_string("formspec", formspec(meta))
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_node("techage:ta3_command_converter_off", {
|
||||
description = DESCR,
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_command_converter.png",
|
||||
},
|
||||
after_place_node = function(pos, placer)
|
||||
local meta = M(pos)
|
||||
logic.after_place_node(pos, placer, "techage:ta3_command_converter_off", DESCR)
|
||||
logic.infotext(meta, DESCR)
|
||||
meta:set_string("formspec", formspec(meta))
|
||||
end,
|
||||
|
||||
on_timer = function (pos, elapsed)
|
||||
switch_on(pos)
|
||||
end,
|
||||
|
||||
on_receive_fields = on_receive_fields,
|
||||
techage_set_numbers = techage_set_numbers,
|
||||
after_dig_node = after_dig_node,
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy=2, cracky=2, crumbly=2},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
})
|
||||
|
||||
minetest.register_node("techage:ta3_command_converter_on", {
|
||||
description = DESCR,
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_command_converter_on.png",
|
||||
},
|
||||
|
||||
on_timer = function (pos, elapsed)
|
||||
switch_off(pos)
|
||||
end,
|
||||
|
||||
on_receive_fields = on_receive_fields,
|
||||
techage_set_numbers = techage_set_numbers,
|
||||
after_dig_node = after_dig_node,
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy=2, cracky=2, crumbly=2, not_in_creative_inventory=1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
drop = "techage:ta3_command_converter_off"
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:ta3_command_converter_off",
|
||||
recipe = {
|
||||
{"", "group:wood", ""},
|
||||
{"default:mese_crystal_fragment", "default:copper_ingot", "techage:vacuum_tube"},
|
||||
{"", "group:wood", ""},
|
||||
},
|
||||
})
|
||||
|
||||
techage.register_node({
|
||||
"techage:ta3_command_converter_off", "techage:ta3_command_converter_on"
|
||||
}, {
|
||||
on_recv_message = function(pos, src, topic, payload)
|
||||
if topic == "on" then
|
||||
local delay = M(pos):get_int("delay_on") or 0
|
||||
if delay > 0 then
|
||||
minetest.get_node_timer(pos):start(delay)
|
||||
else
|
||||
switch_on(pos)
|
||||
end
|
||||
return true
|
||||
elseif topic == "off" then
|
||||
local delay = M(pos):get_int("delay_off") or 0
|
||||
if delay > 0 then
|
||||
minetest.get_node_timer(pos):start(delay)
|
||||
else
|
||||
switch_off(pos)
|
||||
end
|
||||
return true
|
||||
else
|
||||
return "unsupported"
|
||||
end
|
||||
end,
|
||||
}
|
||||
)
|
||||
@@ -0,0 +1,394 @@
|
||||
--[[
|
||||
|
||||
TechAge
|
||||
=======
|
||||
|
||||
Copyright (C) 2017-2023 Joachim Stolberg
|
||||
|
||||
AGPL v3
|
||||
See LICENSE.txt for more information
|
||||
|
||||
TA3/TA4 Item detector
|
||||
|
||||
]]--
|
||||
|
||||
-- for lazy programmers
|
||||
local M = minetest.get_meta
|
||||
local S = techage.S
|
||||
local NDEF = function(pos) return (minetest.registered_nodes[techage.get_node_lvm(pos).name] or {}) end
|
||||
|
||||
local logic = techage.logic
|
||||
local BLOCKING_TIME = 8 -- seconds
|
||||
local ON_TIME = 1
|
||||
|
||||
local WRENCH_MENU3 = {
|
||||
{
|
||||
type = "dropdown",
|
||||
choices = "1,2,4,6,8,12,16",
|
||||
name = "ontime",
|
||||
label = S("On Time") .. " [s]",
|
||||
tooltip = S("The time between the 'on' and 'off' commands."),
|
||||
default = "1",
|
||||
},
|
||||
{
|
||||
type = "dropdown",
|
||||
choices = "2,4,6,8,12,16,20",
|
||||
name = "blockingtime",
|
||||
label = S("Blocking Time") .. " [s]",
|
||||
tooltip = S("The time after the 'off' command\nuntil the next 'on' command is accepted."),
|
||||
default = "8",
|
||||
},
|
||||
{
|
||||
type = "items",
|
||||
name = "config",
|
||||
label = S("Configured Items"),
|
||||
tooltip = S("Items which generate an 'on' command.\nIf empty, all passed items generate an 'on' command."),
|
||||
size = 4,
|
||||
}
|
||||
}
|
||||
|
||||
local WRENCH_MENU4 = {
|
||||
{
|
||||
type = "dropdown",
|
||||
choices = "1,2,4,6,8,12,16",
|
||||
name = "ontime",
|
||||
label = S("On Time") .. " [s]",
|
||||
tooltip = S("The time between the 'on' and 'off' commands."),
|
||||
default = "1",
|
||||
},
|
||||
{
|
||||
type = "dropdown",
|
||||
choices = "2,4,6,8,12,16,20",
|
||||
name = "blockingtime",
|
||||
label = S("Blocking Time") .. " [s]",
|
||||
tooltip = S("The time after the 'off' command\nuntil the next 'on' command is accepted."),
|
||||
default = "8",
|
||||
},
|
||||
{
|
||||
type = "number",
|
||||
name = "countdown",
|
||||
label = S("Countdown"),
|
||||
tooltip = S("Counts down the number of items passed through\nand only triggers an 'on' command when it reaches zero."),
|
||||
default = "0",
|
||||
},
|
||||
{
|
||||
type = "output",
|
||||
name = "countdown",
|
||||
label = S("Current countdown"),
|
||||
tooltip = S("Current countdown value."),
|
||||
default = "0",
|
||||
},
|
||||
{
|
||||
type = "items",
|
||||
name = "config",
|
||||
label = S("Configured Items"),
|
||||
tooltip = S("Items which generate an 'on' command.\nIf empty, all passed items generate an 'on' command."),
|
||||
size = 4,
|
||||
}
|
||||
}
|
||||
|
||||
local function switch_on(pos)
|
||||
local mem = techage.get_mem(pos)
|
||||
local t = minetest.get_gametime()
|
||||
if t > (mem.time or 0) then
|
||||
local name = techage.get_node_lvm(pos).name
|
||||
if name == "techage:ta3_detector_off" then
|
||||
logic.swap_node(pos, "techage:ta3_detector_on")
|
||||
else
|
||||
logic.swap_node(pos, "techage:ta4_detector_on")
|
||||
end
|
||||
local meta = M(pos)
|
||||
local on_time = math.max(meta:get_int("ontime"), ON_TIME)
|
||||
local blocking_time = tonumber(meta:get_string("blockingtime")) or BLOCKING_TIME
|
||||
logic.send_on(pos, meta, on_time)
|
||||
mem.time = t + blocking_time + on_time
|
||||
end
|
||||
end
|
||||
|
||||
local function switch_off(pos)
|
||||
local name = techage.get_node_lvm(pos).name
|
||||
if name == "techage:ta3_detector_on" then
|
||||
logic.swap_node(pos, "techage:ta3_detector_off")
|
||||
else
|
||||
logic.swap_node(pos, "techage:ta4_detector_off")
|
||||
end
|
||||
logic.send_off(pos, M(pos))
|
||||
end
|
||||
|
||||
local function formspec(meta)
|
||||
local numbers = meta:get_string("numbers") or ""
|
||||
return "size[7.5,3]"..
|
||||
techage.wrench_image(7, -0.1) ..
|
||||
"field[0.5,1;7,1;numbers;"..S("Insert destination node number(s)")..";"..numbers.."]" ..
|
||||
"button_exit[2,2;3,1;exit;"..S("Save").."]"
|
||||
end
|
||||
|
||||
local function after_place_node3(pos, placer)
|
||||
local meta = M(pos)
|
||||
local inv = meta:get_inventory()
|
||||
inv:set_size('cfg', 4)
|
||||
logic.after_place_node(pos, placer, "techage:ta3_detector_off", S("TA3 Item Detector"))
|
||||
logic.infotext(meta, S("TA3 Item Detector"))
|
||||
meta:set_string("formspec", formspec(meta))
|
||||
end
|
||||
|
||||
local function after_place_node4(pos, placer)
|
||||
local meta = M(pos)
|
||||
local inv = meta:get_inventory()
|
||||
inv:set_size('cfg', 4)
|
||||
logic.after_place_node(pos, placer, "techage:ta4_detector_off", S("TA4 Item Detector"))
|
||||
logic.infotext(meta, S("TA4 Item Detector"))
|
||||
meta:set_string("formspec", formspec(meta))
|
||||
end
|
||||
|
||||
local function on_receive_fields(pos, formname, fields, player)
|
||||
local meta = minetest.get_meta(pos)
|
||||
if techage.check_numbers(fields.numbers, player:get_player_name()) then
|
||||
meta:set_string("numbers", fields.numbers)
|
||||
logic.infotext(M(pos), NDEF(pos).description)
|
||||
meta:set_string("formspec", formspec(M(pos)))
|
||||
end
|
||||
end
|
||||
|
||||
local function techage_set_numbers(pos, numbers, player_name)
|
||||
local meta = M(pos)
|
||||
local res = logic.set_numbers(pos, numbers, player_name, NDEF(pos).description)
|
||||
meta:set_string("formspec", formspec(meta))
|
||||
return res
|
||||
end
|
||||
|
||||
local function after_dig_node(pos, oldnode, oldmetadata, digger)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
techage.del_mem(pos)
|
||||
end
|
||||
|
||||
local function ta_after_formspec(pos, fields, playername)
|
||||
if fields.save then
|
||||
local nvm = techage.get_nvm(pos)
|
||||
local val = M(pos):get_int("countdown") or 0
|
||||
if val > 0 then
|
||||
nvm.countdown = val
|
||||
else
|
||||
nvm.countdown = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_node("techage:ta3_detector_off", {
|
||||
description = S("TA3 Item Detector"),
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png^techage_appl_arrow.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_outp.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_inp.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_detector.png^[transformFX",
|
||||
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_detector.png",
|
||||
},
|
||||
|
||||
after_place_node = after_place_node3,
|
||||
on_receive_fields = on_receive_fields,
|
||||
techage_set_numbers = techage_set_numbers,
|
||||
after_dig_node = after_dig_node,
|
||||
ta3_formspec = WRENCH_MENU3,
|
||||
|
||||
on_rotate = screwdriver.disallow,
|
||||
paramtype = "light",
|
||||
sunlight_propagates = true,
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy=2, cracky=2, crumbly=2},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
})
|
||||
|
||||
|
||||
minetest.register_node("techage:ta3_detector_on", {
|
||||
description = S("TA3 Item Detector"),
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png^techage_appl_arrow.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_outp.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_inp.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_detector_on.png^[transformFX",
|
||||
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_detector_on.png",
|
||||
},
|
||||
|
||||
on_timer = switch_off,
|
||||
on_rotate = screwdriver.disallow,
|
||||
techage_set_numbers = techage_set_numbers,
|
||||
after_dig_node = after_dig_node,
|
||||
ta3_formspec = WRENCH_MENU3,
|
||||
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy=2, cracky=2, crumbly=2, not_in_creative_inventory=1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
drop = "techage:ta3_detector_off",
|
||||
})
|
||||
|
||||
minetest.register_node("techage:ta4_detector_off", {
|
||||
description = S("TA4 Item Detector"),
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"techage_filling_ta4.png^techage_frame_ta4_top.png^techage_appl_arrow.png",
|
||||
"techage_filling_ta4.png^techage_frame_ta4_top.png",
|
||||
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_outp.png",
|
||||
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_inp.png",
|
||||
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_detector.png^[transformFX",
|
||||
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_detector.png",
|
||||
},
|
||||
|
||||
after_place_node = after_place_node4,
|
||||
on_receive_fields = on_receive_fields,
|
||||
techage_set_numbers = techage_set_numbers,
|
||||
after_dig_node = after_dig_node,
|
||||
ta4_formspec = WRENCH_MENU4,
|
||||
ta_after_formspec = ta_after_formspec,
|
||||
|
||||
on_rotate = screwdriver.disallow,
|
||||
paramtype = "light",
|
||||
sunlight_propagates = true,
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy=2, cracky=2, crumbly=2},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
})
|
||||
|
||||
|
||||
minetest.register_node("techage:ta4_detector_on", {
|
||||
description = S("TA4 Item Detector"),
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"techage_filling_ta4.png^techage_frame_ta4_top.png^techage_appl_arrow.png",
|
||||
"techage_filling_ta4.png^techage_frame_ta4_top.png",
|
||||
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_outp.png",
|
||||
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_inp.png",
|
||||
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_detector_on.png^[transformFX",
|
||||
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_detector_on.png",
|
||||
},
|
||||
|
||||
on_timer = switch_off,
|
||||
on_rotate = screwdriver.disallow,
|
||||
techage_set_numbers = techage_set_numbers,
|
||||
after_dig_node = after_dig_node,
|
||||
ta4_formspec = WRENCH_MENU4,
|
||||
ta_after_formspec = ta_after_formspec,
|
||||
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy=2, cracky=2, crumbly=2, not_in_creative_inventory=1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
drop = "techage:ta4_detector_off",
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:ta3_detector_off",
|
||||
recipe = {
|
||||
{"", "group:wood", ""},
|
||||
{"techage:tubeS", "techage:vacuum_tube", "techage:tubeS"},
|
||||
{"", "group:wood", ""},
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:ta4_detector_off",
|
||||
recipe = {
|
||||
{"", "techage:ta3_detector_off", ""},
|
||||
{"", "techage:ta4_wlanchip", ""},
|
||||
{"", "", ""},
|
||||
},
|
||||
})
|
||||
|
||||
techage.register_node({"techage:ta3_detector_off", "techage:ta3_detector_on"}, {
|
||||
on_push_item = function(pos, in_dir, stack)
|
||||
local leftover = techage.safe_push_items(pos, in_dir, stack)
|
||||
if leftover then
|
||||
local inv = minetest.get_inventory({type = "node", pos = pos})
|
||||
if not inv or inv:is_empty("cfg") or inv:contains_item("cfg", ItemStack(stack:get_name())) then
|
||||
if leftover == true or leftover:get_count() ~= stack:get_count() then
|
||||
switch_on(pos)
|
||||
end
|
||||
end
|
||||
return leftover
|
||||
end
|
||||
return false
|
||||
end,
|
||||
is_pusher = true, -- is a pulling/pushing node
|
||||
})
|
||||
|
||||
techage.register_node({"techage:ta4_detector_off", "techage:ta4_detector_on"}, {
|
||||
on_push_item = function(pos, in_dir, stack)
|
||||
local leftover = techage.safe_push_items(pos, in_dir, stack)
|
||||
if leftover then
|
||||
local inv = minetest.get_inventory({type = "node", pos = pos})
|
||||
if not inv or inv:is_empty("cfg") or inv:contains_item("cfg", ItemStack(stack:get_name())) then
|
||||
local nvm = techage.get_nvm(pos)
|
||||
local num_moved = stack:get_count()
|
||||
if leftover ~= true then
|
||||
num_moved = num_moved - leftover:get_count()
|
||||
end
|
||||
|
||||
if nvm.countdown and nvm.countdown > 0 then
|
||||
nvm.countdown = nvm.countdown - num_moved
|
||||
if nvm.countdown <= 0 then
|
||||
M(pos):set_int("countdown", 0)
|
||||
if leftover == true or leftover:get_count() ~= stack:get_count() then
|
||||
switch_on(pos)
|
||||
end
|
||||
end
|
||||
elseif nvm.countdown == nil then
|
||||
if leftover == true or leftover:get_count() ~= stack:get_count() then
|
||||
switch_on(pos)
|
||||
end
|
||||
end
|
||||
nvm.counter = (nvm.counter or 0) + num_moved
|
||||
end
|
||||
return leftover
|
||||
end
|
||||
return false
|
||||
end,
|
||||
is_pusher = true, -- is a pulling/pushing node
|
||||
|
||||
on_recv_message = function(pos, src, topic, payload)
|
||||
if topic == "count" then
|
||||
local nvm = techage.get_nvm(pos)
|
||||
return nvm.counter or 0
|
||||
elseif topic == "countdown" then
|
||||
local nvm = techage.get_nvm(pos)
|
||||
nvm.countdown = tonumber(payload) or 0
|
||||
M(pos):set_int("countdown", nvm.countdown)
|
||||
return true
|
||||
elseif topic == "reset" then
|
||||
local nvm = techage.get_nvm(pos)
|
||||
nvm.counter = 0
|
||||
nvm.countdown = nil
|
||||
return true
|
||||
else
|
||||
return "unsupported"
|
||||
end
|
||||
end,
|
||||
on_beduino_receive_cmnd = function(pos, src, topic, payload)
|
||||
if topic == 6 then -- Detector Block Reset
|
||||
local nvm = techage.get_nvm(pos)
|
||||
nvm.counter = 0
|
||||
nvm.countdown = nil
|
||||
return 0
|
||||
elseif topic == 5 then -- Detector Block Countdown
|
||||
local nvm = techage.get_nvm(pos)
|
||||
nvm.countdown = tonumber(payload[1]) or 0
|
||||
M(pos):set_int("countdown", nvm.countdown)
|
||||
return 0
|
||||
else
|
||||
return 2
|
||||
end
|
||||
end,
|
||||
on_beduino_request_data = function(pos, src, topic, payload)
|
||||
if topic == 139 then
|
||||
local nvm = techage.get_nvm(pos)
|
||||
return 0, {nvm.counter or 0}
|
||||
else
|
||||
return 2, ""
|
||||
end
|
||||
end,
|
||||
})
|
||||
@@ -0,0 +1,147 @@
|
||||
--[[
|
||||
|
||||
TechAge
|
||||
=======
|
||||
|
||||
Copyright (C) 2017-2023 Joachim Stolberg
|
||||
|
||||
AGPL v3
|
||||
See LICENSE.txt for more information
|
||||
|
||||
TA3 Flip-flop
|
||||
|
||||
]]--
|
||||
|
||||
-- for lazy programmers
|
||||
local M = minetest.get_meta
|
||||
local S = techage.S
|
||||
local DESCR = S("TA3 Flip-Flop")
|
||||
|
||||
local logic = techage.logic
|
||||
|
||||
local function switch_on(pos)
|
||||
logic.swap_node(pos, "techage:ta3_flipflop_on")
|
||||
logic.send_on(pos, M(pos))
|
||||
end
|
||||
|
||||
local function switch_off(pos)
|
||||
logic.swap_node(pos, "techage:ta3_flipflop_off")
|
||||
logic.send_off(pos, M(pos))
|
||||
end
|
||||
|
||||
local function formspec(meta)
|
||||
local numbers = meta:get_string("numbers") or ""
|
||||
|
||||
return "formspec_version[4]size[10,3.5]"..
|
||||
"box[0.2,0.2;9.6,0.6;#c6e8ff]" ..
|
||||
"label[0.4,0.5;" .. minetest.colorize( "#000000", DESCR) .. "]" ..
|
||||
|
||||
"field[1.0,1.5;8,0.6;numbers;" .. S("Insert destination node number(s)") .. ";" .. numbers .. "]" ..
|
||||
|
||||
"button_exit[3.5,2.7;3,0.6;exit;" .. S("Save") .. "]"
|
||||
end
|
||||
|
||||
local function techage_set_numbers(pos, numbers, player_name)
|
||||
local meta = M(pos)
|
||||
local res = logic.set_numbers(pos, numbers, player_name, DESCR)
|
||||
meta:set_string("formspec", formspec(meta))
|
||||
return true --res
|
||||
end
|
||||
|
||||
local function after_dig_node(pos, oldnode, oldmetadata, digger)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
techage.del_mem(pos)
|
||||
end
|
||||
|
||||
local function on_receive_fields(pos, formname, fields, player)
|
||||
if minetest.is_protected(pos, player:get_player_name()) then
|
||||
return
|
||||
end
|
||||
|
||||
local meta = minetest.get_meta(pos)
|
||||
if fields.exit and fields.exit ~= "" then
|
||||
if techage.check_numbers(fields.numbers, player:get_player_name()) then
|
||||
meta:set_string("numbers", fields.numbers)
|
||||
logic.infotext(M(pos), DESCR)
|
||||
end
|
||||
meta:set_string("formspec", formspec(meta))
|
||||
elseif fields.exit == "close" then
|
||||
meta:set_string("formspec", formspec(meta))
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_node("techage:ta3_flipflop_off", {
|
||||
description = DESCR,
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_flipflop.png",
|
||||
},
|
||||
after_place_node = function(pos, placer)
|
||||
local meta = M(pos)
|
||||
logic.after_place_node(pos, placer, "techage:ta3_flipflop_off", DESCR)
|
||||
logic.infotext(meta, DESCR)
|
||||
meta:set_string("formspec", formspec(meta))
|
||||
end,
|
||||
|
||||
on_timer = function (pos, elapsed)
|
||||
switch_on(pos)
|
||||
end,
|
||||
|
||||
on_receive_fields = on_receive_fields,
|
||||
techage_set_numbers = techage_set_numbers,
|
||||
after_dig_node = after_dig_node,
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy=2, cracky=2, crumbly=2},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
})
|
||||
|
||||
minetest.register_node("techage:ta3_flipflop_on", {
|
||||
description = DESCR,
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_flipflop_on.png",
|
||||
},
|
||||
|
||||
on_timer = function (pos, elapsed)
|
||||
switch_off(pos)
|
||||
end,
|
||||
|
||||
on_receive_fields = on_receive_fields,
|
||||
techage_set_numbers = techage_set_numbers,
|
||||
after_dig_node = after_dig_node,
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy=2, cracky=2, crumbly=2, not_in_creative_inventory=1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
drop = "techage:ta3_flipflop_off"
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:ta3_flipflop_off",
|
||||
recipe = {
|
||||
{"", "group:wood", ""},
|
||||
{"default:mese_crystal_fragment", "default:steel_ingot", "techage:vacuum_tube"},
|
||||
{"", "group:wood", ""},
|
||||
},
|
||||
})
|
||||
|
||||
techage.register_node({
|
||||
"techage:ta3_flipflop_off", "techage:ta3_flipflop_on"
|
||||
}, {
|
||||
on_recv_message = function(pos, src, topic, payload)
|
||||
if topic == "on" then
|
||||
minetest.get_node_timer(pos):start(0.1)
|
||||
return true
|
||||
elseif topic == "off" then
|
||||
return true
|
||||
else
|
||||
return "unsupported"
|
||||
end
|
||||
end,
|
||||
}
|
||||
)
|
||||
@@ -0,0 +1,244 @@
|
||||
--[[
|
||||
|
||||
TechAge
|
||||
=======
|
||||
|
||||
Copyright (C) 2017-2023 Joachim Stolberg
|
||||
|
||||
AGPL v3
|
||||
See LICENSE.txt for more information
|
||||
|
||||
TA4 Gaze Sensor
|
||||
|
||||
]]--
|
||||
|
||||
-- for lazy programmers
|
||||
local M = minetest.get_meta
|
||||
local S = techage.S
|
||||
|
||||
local logic = techage.logic
|
||||
local CYCLE_TIME = 2
|
||||
local DESCR = S("TA4 Gaze Sensor")
|
||||
local MAX_PLAYER_DIST = 30
|
||||
|
||||
local WRENCH_MENU = {
|
||||
{
|
||||
type = "ascii",
|
||||
name = "names",
|
||||
label = S("Player Names"),
|
||||
tooltip = S("Input the player name(s) separated by blanks.\nIf empty, only the owner is accepted."),
|
||||
default = "",
|
||||
},
|
||||
{
|
||||
type = "numbers",
|
||||
name = "numbers",
|
||||
label = S("Number"),
|
||||
tooltip = S("Destination block number(s)"),
|
||||
default = "",
|
||||
check = techage.check_numbers,
|
||||
},
|
||||
{
|
||||
type = "ascii",
|
||||
name = "command1",
|
||||
label = "On " .. S("Command"),
|
||||
tooltip = S("Command to send when sensor is viewed"),
|
||||
default = "on",
|
||||
},
|
||||
{
|
||||
type = "ascii",
|
||||
name = "command2",
|
||||
label = "Off " .. S("Command"),
|
||||
tooltip = S("Command to send when sensor is no longer viewed"),
|
||||
default = "off",
|
||||
},
|
||||
}
|
||||
|
||||
local function switch_on(pos)
|
||||
if logic.swap_node(pos, "techage:ta4_gaze_sensor_on") then
|
||||
logic.send_cmnd(pos, "command1", "on")
|
||||
end
|
||||
end
|
||||
|
||||
local function switch_off(pos)
|
||||
if logic.swap_node(pos, "techage:ta4_gaze_sensor_off") then
|
||||
logic.send_cmnd(pos, "command2", "off")
|
||||
end
|
||||
end
|
||||
|
||||
local function get_players(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local names = meta:get_string("names") or ""
|
||||
local t = string.split(names, " ") or {}
|
||||
t[#t + 1] = meta:get_string("owner")
|
||||
return t
|
||||
end
|
||||
|
||||
local function player_focuses_block(pos, name, obj)
|
||||
obj = obj or minetest.get_player_by_name(name)
|
||||
if obj then
|
||||
local player_pos = obj:get_pos()
|
||||
player_pos.y = player_pos.y + 1.5
|
||||
local dist = vector.distance(pos, player_pos)
|
||||
if dist < MAX_PLAYER_DIST then
|
||||
local dir = obj:get_look_dir()
|
||||
if dir then
|
||||
local vec1 = vector.multiply(dir, dist)
|
||||
local pos1 = vector.round(vector.add(player_pos, vec1))
|
||||
if vector.equals(pos, pos1) then
|
||||
local item = obj:get_wielded_item()
|
||||
if not item or item:get_name() ~= "techage:end_wrench" then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function scan_for_player(pos)
|
||||
local mem = techage.get_mem(pos)
|
||||
mem.players = mem.players or get_players(pos)
|
||||
if mem.players[1] == "***" then
|
||||
for _, obj in ipairs(minetest.get_objects_inside_radius(pos, MAX_PLAYER_DIST)) do
|
||||
if player_focuses_block(pos, "", obj) then
|
||||
mem.player_name = obj:get_player_name()
|
||||
return true
|
||||
end
|
||||
end
|
||||
else
|
||||
for _, name in ipairs(mem.players) do
|
||||
if player_focuses_block(pos, name, nil) then
|
||||
mem.player_name = name
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
mem.player_name = ""
|
||||
return false
|
||||
end
|
||||
|
||||
local function ta_after_formspec(pos, fields, playername)
|
||||
if fields.save then
|
||||
local mem = techage.get_mem(pos)
|
||||
mem.players = nil
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_node("techage:ta4_gaze_sensor_off", {
|
||||
description = DESCR,
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"techage_filling_ta4.png^techage_frame_ta4_top.png",
|
||||
"techage_filling_ta4.png^techage_frame_ta4_top.png",
|
||||
"techage_filling_ta4.png^techage_frame_ta4_top.png^techage_appl_gaze_sensor.png",
|
||||
},
|
||||
after_place_node = function(pos, placer)
|
||||
local meta = M(pos)
|
||||
logic.after_place_node(pos, placer, "techage:ta4_gaze_sensor_off", DESCR)
|
||||
logic.infotext(meta, DESCR)
|
||||
minetest.get_node_timer(pos):start(CYCLE_TIME)
|
||||
end,
|
||||
|
||||
on_timer = function (pos, elapsed)
|
||||
if scan_for_player(pos) then
|
||||
switch_on(pos)
|
||||
end
|
||||
return true
|
||||
end,
|
||||
|
||||
techage_set_numbers = function(pos, numbers, player_name)
|
||||
return logic.set_numbers(pos, numbers, player_name, DESCR)
|
||||
end,
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
techage.del_mem(pos)
|
||||
end,
|
||||
|
||||
ta4_formspec = WRENCH_MENU,
|
||||
ta_after_formspec = ta_after_formspec,
|
||||
groups = {choppy=2, cracky=2, crumbly=2},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
})
|
||||
|
||||
minetest.register_node("techage:ta4_gaze_sensor_on", {
|
||||
description = DESCR,
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"techage_filling_ta4.png^techage_frame_ta4_top.png",
|
||||
"techage_filling_ta4.png^techage_frame_ta4_top.png",
|
||||
"techage_filling_ta4.png^techage_frame_ta4_top.png^techage_appl_gaze_sensor_on.png",
|
||||
},
|
||||
|
||||
on_timer = function (pos, elapsed)
|
||||
if not scan_for_player(pos) then
|
||||
switch_off(pos)
|
||||
end
|
||||
return true
|
||||
end,
|
||||
|
||||
techage_set_numbers = function(pos, numbers, player_name)
|
||||
return logic.set_numbers(pos, numbers, player_name, DESCR)
|
||||
end,
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
techage.del_mem(pos)
|
||||
end,
|
||||
|
||||
ta4_formspec = WRENCH_MENU,
|
||||
ta_after_formspec = ta_after_formspec,
|
||||
groups = {choppy=2, cracky=2, crumbly=2, not_in_creative_inventory=1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
drop = "techage:ta4_gaze_sensor_off"
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:ta4_gaze_sensor_off",
|
||||
recipe = {
|
||||
{"dye:blue", "techage:aluminum", "dye:blue"},
|
||||
{"default:copper_ingot", "techage:ta4_wlanchip", "default:wood"},
|
||||
},
|
||||
})
|
||||
|
||||
techage.register_node({
|
||||
"techage:ta4_gaze_sensor_off", "techage:ta4_gaze_sensor_on",
|
||||
}, {
|
||||
on_recv_message = function(pos, src, topic, payload)
|
||||
if topic == "name" then
|
||||
local mem = techage.get_mem(pos)
|
||||
return mem.player_name or ""
|
||||
elseif topic == "state" then
|
||||
local node = techage.get_node_lvm(pos)
|
||||
if node.name == "techage:ta4_gaze_sensor_on" then
|
||||
return "on"
|
||||
else
|
||||
return "off"
|
||||
end
|
||||
else
|
||||
return "unsupported"
|
||||
end
|
||||
end,
|
||||
on_beduino_request_data = function(pos, src, topic, payload)
|
||||
if topic == 144 then -- Player Name
|
||||
local mem = techage.get_mem(pos)
|
||||
return 0, mem.player_name or ""
|
||||
elseif topic == 142 then -- Binary State
|
||||
local node = techage.get_node_lvm(pos)
|
||||
if node.name == "techage:ta4_gaze_sensor_on" then
|
||||
return 0, {1}
|
||||
else
|
||||
return 0, {0}
|
||||
end
|
||||
else
|
||||
return 2, ""
|
||||
end
|
||||
end,
|
||||
on_node_load = function(pos)
|
||||
minetest.get_node_timer(pos):start(CYCLE_TIME)
|
||||
end,
|
||||
}
|
||||
)
|
||||
@@ -0,0 +1,130 @@
|
||||
--[[
|
||||
|
||||
TechAge
|
||||
=======
|
||||
|
||||
Copyright (C) 2019 Joachim Stolberg
|
||||
|
||||
AGPL v3
|
||||
See LICENSE.txt for more information
|
||||
|
||||
Logic library
|
||||
|
||||
]]--
|
||||
|
||||
-- for lazy programmers
|
||||
local M = minetest.get_meta
|
||||
local S = techage.S
|
||||
local S2P = minetest.string_to_pos
|
||||
local P2S = minetest.pos_to_string
|
||||
|
||||
techage.logic = {}
|
||||
|
||||
local Face2Dir = {[0]=
|
||||
{x=0, y=0, z=1},
|
||||
{x=1, y=0, z=0},
|
||||
{x=0, y=0, z=-1},
|
||||
{x=-1, y=0, z=0},
|
||||
{x=0, y=-1, z=0},
|
||||
{x=0, y=1, z=0}
|
||||
}
|
||||
|
||||
-- Determine the destination position based on the position,
|
||||
-- the node param2, and a route table like : {0,0,3}
|
||||
-- 0 = forward, 1 = right, 2 = backward, 3 = left
|
||||
function techage.logic.dest_pos(pos, param2, route)
|
||||
local p2 = param2
|
||||
for _,dir in ipairs(route) do
|
||||
p2 = (param2 + dir) % 4
|
||||
pos = vector.add(pos, Face2Dir[p2])
|
||||
end
|
||||
return pos, p2
|
||||
end
|
||||
|
||||
function techage.logic.swap_node(pos, name)
|
||||
local node = techage.get_node_lvm(pos)
|
||||
if node.name == name then
|
||||
return false
|
||||
end
|
||||
node.name = name
|
||||
minetest.swap_node(pos, node)
|
||||
return true
|
||||
end
|
||||
|
||||
function techage.logic.after_place_node(pos, placer, name, descr)
|
||||
local meta = M(pos)
|
||||
local own_num = techage.add_node(pos, name)
|
||||
meta:set_string("node_number", own_num)
|
||||
meta:set_string("owner", placer:get_player_name())
|
||||
meta:set_string("infotext", descr.." -")
|
||||
end
|
||||
|
||||
techage.recursion_guard = techage.recursion_guard or {}
|
||||
|
||||
function techage.logic.guarded_action(pos, cmnd, ...)
|
||||
if not cmnd then
|
||||
return
|
||||
end
|
||||
local arg = {...}
|
||||
local own_num = M(pos):get_string("node_number")
|
||||
if techage.recursion_guard[own_num] then
|
||||
minetest.log("warning", "[techage] Button recursion detected at node_number=".. own_num .. " pos=" .. P2S(pos))
|
||||
return -- recursion detected, do not execute
|
||||
end
|
||||
techage.recursion_guard[own_num] = true
|
||||
local result = cmnd(unpack(arg))
|
||||
techage.recursion_guard[own_num] = nil
|
||||
return result
|
||||
end
|
||||
|
||||
function techage.logic.send_on(pos, meta, time)
|
||||
local own_num = meta:get_string("node_number") or ""
|
||||
local numbers = meta:get_string("numbers") or ""
|
||||
if time and time > 0 then
|
||||
minetest.get_node_timer(pos):start(time)
|
||||
end
|
||||
techage.send_multi(own_num, numbers, "on")
|
||||
return own_num == numbers
|
||||
end
|
||||
|
||||
function techage.logic.send_cmnd(pos, ident, default, time)
|
||||
local meta = M(pos)
|
||||
local s = meta:contains(ident) and meta:get_string(ident) or default
|
||||
local command, payload = unpack(string.split(s, " ", false, 1))
|
||||
local own_num = meta:get_string("node_number") or ""
|
||||
local numbers = meta:get_string("numbers") or ""
|
||||
if time and time > 0 then
|
||||
minetest.get_node_timer(pos):start(time)
|
||||
end
|
||||
if command and command ~= "" then
|
||||
techage.send_multi(own_num, numbers, command, payload)
|
||||
end
|
||||
end
|
||||
|
||||
function techage.logic.send_off(pos, meta)
|
||||
local own_num = meta:get_string("node_number") or ""
|
||||
local numbers = meta:get_string("numbers") or ""
|
||||
techage.send_multi(own_num, numbers, "off")
|
||||
end
|
||||
|
||||
function techage.logic.infotext(meta, descr, text)
|
||||
local own_num = meta:get_string("node_number") or ""
|
||||
local numbers = meta:get_string("numbers") or ""
|
||||
if numbers ~= "" then
|
||||
meta:set_string("infotext", descr.." "..own_num..": "..S("connected with").." "..numbers)
|
||||
elseif text then
|
||||
meta:set_string("infotext", descr.." "..own_num..": "..text)
|
||||
else
|
||||
meta:set_string("infotext", descr.." "..own_num)
|
||||
end
|
||||
end
|
||||
|
||||
function techage.logic.set_numbers(pos, numbers, player_name, descr)
|
||||
if techage.check_numbers(numbers, player_name) then
|
||||
local meta = M(pos)
|
||||
meta:set_string("numbers", numbers)
|
||||
techage.logic.infotext(meta, descr)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
@@ -0,0 +1,190 @@
|
||||
--[[
|
||||
|
||||
TechAge
|
||||
=======
|
||||
|
||||
Copyright (C) 2019-2022 Joachim Stolberg
|
||||
|
||||
AGPL v3
|
||||
See LICENSE.txt for more information
|
||||
|
||||
Light Detector
|
||||
|
||||
]]--
|
||||
|
||||
-- for lazy programmers
|
||||
local M = minetest.get_meta
|
||||
local S = techage.S
|
||||
local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end
|
||||
|
||||
local logic = techage.logic
|
||||
local CYCLE_TIME = 2
|
||||
|
||||
local function switch_off(pos)
|
||||
local node = minetest.get_node(pos)
|
||||
if node.name == "techage:ta3_lightdetector_on" then
|
||||
logic.swap_node(pos, "techage:ta3_lightdetector_off")
|
||||
logic.send_off(pos, M(pos))
|
||||
end
|
||||
end
|
||||
|
||||
local function switch_on(pos)
|
||||
logic.swap_node(pos, "techage:ta3_lightdetector_on")
|
||||
if logic.send_on(pos, M(pos)) then
|
||||
minetest.after(1, switch_off, pos)
|
||||
end
|
||||
end
|
||||
|
||||
local function node_timer(pos)
|
||||
|
||||
local nvm = techage.get_nvm(pos)
|
||||
|
||||
local trigger = nvm.mode or 7
|
||||
|
||||
local pos_above = {x = pos.x, y = pos.y + 1, z = pos.z}
|
||||
if minetest.get_node_light(pos_above, nil) == nil then
|
||||
switch_off(pos)
|
||||
return true
|
||||
end
|
||||
|
||||
if minetest.get_node_light(pos_above, nil) > trigger then
|
||||
switch_on(pos)
|
||||
else
|
||||
switch_off(pos)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local function formspec(meta, nvm)
|
||||
local numbers = meta:get_string("numbers") or ""
|
||||
local dropdown_label = "1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15" -- Has to be a cleaner way of doing this, but it's just easier this way
|
||||
return "size[7.5,4]"..
|
||||
default.gui_bg..
|
||||
default.gui_bg_img..
|
||||
default.gui_slots..
|
||||
"field[0.5,1;7,1;numbers;"..S("Insert destination node number(s)")..";"..numbers.."]" ..
|
||||
"label[0.2,1.6;"..S("Send signal if light level is above:").."]"..
|
||||
"dropdown[0.2,2.1;7.3,1;mode;"..dropdown_label.."; "..(nvm.mode or 7).."]"..
|
||||
"button_exit[2,3.2;3,1;accept;"..S("accept").."]"
|
||||
end
|
||||
|
||||
local function on_receive_fields(pos, formname, fields, player)
|
||||
if minetest.is_protected(pos, player:get_player_name()) then
|
||||
return
|
||||
end
|
||||
|
||||
local meta = minetest.get_meta(pos)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
|
||||
if fields.accept then
|
||||
nvm.mode = tonumber(fields.mode) or 7
|
||||
if techage.check_numbers(fields.numbers, player:get_player_name()) then
|
||||
meta:set_string("numbers", fields.numbers)
|
||||
logic.infotext(M(pos), S("TA3 Light Detector"))
|
||||
end
|
||||
meta:set_string("formspec", formspec(meta, nvm))
|
||||
end
|
||||
end
|
||||
|
||||
local function techage_set_numbers(pos, numbers, player_name)
|
||||
local meta = M(pos)
|
||||
local res = logic.set_numbers(pos, numbers, player_name, S("TA3 Light Detector"))
|
||||
local nvm = techage.get_nvm(pos)
|
||||
meta:set_string("formspec", formspec(meta, nvm))
|
||||
return res
|
||||
end
|
||||
|
||||
local function after_dig_node(pos, oldnode, oldmetadata, digger)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
end
|
||||
|
||||
minetest.register_node("techage:ta3_lightdetector_off", {
|
||||
description = S("TA3 Light Detector"),
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png^techage_appl_lightdetector.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png^techage_appl_arrow.png^[transformR90",
|
||||
},
|
||||
after_place_node = function(pos, placer)
|
||||
local meta = M(pos)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
logic.after_place_node(pos, placer, "techage:ta3_lightdetector_off", S("TA3 Light Detector"))
|
||||
logic.infotext(meta, S("TA3 Light Detector"))
|
||||
meta:set_string("formspec", formspec(meta, nvm))
|
||||
minetest.get_node_timer(pos):start(CYCLE_TIME)
|
||||
end,
|
||||
|
||||
on_receive_fields = on_receive_fields,
|
||||
on_timer = node_timer,
|
||||
techage_set_numbers = techage_set_numbers,
|
||||
after_dig_node = after_dig_node,
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy=2, cracky=2, crumbly=2},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
})
|
||||
|
||||
minetest.register_node("techage:ta3_lightdetector_on", {
|
||||
description = "TA3 Light Detector (On)",
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png^techage_appl_lightdetector_on.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png^techage_appl_arrow.png^[transformR90",
|
||||
},
|
||||
on_receive_fields = on_receive_fields,
|
||||
on_timer = node_timer,
|
||||
techage_set_numbers = techage_set_numbers,
|
||||
after_dig_node = after_dig_node,
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy=2, cracky=2, crumbly=2, not_in_creative_inventory=1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
drop = "techage:ta3_lightdetector_off"
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:ta3_lightdetector_off",
|
||||
recipe = {
|
||||
{"", "group:wood", "default:glass"},
|
||||
{"", "default:copper_ingot", "techage:vacuum_tube"},
|
||||
{"", "group:wood", "default:mese_crystal"},
|
||||
},
|
||||
})
|
||||
|
||||
techage.register_node({"techage:ta3_lightdetector_off", "techage:ta3_lightdetector_on"}, {
|
||||
on_recv_message = function(pos, src, topic, payload)
|
||||
if topic == "state" then
|
||||
local node = techage.get_node_lvm(pos)
|
||||
if node.name == "techage:ta3_lightdetector_on" then
|
||||
return "on"
|
||||
else
|
||||
return "off"
|
||||
end
|
||||
elseif topic == "light_level" then -- Allow finding the specific light level
|
||||
local pos_above = {x = pos.x, y = pos.y + 1, z = pos.z}
|
||||
return minetest.get_node_light(pos_above, nil)
|
||||
else
|
||||
return "unsupported"
|
||||
end
|
||||
end,
|
||||
on_beduino_request_data = function(pos, src, topic, payload)
|
||||
if topic == 142 then -- Binary State
|
||||
local node = techage.get_node_lvm(pos)
|
||||
if node.name == "techage:ta3_lightdetector_on" then
|
||||
return 0, {1}
|
||||
else
|
||||
return 0, {0}
|
||||
end
|
||||
elseif topic == 143 then -- Allow finding the specific light level
|
||||
local pos_above = {x = pos.x, y = pos.y + 1, z = pos.z}
|
||||
return 0, {minetest.get_node_light(pos_above, nil)}
|
||||
else
|
||||
return 2, ""
|
||||
end
|
||||
end,
|
||||
on_node_load = function(pos)
|
||||
minetest.get_node_timer(pos):start(CYCLE_TIME)
|
||||
end,
|
||||
})
|
||||
@@ -0,0 +1,435 @@
|
||||
--[[
|
||||
|
||||
TechAge
|
||||
=======
|
||||
|
||||
Copyright (C) 2017-2022 Joachim Stolberg
|
||||
|
||||
AGPL v3
|
||||
See LICENSE.txt for more information
|
||||
|
||||
Logic Block 2
|
||||
|
||||
]]--
|
||||
|
||||
-- for lazy programmers
|
||||
local M = minetest.get_meta
|
||||
local S = techage.S
|
||||
local logic = techage.logic
|
||||
local NUM_RULES = 4
|
||||
|
||||
local HELP = S("Send an 'on'/'off' command if the\nexpression becomes true.\n") ..
|
||||
S("\nRule:\n<output> = on/off if <input-expression> is true\n") ..
|
||||
S("\n<output> is the block number to which the\ncommand should be sent.\n") ..
|
||||
S("\n<input-expression> is a boolean expression\nwhere input numbers are evaluated.\n") ..
|
||||
S("\nExamples:\n1234 == on\n1234 == off\n1234 == on and 2345 == off\n2345 ~= 3456\n") ..
|
||||
S("\nValid operators:\nand or on off me == ~= ( )\n") ..
|
||||
S("'~=' means: not equal\n") ..
|
||||
S("'me' has to be used for the own block number.\n") ..
|
||||
S("\nAll rules are checked with each received\ncommand.") ..
|
||||
S("\nThe internal processing time for all\ncommands is 100 ms.")
|
||||
|
||||
local ValidSymbols = {
|
||||
["me"] = true,
|
||||
["and"] = true,
|
||||
["or"] = true,
|
||||
["on"] = true,
|
||||
["off"] = true,
|
||||
["=="] = true,
|
||||
["~="] = true,
|
||||
["("] = true,
|
||||
[")"] = true,
|
||||
}
|
||||
|
||||
local Dropdown = {
|
||||
[""] = 1,
|
||||
["on"] = 2,
|
||||
["off"] = 3
|
||||
}
|
||||
|
||||
local function check_expr(pos, expr)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
local origin = expr
|
||||
-- Add blanks for the syntax check
|
||||
expr = expr:gsub("==", " == ")
|
||||
expr = expr:gsub("~=", " ~= ")
|
||||
expr = expr:gsub("%(", " ( ")
|
||||
expr = expr:gsub("%)", " ) ")
|
||||
|
||||
-- First syntax check
|
||||
local old_sym = "or" -- valid default value
|
||||
for sym in expr:gmatch("[^%s]+") do
|
||||
if not ValidSymbols[sym] and string.find(sym, '^[0-9]+$') == nil then
|
||||
return "Unexpected symbol '"..sym.."'"
|
||||
end
|
||||
if string.find(sym, '^[0-9]+$') and sym == nvm.own_num then
|
||||
return "Invalid node number '"..sym.."'"
|
||||
end
|
||||
-- function call check
|
||||
if sym == "(" and (old_sym ~= "and" and old_sym ~= "or") then
|
||||
return "Syntax error at '" .. sym .. "'"
|
||||
end
|
||||
old_sym = sym
|
||||
end
|
||||
-- Second syntax check
|
||||
local code, _ = loadstring("return " .. expr)
|
||||
if not code then
|
||||
return "Syntax error in '" .. origin .. "'"
|
||||
end
|
||||
end
|
||||
|
||||
local function check_num(pos, num, player_name)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
|
||||
if num ~= "me" and (num == nvm.own_num or
|
||||
not techage.check_numbers(num, player_name)) then
|
||||
return "Invalid node number '"..num.."'"
|
||||
end
|
||||
end
|
||||
|
||||
local function debug(mem, text)
|
||||
mem.debug = mem.debug or {}
|
||||
if #mem.debug > 20 then
|
||||
table.remove(mem.debug, 1)
|
||||
end
|
||||
local s = string.format("%.3f", techage.SystemTime) .. " s: " .. text
|
||||
table.insert(mem.debug, s)
|
||||
end
|
||||
|
||||
local function send(pos, num, val)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
local mem = techage.get_mem(pos)
|
||||
debug(mem, "(outp) " .. num .. " = " .. val)
|
||||
|
||||
if num == "me" then
|
||||
nvm.outp_tbl = nvm.outp_tbl or {}
|
||||
nvm.outp_tbl.me = val
|
||||
-- set the input directly
|
||||
nvm.inp_tbl = nvm.inp_tbl or {}
|
||||
nvm.inp_tbl.me = val
|
||||
else
|
||||
nvm.outp_tbl = nvm.outp_tbl or {}
|
||||
nvm.outp_tbl[num] = val
|
||||
nvm.own_num = nvm.own_num or M(pos):get_string("node_number")
|
||||
techage.send_single(nvm.own_num, num, val)
|
||||
end
|
||||
end
|
||||
|
||||
local function get_inputs(pos)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
local mem = techage.get_mem(pos)
|
||||
-- old data is needed for formspec 'input' values
|
||||
nvm.old_inp_tbl = table.copy(nvm.inp_tbl or {})
|
||||
for _, num in ipairs(mem.outp_num or {}) do
|
||||
nvm.old_inp_tbl[num] = nvm.outp_tbl[num] or "off"
|
||||
end
|
||||
return nvm.old_inp_tbl
|
||||
end
|
||||
|
||||
local function check_syntax(pos, line, owner, outp, expr)
|
||||
local err = check_num(pos, outp, owner)
|
||||
if not err then
|
||||
err = check_expr(pos, expr)
|
||||
if not err then
|
||||
return true, "ok"
|
||||
end
|
||||
end
|
||||
return false, "Error(" .. line .. "): " .. err
|
||||
end
|
||||
|
||||
local function compile(nvm, str)
|
||||
if str then
|
||||
local code, _ = loadstring(str)
|
||||
if code then
|
||||
nvm.error = "ok"
|
||||
return code
|
||||
else
|
||||
nvm.error = "Unknown compile error"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function data(nvm)
|
||||
local inp = {}
|
||||
local outp = {}
|
||||
for num, val in pairs(nvm.old_inp_tbl or {}) do
|
||||
if num == nvm.own_num then num = "me" end
|
||||
inp[#inp+1] = num .. " = " .. tostring(val)
|
||||
end
|
||||
for num, val in pairs(nvm.outp_tbl or {}) do
|
||||
if num == nvm.own_num then num = "me" end
|
||||
outp[#outp+1] = num .. " = " .. tostring(val)
|
||||
end
|
||||
return table.concat(inp, ", "), table.concat(outp, ", ")
|
||||
end
|
||||
|
||||
local function get_code(pos, nvm, mem)
|
||||
local meta = M(pos)
|
||||
local tbl = {"local inputs = get_inputs(pos) or {}"}
|
||||
local owner = M(pos):get_string("owner")
|
||||
nvm.own_num = nvm.own_num or M(pos):get_string("node_number")
|
||||
mem.outp_num = {}
|
||||
|
||||
for i = 1,NUM_RULES do
|
||||
local outp = meta:get_string("outp" .. i)
|
||||
local val = meta:get_string("val" .. i)
|
||||
local expr = meta:get_string("expr" .. i)
|
||||
|
||||
if outp ~= "" and val ~= "" and expr ~= "" then
|
||||
local res, err = check_syntax(pos, i, owner, outp, expr)
|
||||
if res then
|
||||
expr = string.gsub(expr, '([0-9]+)', 'inputs["%1"]')
|
||||
expr = string.gsub(expr, 'me', 'inputs["me"]')
|
||||
expr = string.gsub(expr, 'on', '"on"')
|
||||
expr = string.gsub(expr, 'off', '"off"')
|
||||
tbl[#tbl + 1] = "if "..expr.." then send(pos, '"..outp.."', '"..val.."') end"
|
||||
table.insert(mem.outp_num, outp)
|
||||
else
|
||||
nvm.error = err
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local str = table.concat(tbl, "\n")
|
||||
local code = compile(nvm, str)
|
||||
if code then
|
||||
local env = {}
|
||||
env.send = send
|
||||
env.pos = pos
|
||||
env.get_inputs = get_inputs
|
||||
setfenv(code, env)
|
||||
|
||||
return code
|
||||
end
|
||||
end
|
||||
|
||||
local function execute(pos)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
local mem = techage.get_mem(pos)
|
||||
mem.code = mem.code or get_code(pos, nvm, mem)
|
||||
if mem.code then
|
||||
local res, _ = pcall(mem.code)
|
||||
if not res then
|
||||
nvm.error = "Unknown runtime error"
|
||||
mem.code = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function rules(meta)
|
||||
local tbl = {}
|
||||
|
||||
tbl[#tbl + 1] = "label[-0.2,0;<outp>]"
|
||||
tbl[#tbl + 1] = "label[1.4,0;=]"
|
||||
tbl[#tbl + 1] = "label[1.8,0;<cmnd>]"
|
||||
tbl[#tbl + 1] = "label[3.5,0;if]"
|
||||
tbl[#tbl + 1] = "label[4.2,0;<inp expression> is true]"
|
||||
|
||||
|
||||
for i = 1,NUM_RULES do
|
||||
local y1 = (i * 0.9) - 0.1
|
||||
local y2 = (i * 0.9) - 0.2
|
||||
local y3 = (i * 0.9) - 0.3
|
||||
local outp = meta:get_string("outp" .. i)
|
||||
local val = meta:get_string("val" .. i)
|
||||
local expr = meta:get_string("expr" .. i)
|
||||
val = Dropdown[val] or 1
|
||||
|
||||
tbl[#tbl + 1] = "field[0," .. y1 .. ";1.6,1;outp" .. i ..";;" .. outp .. "]"
|
||||
tbl[#tbl + 1] = "label[1.4," .. y2 .. ";=]"
|
||||
tbl[#tbl + 1] = "dropdown[1.8," .. y3 .. ";1.6,1;val" .. i ..";,on,off;" .. val .. "]"
|
||||
tbl[#tbl + 1] = "label[3.5," .. y2 .. ";if]"
|
||||
tbl[#tbl + 1] = "field[4.2," .. y1 .. ";5.6,1;expr" .. i ..";;" .. expr .. "]"
|
||||
end
|
||||
return table.concat(tbl, "")
|
||||
end
|
||||
|
||||
local function formspec(pos, meta)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
local err = nvm.error or "ok"
|
||||
err = minetest.formspec_escape(err)
|
||||
nvm.io_tbl = nvm.io_tbl or {}
|
||||
local inputs, outputs = data(nvm)
|
||||
local bt = nvm.blocking_time or 1
|
||||
return "size[10,8.2]" ..
|
||||
"tabheader[0,0;tab;"..S("Rules") .. "," .. S("Help") .. "," .. S("Debug") .. ";1;;true]" ..
|
||||
"container[0.4,0.1]" ..
|
||||
rules(meta) ..
|
||||
"container_end[]" ..
|
||||
|
||||
"label[0.2,4.4;" .. S("Blocking Time") .. "]"..
|
||||
"field[4.6,4.5;2,1;bt;;" .. bt .. "]"..
|
||||
"label[6.3,4.4;s]"..
|
||||
|
||||
"label[0,5.3;" .. S("Inputs") .. ":]" ..
|
||||
"label[2,5.3;" .. inputs .."]" ..
|
||||
"label[0,5.9;" .. S("Outputs") .. ":]" ..
|
||||
"label[2,5.9;" .. outputs .."]" ..
|
||||
"label[0,6.5;" .. S("Syntax") .. ":]" ..
|
||||
"label[2,6.5;" .. err .. "]" ..
|
||||
"button[1.5,7.5;3,1;update;" .. S("Update") .. "]" ..
|
||||
"button[5.6,7.5;3,1;store;" .. S("Store") .. "]"
|
||||
end
|
||||
|
||||
local function formspec_help()
|
||||
return "size[10,8.2]" ..
|
||||
"tabheader[0,0;tab;"..S("Rules") .. "," .. S("Help") .. "," .. S("Debug") .. ";2;;true]" ..
|
||||
"textarea[0.3,0.3;9.9,8.5;;;"..minetest.formspec_escape(HELP).."]"
|
||||
end
|
||||
|
||||
local function formspec_debug(mem)
|
||||
mem.debug = mem.debug or {}
|
||||
local s = table.concat(mem.debug, "\n")
|
||||
return "size[10,8.2]" ..
|
||||
"tabheader[0,0;tab;"..S("Rules") .. "," .. S("Help") .. "," .. S("Debug") .. ";3;;true]" ..
|
||||
"textarea[0.3,0.3;9.9,8.5;;;"..minetest.formspec_escape(s).."]" ..
|
||||
"button[1.5,7.5;3,1;update2;" .. S("Update") .. "]" ..
|
||||
"button[5.6,7.5;3,1;clear;" .. S("Clear") .. "]"
|
||||
end
|
||||
|
||||
minetest.register_node("techage:ta3_logic2", {
|
||||
description = S("TA3 Logic Block"),
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_logic.png",
|
||||
},
|
||||
|
||||
after_place_node = function(pos, placer)
|
||||
local meta = M(pos)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
logic.after_place_node(pos, placer, "techage:ta3_logic2", S("TA3 Logic Block"))
|
||||
logic.infotext(meta, S("TA3 Logic Block"))
|
||||
meta:set_string("formspec", formspec(pos, meta))
|
||||
meta:set_string("owner", placer:get_player_name())
|
||||
end,
|
||||
|
||||
on_receive_fields = function(pos, formname, fields, player)
|
||||
if minetest.is_protected(pos, player:get_player_name()) then
|
||||
return
|
||||
end
|
||||
|
||||
local meta = M(pos)
|
||||
|
||||
if fields.store then
|
||||
for i = 1,NUM_RULES do
|
||||
meta:set_string("outp" .. i, fields["outp" .. i] or "")
|
||||
meta:set_string("val" .. i, fields["val" .. i] or "")
|
||||
meta:set_string("expr" .. i, fields["expr" .. i] or "")
|
||||
end
|
||||
local nvm = techage.get_nvm(pos)
|
||||
nvm.blocking_time = tonumber(fields.bt) or 0.1
|
||||
nvm.inp_tbl = {me = "off"}
|
||||
nvm.outp_tbl = {}
|
||||
elseif fields.update2 then
|
||||
local mem = techage.get_mem(pos)
|
||||
meta:set_string("formspec", formspec_debug(mem))
|
||||
elseif fields.clear then
|
||||
local mem = techage.get_mem(pos)
|
||||
mem.debug = {}
|
||||
meta:set_string("formspec", formspec_debug(mem))
|
||||
end
|
||||
|
||||
if fields.tab == "2" then
|
||||
meta:set_string("formspec", formspec_help())
|
||||
elseif fields.tab == "3" then
|
||||
local mem = techage.get_mem(pos)
|
||||
meta:set_string("formspec", formspec_debug(mem))
|
||||
else
|
||||
local nvm = techage.get_nvm(pos)
|
||||
local mem = techage.get_mem(pos)
|
||||
mem.code = nil
|
||||
get_code(pos, nvm, mem)
|
||||
meta:set_string("formspec", formspec(pos, meta))
|
||||
end
|
||||
end,
|
||||
|
||||
on_timer = function(pos)
|
||||
execute(pos)
|
||||
return false
|
||||
end,
|
||||
|
||||
on_rightclick = function(pos, node, clicker)
|
||||
if minetest.is_protected(pos, clicker:get_player_name()) then
|
||||
return
|
||||
end
|
||||
|
||||
local meta = M(pos)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
meta:set_string("formspec", formspec(pos, meta))
|
||||
end,
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
techage.del_mem(pos)
|
||||
end,
|
||||
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy=2, cracky=2, crumbly=2},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
})
|
||||
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:ta3_logic2",
|
||||
recipe = {
|
||||
{"", "group:wood", ""},
|
||||
{"techage:vacuum_tube", "default:copper_ingot", "techage:vacuum_tube"},
|
||||
{"", "group:wood", ""},
|
||||
},
|
||||
})
|
||||
|
||||
techage.register_node({"techage:ta3_logic2"}, {
|
||||
on_recv_message = function(pos, src, topic, payload)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
local mem = techage.get_mem(pos)
|
||||
nvm.own_num = nvm.own_num or M(pos):get_string("node_number")
|
||||
nvm.blocking_time = nvm.blocking_time or M(pos):get_float("blocking_time")
|
||||
nvm.inp_tbl = nvm.inp_tbl or {}
|
||||
|
||||
if src ~= nvm.own_num then
|
||||
if topic == "on" then
|
||||
debug(mem, "(inp) " .. src .. " = on")
|
||||
nvm.inp_tbl[src] = "on"
|
||||
elseif topic == "off" then
|
||||
debug(mem, "(inp) " .. src .. " = off")
|
||||
nvm.inp_tbl[src] = "off"
|
||||
else
|
||||
debug(mem, "(inp) invalid command")
|
||||
return "unsupported"
|
||||
end
|
||||
|
||||
local t = math.max((mem.ttl or 0) - techage.SystemTime, 0.1)
|
||||
minetest.get_node_timer(pos):start(t)
|
||||
mem.ttl = techage.SystemTime + (nvm.blocking_time or 0)
|
||||
end
|
||||
end,
|
||||
on_beduino_receive_cmnd = function(pos, src, topic, payload)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
local mem = techage.get_mem(pos)
|
||||
nvm.own_num = nvm.own_num or M(pos):get_string("node_number")
|
||||
nvm.blocking_time = nvm.blocking_time or M(pos):get_float("blocking_time")
|
||||
nvm.inp_tbl = nvm.inp_tbl or {}
|
||||
|
||||
if src ~= nvm.own_num then
|
||||
if topic == 1 and payload[1] == 1 then
|
||||
debug(mem, "(inp) " .. src .. " = on")
|
||||
nvm.inp_tbl[src] = "on"
|
||||
return 0
|
||||
elseif topic == 1 and payload[1] == 0 then
|
||||
debug(mem, "(inp) " .. src .. " = off")
|
||||
nvm.inp_tbl[src] = "off"
|
||||
return 0
|
||||
else
|
||||
debug(mem, "(inp) invalid command")
|
||||
return 2
|
||||
end
|
||||
local t = math.max((mem.ttl or 0) - techage.SystemTime, 0.1)
|
||||
minetest.get_node_timer(pos):start(t)
|
||||
mem.ttl = techage.SystemTime + (nvm.blocking_time or 0)
|
||||
end
|
||||
end,
|
||||
})
|
||||
@@ -0,0 +1,264 @@
|
||||
--[[
|
||||
|
||||
TechAge
|
||||
=======
|
||||
|
||||
Copyright (C) 2017-2022 Joachim Stolberg
|
||||
|
||||
AGPL v3
|
||||
See LICENSE.txt for more information
|
||||
|
||||
Lua Logic Block (Deprecated and replaced by "techage:ta3_logic2")
|
||||
|
||||
]]--
|
||||
|
||||
-- for lazy programmers
|
||||
local M = minetest.get_meta
|
||||
local S = techage.S
|
||||
local logic = techage.logic
|
||||
|
||||
-- mem.inp_tbl = {
|
||||
-- n001 = true, -- "on" received
|
||||
-- n002 = false, -- "off" received
|
||||
-- inp = true, -- last input
|
||||
-- outp = false, -- last output
|
||||
-- }
|
||||
|
||||
local ValidSymbols = {
|
||||
["if"] = true,
|
||||
["then"] = true,
|
||||
["else"] = true,
|
||||
["end"] = true,
|
||||
["return"] = true,
|
||||
["not"] = true,
|
||||
["and"] = true,
|
||||
["or"] = true,
|
||||
["inp"] = true,
|
||||
["outp"] = true,
|
||||
["true"] = true,
|
||||
["false"] = true,
|
||||
["nil"] = true,
|
||||
["=="] = true,
|
||||
["~="] = true,
|
||||
["("] = true,
|
||||
[")"] = true,
|
||||
}
|
||||
local function check(expression)
|
||||
for _, sym in ipairs(string.split(expression, " ")) do
|
||||
if not ValidSymbols[sym] and string.find(sym, '^[n0-9]+$') == nil then
|
||||
return false, "Error: Invalid symbol '"..sym.."'"
|
||||
end
|
||||
end
|
||||
return true, "ok"
|
||||
end
|
||||
|
||||
local function compile(nvm, expression)
|
||||
local res, err = check(expression)
|
||||
if res then
|
||||
local code, err = loadstring(expression, "")
|
||||
if code then
|
||||
nvm.code = code
|
||||
nvm.error = "ok"
|
||||
else
|
||||
nvm.code = nil
|
||||
nvm.error = err
|
||||
end
|
||||
else
|
||||
nvm.code = nil
|
||||
nvm.error = err
|
||||
end
|
||||
end
|
||||
|
||||
local function get_code(pos, nvm)
|
||||
local meta = M(pos)
|
||||
local if_expr = meta:get_string("if_expr") or ""
|
||||
local then_expr = meta:get_string("then_expr") or ""
|
||||
local else_expr = meta:get_string("else_expr") or ""
|
||||
local expr = "if "..if_expr.." then return "..then_expr.." else return "..else_expr.." end"
|
||||
compile(nvm, expr)
|
||||
return nvm.code
|
||||
end
|
||||
|
||||
local function eval(pos, nvm)
|
||||
nvm.code = nvm.code or get_code(pos, nvm)
|
||||
if nvm.code then
|
||||
setfenv(nvm.code, nvm.inp_tbl)
|
||||
local res, sts = pcall(nvm.code)
|
||||
if res then
|
||||
nvm.error = "ok"
|
||||
if sts == true and nvm.inp_tbl.outp ~= true then
|
||||
nvm.inp_tbl.outp = sts
|
||||
return "on"
|
||||
elseif sts == false and nvm.inp_tbl.outp ~= false then
|
||||
nvm.inp_tbl.outp = sts
|
||||
return "off"
|
||||
end
|
||||
else
|
||||
nvm.error = "Error: "..sts
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function data(nvm)
|
||||
local tbl = {"inp = "..dump(nvm.inp_tbl.inp), "outp = "..dump(nvm.inp_tbl.outp)}
|
||||
for k,v in pairs(nvm.inp_tbl) do
|
||||
if k ~= "inp" and k ~= "outp" then
|
||||
tbl[#tbl+1] = k.." = "..dump(v)
|
||||
end
|
||||
end
|
||||
return table.concat(tbl, ", ")
|
||||
end
|
||||
|
||||
local function formspec(pos, meta)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
local numbers = meta:get_string("numbers") or ""
|
||||
local if_expr = meta:get_string("if_expr") or ""
|
||||
local then_expr = meta:get_string("then_expr") or ""
|
||||
local else_expr = meta:get_string("else_expr") or ""
|
||||
local err = nvm.error or "ok"
|
||||
if err ~= "ok" then
|
||||
err = string.sub(err, 15)
|
||||
end
|
||||
err = minetest.formspec_escape(err)
|
||||
nvm.inp_tbl = nvm.inp_tbl or {inp = false, outp = false}
|
||||
local data = data(nvm)
|
||||
return "size[9,8]"..
|
||||
"background[0,0;9,1.3;techage_formspec_bg.png]"..
|
||||
"field[0.5,0.2;8.5,2;numbers;"..S("Insert destination node number(s)")..";"..numbers.."]" ..
|
||||
"label[0,1.4;Variables: "..data.."]"..
|
||||
"label[0,2;Valid symbols: not and or true false nil == ~= ( )]"..
|
||||
"background[0,2.6;9,4;techage_formspec_bg.png]"..
|
||||
"label[0.1,2.8;if]"..
|
||||
"field[0.8,2.9;7,1;if_expr;;"..if_expr.."]" ..
|
||||
"label[7.6,2.8;then]"..
|
||||
"label[0.6,3.8;return]"..
|
||||
"field[2,3.9;7,1;then_expr;;"..then_expr.."]" ..
|
||||
"label[0.1,4.5;else]"..
|
||||
"label[0.6,5.2;return]"..
|
||||
"field[2,5.3;7,1;else_expr;;"..else_expr.."]" ..
|
||||
"label[0.1,6;end]"..
|
||||
"label[0,6.8;Result: "..err.."]"..
|
||||
"button[2,7.3;2.5,1;update;"..S("Update").."]"..
|
||||
"button[5,7.3;2.5,1;store;"..S("Store").."]"
|
||||
end
|
||||
|
||||
minetest.register_node("techage:ta3_logic", {
|
||||
description = S("TA3 Logic Block"),
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_logic.png",
|
||||
},
|
||||
|
||||
after_place_node = function(pos, placer)
|
||||
local meta = M(pos)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
nvm.inp_tbl = {inp = false, outp = false}
|
||||
logic.after_place_node(pos, placer, "techage:ta3_logic", S("TA3 Logic Block"))
|
||||
logic.infotext(meta, S("TA3 Logic Block"))
|
||||
meta:set_string("formspec", formspec(pos, meta))
|
||||
end,
|
||||
|
||||
on_receive_fields = function(pos, formname, fields, player)
|
||||
if minetest.is_protected(pos, player:get_player_name()) then
|
||||
return
|
||||
end
|
||||
|
||||
local meta = M(pos)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
if fields.numbers and fields.numbers ~= "" then
|
||||
if techage.check_numbers(fields.numbers, player:get_player_name()) then
|
||||
meta:set_string("numbers", fields.numbers)
|
||||
logic.infotext(M(pos), S("TA3 Logic Block"))
|
||||
end
|
||||
end
|
||||
if fields.if_expr and fields.if_expr ~= "" then
|
||||
meta:set_string("if_expr", fields.if_expr)
|
||||
end
|
||||
if fields.then_expr and fields.then_expr ~= "" then
|
||||
meta:set_string("then_expr", fields.then_expr)
|
||||
end
|
||||
if fields.else_expr and fields.else_expr ~= "" then
|
||||
meta:set_string("else_expr", fields.else_expr)
|
||||
end
|
||||
if fields.store then
|
||||
get_code(pos, nvm)
|
||||
end
|
||||
meta:set_string("formspec", formspec(pos, meta))
|
||||
end,
|
||||
|
||||
on_timer = function(pos,elapsed)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
local topic = eval(pos, nvm)
|
||||
if topic then
|
||||
local meta = M(pos)
|
||||
local own_num = meta:get_string("node_number") or ""
|
||||
local numbers = meta:get_string("numbers") or ""
|
||||
techage.send_multi(own_num, numbers, topic)
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
techage_set_numbers = function(pos, numbers, player_name)
|
||||
local meta = M(pos)
|
||||
local res = logic.set_numbers(pos, numbers, player_name, S("TA3 Logic Block"))
|
||||
meta:set_string("formspec", formspec(pos, meta))
|
||||
return res
|
||||
end,
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
techage.del_mem(pos)
|
||||
end,
|
||||
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy=2, cracky=2, crumbly=2},
|
||||
is_ground_content = false,
|
||||
drop = "techage:ta3_logic2",
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
})
|
||||
|
||||
|
||||
-- Deprecated and replaced by "techage:ta3_logic2"
|
||||
--minetest.register_craft({
|
||||
-- output = "techage:ta3_logic",
|
||||
-- recipe = {
|
||||
-- {"", "group:wood", ""},
|
||||
-- {"", "default:copper_ingot", "techage:vacuum_tube"},
|
||||
-- {"", "group:wood", ""},
|
||||
-- },
|
||||
--})
|
||||
|
||||
techage.register_node({"techage:ta3_logic"}, {
|
||||
on_recv_message = function(pos, src, topic, payload)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
nvm.inp_tbl = nvm.inp_tbl or {outp = false}
|
||||
|
||||
if topic == "on" then
|
||||
nvm.inp_tbl.inp = true
|
||||
nvm.inp_tbl["n"..src] = true
|
||||
elseif topic == "off" then
|
||||
nvm.inp_tbl.inp = false
|
||||
nvm.inp_tbl["n"..src] = false
|
||||
else
|
||||
return "unsupported"
|
||||
end
|
||||
minetest.get_node_timer(pos):start(0.1)
|
||||
end,
|
||||
on_beduino_receive_cmnd = function(pos, src, topic, payload)
|
||||
if topic == 1 and payload[1] == 1 then
|
||||
nvm.inp_tbl.inp = true
|
||||
nvm.inp_tbl["n"..src] = true
|
||||
return 0
|
||||
elseif topic == 1 and payload[1] == 0 then
|
||||
nvm.inp_tbl.inp = false
|
||||
nvm.inp_tbl["n"..src] = false
|
||||
return 0
|
||||
else
|
||||
return 2
|
||||
end
|
||||
end,
|
||||
on_node_load = function(pos)
|
||||
end,
|
||||
})
|
||||
@@ -0,0 +1,116 @@
|
||||
--[[
|
||||
|
||||
TechAge
|
||||
=======
|
||||
|
||||
Copyright (C) 2017-2022 Joachim Stolberg
|
||||
|
||||
AGPL v3
|
||||
See LICENSE.txt for more information
|
||||
|
||||
TA4 Mapblock Active Detector
|
||||
|
||||
]]--
|
||||
|
||||
-- for lazy programmers
|
||||
local M = minetest.get_meta
|
||||
local S = techage.S
|
||||
|
||||
local logic = techage.logic
|
||||
|
||||
minetest.register_node("techage:ta4_mbadetector", {
|
||||
description = "TA4 Mapblock Active Detector",
|
||||
inventory_image = 'techage_smartline_mba_detector_inv.png',
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"techage_smartline.png",
|
||||
"techage_smartline.png",
|
||||
"techage_smartline.png",
|
||||
"techage_smartline.png",
|
||||
"techage_smartline.png",
|
||||
"techage_smartline.png^techage_smartline_mba_detector.png",
|
||||
},
|
||||
|
||||
drawtype = "nodebox",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{ -6/32, -6/32, 14/32, 6/32, 6/32, 16/32},
|
||||
},
|
||||
},
|
||||
|
||||
after_place_node = function(pos, placer)
|
||||
local meta = M(pos)
|
||||
logic.after_place_node(pos, placer, "techage:ta4_mbadetector", S("TA4 Mapblock Active Detector"))
|
||||
logic.infotext(meta, S("TA4 Mapblock Active Detector"))
|
||||
minetest.get_node_timer(pos):start(1)
|
||||
end,
|
||||
|
||||
on_timer = function(pos, elapsed)
|
||||
local mem = techage.get_mem(pos)
|
||||
mem.gametime = minetest.get_gametime()
|
||||
return true
|
||||
end,
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
techage.del_mem(pos)
|
||||
end,
|
||||
|
||||
paramtype = "light",
|
||||
sunlight_propagates = true,
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy=2, cracky=2, crumbly=2},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:ta4_mbadetector",
|
||||
recipe = {
|
||||
{"", "group:wood", "default:mese_crystal"},
|
||||
{"", "techage:vacuum_tube", "default:copper_ingot"},
|
||||
{"", "group:wood", ""},
|
||||
},
|
||||
})
|
||||
|
||||
techage.register_node({"techage:ta4_mbadetector"}, {
|
||||
on_recv_message = function(pos, src, topic, payload)
|
||||
if topic == "state" then
|
||||
if minetest.compare_block_status then
|
||||
if minetest.compare_block_status(pos, "active") then
|
||||
return "on"
|
||||
else
|
||||
return "off"
|
||||
end
|
||||
else
|
||||
local mem = techage.get_mem(pos)
|
||||
local res = mem.gametime and mem.gametime > (minetest.get_gametime() - 2)
|
||||
return res and "on" or "off"
|
||||
end
|
||||
else
|
||||
return "unsupported"
|
||||
end
|
||||
end,
|
||||
on_beduino_request_data = function(pos, src, topic, payload)
|
||||
if topic == 142 then -- Binary State
|
||||
if minetest.compare_block_status then
|
||||
if minetest.compare_block_status(pos, "active") then
|
||||
return 0, {1}
|
||||
else
|
||||
return 0, {0}
|
||||
end
|
||||
else
|
||||
local mem = techage.get_mem(pos)
|
||||
local res = mem.gametime and mem.gametime > (minetest.get_gametime() - 2)
|
||||
return 0, {res and 1 or 0}
|
||||
end
|
||||
else
|
||||
return 2, ""
|
||||
end
|
||||
end,
|
||||
on_node_load = function(pos)
|
||||
minetest.get_node_timer(pos):start(1)
|
||||
end,
|
||||
}
|
||||
)
|
||||
@@ -0,0 +1,199 @@
|
||||
--[[
|
||||
|
||||
TechAge
|
||||
=======
|
||||
|
||||
Copyright (C) 2017-2023 Joachim Stolberg
|
||||
|
||||
AGPL v3
|
||||
See LICENSE.txt for more information
|
||||
|
||||
Mesecons converter
|
||||
|
||||
]]--
|
||||
|
||||
-- for lazy programmers
|
||||
local M = minetest.get_meta
|
||||
local S = techage.S
|
||||
|
||||
local logic = techage.logic
|
||||
local OVER_LOAD_MAX = 10
|
||||
local CYCLE_TIME = 2
|
||||
|
||||
local function formspec(meta)
|
||||
local numbers = meta:get_string("numbers") or ""
|
||||
return "size[7.5,3]"..
|
||||
"field[0.5,1;7,1;numbers;"..S("Insert destination node number(s)")..";"..numbers.."]" ..
|
||||
"button_exit[2,2;3,1;exit;"..S("Save").."]"
|
||||
end
|
||||
|
||||
local function send_message(pos, topic)
|
||||
local meta = M(pos)
|
||||
local mem = techage.get_mem(pos)
|
||||
mem.overload_cnt = (mem.overload_cnt or 0) + 1
|
||||
if mem.overload_cnt > OVER_LOAD_MAX then
|
||||
logic.infotext(M(pos), S("TA3 Mesecons Converter"), "fault (overloaded)")
|
||||
techage.logic.swap_node(pos, "techage:ta3_mesecons_converter")
|
||||
minetest.get_node_timer(pos):stop()
|
||||
return false
|
||||
end
|
||||
local own_num = meta:get_string("node_number")
|
||||
local numbers = meta:get_string("numbers")
|
||||
techage.send_multi(own_num, numbers, topic)
|
||||
end
|
||||
|
||||
local function on_receive_fields(pos, formname, fields, player)
|
||||
if minetest.is_protected(pos, player:get_player_name()) then
|
||||
return
|
||||
end
|
||||
|
||||
local meta = M(pos)
|
||||
if techage.check_numbers(fields.numbers, player:get_player_name()) then
|
||||
meta:set_string("numbers", fields.numbers)
|
||||
logic.infotext(M(pos), S("TA3 Mesecons Converter"))
|
||||
meta:set_string("formspec", formspec(meta))
|
||||
end
|
||||
minetest.get_node_timer(pos):start(CYCLE_TIME)
|
||||
end
|
||||
|
||||
local function on_timer(pos,elapsed)
|
||||
local mem = techage.get_mem(pos)
|
||||
mem.overload_cnt = 0
|
||||
return true
|
||||
end
|
||||
|
||||
local function techage_set_numbers(pos, numbers, player_name)
|
||||
local meta = M(pos)
|
||||
local res = logic.set_numbers(pos, numbers, player_name, S("TA3 Mesecons Converter"))
|
||||
meta:set_string("formspec", formspec(meta))
|
||||
return res
|
||||
end
|
||||
|
||||
local function after_dig_node(pos, oldnode, oldmetadata)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
techage.del_mem(pos)
|
||||
mesecon.on_dignode(pos, oldnode)
|
||||
end
|
||||
|
||||
|
||||
minetest.register_node("techage:ta3_mesecons_converter", {
|
||||
description = S("TA3 Mesecons Converter"),
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_mesecons_converter.png",
|
||||
},
|
||||
|
||||
after_place_node = function(pos, placer)
|
||||
local meta = M(pos)
|
||||
local mem = techage.get_mem(pos)
|
||||
logic.after_place_node(pos, placer, "techage:ta3_mesecons_converter", S("TA3 Mesecons Converter"))
|
||||
logic.infotext(meta, S("TA3 Mesecons Converter"))
|
||||
meta:set_string("formspec", formspec(meta))
|
||||
mem.overload_cnt = -OVER_LOAD_MAX -- to prevent overload after placing
|
||||
minetest.get_node_timer(pos):start(CYCLE_TIME)
|
||||
mesecon.on_placenode(pos, minetest.get_node(pos))
|
||||
end,
|
||||
|
||||
on_receive_fields = on_receive_fields,
|
||||
on_timer = on_timer,
|
||||
techage_set_numbers = techage_set_numbers,
|
||||
after_dig_node = after_dig_node,
|
||||
|
||||
mesecons = {
|
||||
receptor = {
|
||||
state = mesecon.state.off,
|
||||
rules = mesecon.rules.default,
|
||||
},
|
||||
effector = {
|
||||
rules = mesecon.rules.default,
|
||||
action_on = function(pos, node)
|
||||
techage.logic.swap_node(pos, "techage:ta3_mesecons_converter_on")
|
||||
send_message(pos, "on")
|
||||
end,
|
||||
action_off = function(pos, node)
|
||||
end,
|
||||
action_change = function(pos, node)
|
||||
techage.logic.swap_node(pos, "techage:ta3_mesecons_converter_on")
|
||||
send_message(pos, "on")
|
||||
end,
|
||||
}
|
||||
},
|
||||
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy=2, cracky=2, crumbly=2},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
})
|
||||
|
||||
minetest.register_node("techage:ta3_mesecons_converter_on", {
|
||||
description = S("TA3 Mesecons Converter"),
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_mesecons_converter.png",
|
||||
},
|
||||
|
||||
on_receive_fields = on_receive_fields,
|
||||
on_timer = on_timer,
|
||||
techage_set_numbers = techage_set_numbers,
|
||||
after_dig_node = after_dig_node,
|
||||
|
||||
mesecons = {
|
||||
receptor = {
|
||||
state = mesecon.state.off,
|
||||
rules = mesecon.rules.default,
|
||||
},
|
||||
effector = {
|
||||
rules = mesecon.rules.default,
|
||||
action_on = function(pos, node)
|
||||
end,
|
||||
action_off = function(pos, node)
|
||||
techage.logic.swap_node(pos, "techage:ta3_mesecons_converter")
|
||||
send_message(pos, "off")
|
||||
end,
|
||||
action_change = function(pos, node)
|
||||
techage.logic.swap_node(pos, "techage:ta3_mesecons_converter")
|
||||
send_message(pos, "off")
|
||||
end,
|
||||
}
|
||||
},
|
||||
|
||||
paramtype = "light",
|
||||
light_source = 5,
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy=2, cracky=2, crumbly=2, not_in_creative_inventory=1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
drop = "techage:ta3_mesecons_converter",
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:ta3_mesecons_converter",
|
||||
recipe = {
|
||||
{"techage:ta3_repeater", "mesecons:wire_00000000_off"},
|
||||
},
|
||||
})
|
||||
|
||||
techage.register_node({"techage:ta3_mesecons_converter", "techage:ta3_mesecons_converter_on"}, {
|
||||
on_recv_message = function(pos, src, topic, payload)
|
||||
local mem = techage.get_mem(pos)
|
||||
mem.overload_cnt = (mem.overload_cnt or 0) + 1
|
||||
if mem.overload_cnt > OVER_LOAD_MAX then
|
||||
logic.infotext(M(pos), S("TA3 Mesecons Converter"), "fault (overloaded)")
|
||||
minetest.get_node_timer(pos):stop()
|
||||
return false
|
||||
elseif topic == "on" then
|
||||
techage.logic.swap_node(pos, "techage:ta3_mesecons_converter_on")
|
||||
mesecon.receptor_on(pos, mesecon.rules.default)
|
||||
elseif topic == "off" then
|
||||
techage.logic.swap_node(pos, "techage:ta3_mesecons_converter")
|
||||
mesecon.receptor_off(pos, mesecon.rules.default)
|
||||
end
|
||||
end,
|
||||
on_node_load = function(pos)
|
||||
minetest.get_node_timer(pos):start(CYCLE_TIME)
|
||||
end,
|
||||
})
|
||||
@@ -0,0 +1,407 @@
|
||||
--[[
|
||||
|
||||
TechAge
|
||||
=======
|
||||
|
||||
Copyright (C) 2017-2023 Joachim Stolberg
|
||||
|
||||
AGPL v3
|
||||
See LICENSE.txt for more information
|
||||
|
||||
TA3/TA4 Node Detector
|
||||
|
||||
]]--
|
||||
|
||||
-- for lazy programmers
|
||||
local M = minetest.get_meta
|
||||
local S = techage.S
|
||||
local MP = minetest.get_modpath("techage")
|
||||
local mark = dofile(MP .. "/basis/mark_lib.lua")
|
||||
|
||||
local logic = techage.logic
|
||||
local CYCLE_TIME = 2
|
||||
local MAX_BLOCKS = 4
|
||||
local DESCR3 = S("TA3 Node Detector")
|
||||
local DESCR4 = S("TA4 Node Detector")
|
||||
|
||||
local function switch_on3(pos)
|
||||
if logic.swap_node(pos, "techage:ta3_nodedetector_on") then
|
||||
logic.send_on(pos, M(pos))
|
||||
end
|
||||
end
|
||||
|
||||
local function switch_off3(pos)
|
||||
if logic.swap_node(pos, "techage:ta3_nodedetector_off") then
|
||||
logic.send_off(pos, M(pos))
|
||||
end
|
||||
end
|
||||
|
||||
local function switch_on4(pos)
|
||||
if logic.swap_node(pos, "techage:ta4_nodedetector_on") then
|
||||
logic.send_on(pos, M(pos))
|
||||
end
|
||||
end
|
||||
|
||||
local function switch_off4(pos)
|
||||
if logic.swap_node(pos, "techage:ta4_nodedetector_off") then
|
||||
logic.send_off(pos, M(pos))
|
||||
end
|
||||
end
|
||||
|
||||
local DropdownValues = {
|
||||
[S("added")] = 1,
|
||||
[S("removed")] = 2,
|
||||
[S("added or removed")] = 3,
|
||||
}
|
||||
|
||||
local AirLikeBlocks = {"air"}
|
||||
local kvAirLikeBlocks = {air = 1}
|
||||
|
||||
for i = 1,14 do
|
||||
-- Add light blocks from the mod "wielded_light" to the air-like blocks
|
||||
AirLikeBlocks[#AirLikeBlocks + 1] = "wielded_light:" .. i
|
||||
kvAirLikeBlocks["wielded_light:" .. i] = 1
|
||||
end
|
||||
|
||||
local function formspec3(meta, nvm)
|
||||
local numbers = meta:get_string("numbers") or ""
|
||||
local label = S("added")..","..S("removed")..","..S("added or removed")
|
||||
return "size[7.5,4]"..
|
||||
default.gui_bg..
|
||||
default.gui_bg_img..
|
||||
default.gui_slots..
|
||||
"field[0.5,0.6;7,1;numbers;"..S("Insert destination node number(s)")..";"..numbers.."]" ..
|
||||
"label[0.2,1.6;"..S("Send signal if nodes have been:").."]"..
|
||||
"dropdown[0.2,2.1;7.3,1;mode;"..label..";"..(nvm.mode or 3).."]"..
|
||||
"button_exit[2,3.2;3,1;accept;"..S("accept").."]"
|
||||
end
|
||||
|
||||
local function formspec4(meta, nvm)
|
||||
local numbers = meta:get_string("numbers") or ""
|
||||
local label = S("added")..","..S("removed")..","..S("added or removed")
|
||||
return "size[7.5,6]"..
|
||||
"box[0,-0.1;7.2,0.5;#c6e8ff]" ..
|
||||
"label[0.2,-0.1;" .. minetest.colorize( "#000000", DESCR4) .. "]" ..
|
||||
"button[0.1,0.6;3.6,1;record;" .. S("Record") .. "]" ..
|
||||
"button[3.9,0.6;3.6,1;done;" .. S("Done") .. "]" ..
|
||||
"field[0.5,2.6;7,1;numbers;"..S("Insert destination node number(s)")..";"..numbers.."]" ..
|
||||
"label[0.2,3.6;"..S("Send signal if nodes have been:").."]"..
|
||||
"dropdown[0.2,4.1;7.3,1;mode;"..label..";"..(nvm.mode or 3).."]"..
|
||||
"button_exit[2,5.2;3,1;accept;"..S("accept").."]"
|
||||
end
|
||||
|
||||
local function any_node_changed3(pos)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
if not nvm.pos1 or not nvm.pos2 or not nvm.num then
|
||||
local node = minetest.get_node(pos)
|
||||
local param2 = (node.param2 + 2) % 4
|
||||
nvm.pos1 = logic.dest_pos(pos, param2, {0})
|
||||
nvm.pos2 = logic.dest_pos(pos, param2, {0,0,0})
|
||||
nvm.num = #minetest.find_nodes_in_area(nvm.pos1, nvm.pos2, AirLikeBlocks)
|
||||
return false
|
||||
end
|
||||
local num1 = #minetest.find_nodes_in_area(nvm.pos1, nvm.pos2, AirLikeBlocks)
|
||||
local num2 = #minetest.find_nodes_in_area(nvm.pos1, nvm.pos2, {"ignore"})
|
||||
|
||||
if num2 == 0 and nvm.num ~= num1 then
|
||||
if nvm.mode == 1 and num1 < nvm.num then
|
||||
nvm.num = num1
|
||||
return true
|
||||
elseif nvm.mode == 2 and num1 > nvm.num then
|
||||
nvm.num = num1
|
||||
return true
|
||||
elseif nvm.mode == 3 then
|
||||
nvm.num = num1
|
||||
return true
|
||||
end
|
||||
nvm.num = num1
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function any_node_changed4(pos)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
nvm.lpos = nvm.lpos or {}
|
||||
local num = 0
|
||||
for _,pos1 in ipairs(nvm.lpos) do
|
||||
local name = minetest.get_node(pos1).name
|
||||
if name == "ignore" then return false end
|
||||
num = num + (kvAirLikeBlocks[name] or 0)
|
||||
end
|
||||
if not nvm.num then
|
||||
nvm.num = num
|
||||
elseif nvm.num ~= num then
|
||||
if nvm.mode == 1 and num < nvm.num then
|
||||
nvm.num = num
|
||||
return true
|
||||
elseif nvm.mode == 2 and num > nvm.num then
|
||||
nvm.num = num
|
||||
return true
|
||||
elseif nvm.mode == 3 then
|
||||
nvm.num = num
|
||||
return true
|
||||
end
|
||||
nvm.num = num
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function on_receive_fields3(pos, formname, fields, player)
|
||||
if minetest.is_protected(pos, player:get_player_name()) then
|
||||
return
|
||||
end
|
||||
|
||||
local nvm = techage.get_nvm(pos)
|
||||
local meta = M(pos)
|
||||
if fields.accept then
|
||||
nvm.mode = DropdownValues[fields.mode] or 3
|
||||
if techage.check_numbers(fields.numbers, player:get_player_name()) then
|
||||
meta:set_string("numbers", fields.numbers)
|
||||
logic.infotext(M(pos), DESCR3)
|
||||
end
|
||||
end
|
||||
meta:set_string("formspec", formspec3(meta, nvm))
|
||||
end
|
||||
|
||||
local function on_receive_fields4(pos, formname, fields, player)
|
||||
if minetest.is_protected(pos, player:get_player_name()) then
|
||||
return
|
||||
end
|
||||
|
||||
local name = player:get_player_name()
|
||||
local nvm = techage.get_nvm(pos)
|
||||
local meta = M(pos)
|
||||
|
||||
if fields.accept then
|
||||
nvm.mode = DropdownValues[fields.mode] or 3
|
||||
if techage.check_numbers(fields.numbers, name) then
|
||||
meta:set_string("numbers", fields.numbers)
|
||||
logic.infotext(M(pos), DESCR4)
|
||||
end
|
||||
mark.unmark_all(name)
|
||||
mark.stop(name)
|
||||
elseif fields.record then
|
||||
nvm.lpos = {}
|
||||
minetest.chat_send_player(name, "[techage] " .. S("Click on all blocks whose positions should be checked"))
|
||||
mark.start(name, MAX_BLOCKS)
|
||||
elseif fields.done then
|
||||
local pos_list = mark.get_poslist(name)
|
||||
minetest.chat_send_player(name, "[techage] " .. #pos_list.." "..S("block positions are stored."))
|
||||
nvm.lpos = pos_list
|
||||
mark.unmark_all(name)
|
||||
mark.stop(name)
|
||||
end
|
||||
meta:set_string("formspec", formspec4(meta, nvm))
|
||||
end
|
||||
|
||||
local function node_timer3(pos)
|
||||
if any_node_changed3(pos)then
|
||||
switch_on3(pos)
|
||||
else
|
||||
switch_off3(pos)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
minetest.register_node("techage:ta3_nodedetector_off", {
|
||||
description = DESCR3,
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png^techage_appl_arrow.png^[transformR270",
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_nodedetector.png",
|
||||
},
|
||||
|
||||
after_place_node = function(pos, placer)
|
||||
local meta = M(pos)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
logic.after_place_node(pos, placer, "techage:ta3_nodedetector_off", DESCR3)
|
||||
logic.infotext(meta, DESCR3)
|
||||
nvm.mode = 3 -- default mode
|
||||
meta:set_string("formspec", formspec3(meta, nvm))
|
||||
minetest.get_node_timer(pos):start(CYCLE_TIME)
|
||||
any_node_changed3(pos)
|
||||
end,
|
||||
|
||||
on_timer = node_timer3,
|
||||
on_receive_fields = on_receive_fields3,
|
||||
|
||||
techage_set_numbers = function(pos, numbers, player_name)
|
||||
local meta = M(pos)
|
||||
local res = logic.set_numbers(pos, numbers, player_name, DESCR3)
|
||||
meta:set_string("formspec", formspec3(meta, techage.get_nvm(pos)))
|
||||
return res
|
||||
end,
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
techage.del_mem(pos)
|
||||
end,
|
||||
|
||||
on_rotate = screwdriver.disallow,
|
||||
paramtype2 = "facedir",
|
||||
is_ground_content = false,
|
||||
groups = {choppy=2, cracky=2, crumbly=2},
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
})
|
||||
|
||||
minetest.register_node("techage:ta3_nodedetector_on", {
|
||||
description = DESCR3,
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png^techage_appl_arrow.png^[transformR270",
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_nodedetector_on.png",
|
||||
},
|
||||
|
||||
on_timer = node_timer3,
|
||||
|
||||
techage_set_numbers = function(pos, numbers, player_name)
|
||||
local meta = M(pos)
|
||||
local res = logic.set_numbers(pos, numbers, player_name, DESCR3)
|
||||
meta:set_string("formspec", formspec3(meta, techage.get_nvm(pos)))
|
||||
return res
|
||||
end,
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
techage.del_mem(pos)
|
||||
end,
|
||||
|
||||
on_rotate = screwdriver.disallow,
|
||||
paramtype2 = "facedir",
|
||||
is_ground_content = false,
|
||||
drop = "techage:ta3_nodedetector_off",
|
||||
groups = {choppy=2, cracky=2, crumbly=2, not_in_creative_inventory = 1},
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
})
|
||||
|
||||
local function node_timer4(pos)
|
||||
if any_node_changed4(pos)then
|
||||
switch_on4(pos)
|
||||
else
|
||||
switch_off4(pos)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
minetest.register_node("techage:ta4_nodedetector_off", {
|
||||
description = DESCR4,
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"techage_filling_ta4.png^techage_frame_ta4_top.png^techage_appl_arrow.png^[transformR270",
|
||||
"techage_filling_ta4.png^techage_frame_ta4_top.png",
|
||||
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_nodedetector.png",
|
||||
},
|
||||
|
||||
after_place_node = function(pos, placer)
|
||||
local meta = M(pos)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
logic.after_place_node(pos, placer, "techage:ta4_nodedetector_off", DESCR4)
|
||||
logic.infotext(meta, DESCR4)
|
||||
nvm.mode = 3 -- default mode
|
||||
meta:set_string("formspec", formspec4(meta, nvm))
|
||||
minetest.get_node_timer(pos):start(CYCLE_TIME)
|
||||
end,
|
||||
|
||||
on_timer = node_timer4,
|
||||
on_receive_fields = on_receive_fields4,
|
||||
|
||||
techage_set_numbers = function(pos, numbers, player_name)
|
||||
local meta = M(pos)
|
||||
local res = logic.set_numbers(pos, numbers, player_name, DESCR4)
|
||||
meta:set_string("formspec", formspec4(meta, techage.get_nvm(pos)))
|
||||
return res
|
||||
end,
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
techage.del_mem(pos)
|
||||
end,
|
||||
|
||||
on_rotate = screwdriver.disallow,
|
||||
paramtype2 = "facedir",
|
||||
is_ground_content = false,
|
||||
groups = {choppy=2, cracky=2, crumbly=2},
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
})
|
||||
|
||||
minetest.register_node("techage:ta4_nodedetector_on", {
|
||||
description = DESCR4,
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"techage_filling_ta4.png^techage_frame_ta4_top.png^techage_appl_arrow.png^[transformR270",
|
||||
"techage_filling_ta4.png^techage_frame_ta4_top.png",
|
||||
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_nodedetector_on.png",
|
||||
},
|
||||
|
||||
on_timer = node_timer4,
|
||||
|
||||
techage_set_numbers = function(pos, numbers, player_name)
|
||||
local meta = M(pos)
|
||||
local res = logic.set_numbers(pos, numbers, player_name, DESCR4)
|
||||
meta:set_string("formspec", formspec4(meta, techage.get_nvm(pos)))
|
||||
return res
|
||||
end,
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
techage.del_mem(pos)
|
||||
end,
|
||||
|
||||
on_rotate = screwdriver.disallow,
|
||||
paramtype2 = "facedir",
|
||||
is_ground_content = false,
|
||||
drop = "techage:ta4_nodedetector_off",
|
||||
groups = {choppy=2, cracky=2, crumbly=2, not_in_creative_inventory = 1},
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:ta3_nodedetector_off",
|
||||
recipe = {
|
||||
{"", "group:wood", ""},
|
||||
{"", "default:copper_ingot", "techage:vacuum_tube"},
|
||||
{"", "group:wood", "default:mese_crystal"},
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:ta4_nodedetector_off",
|
||||
recipe = {
|
||||
{"", "dye:blue", ""},
|
||||
{"", "techage:ta3_nodedetector_off", ""},
|
||||
{"", "techage:ta4_wlanchip", ""},
|
||||
},
|
||||
})
|
||||
|
||||
techage.register_node({"techage:ta3_nodedetector_off", "techage:ta3_nodedetector_on",
|
||||
"techage:ta4_nodedetector_off", "techage:ta4_nodedetector_on"}, {
|
||||
on_recv_message = function(pos, src, topic, payload)
|
||||
if topic == "state" then
|
||||
local node = techage.get_node_lvm(pos)
|
||||
if node.name == "techage:ta3_nodedetector_off" or node.name == "techage:ta4_nodedetector_off" then
|
||||
return "off"
|
||||
else
|
||||
return "on"
|
||||
end
|
||||
else
|
||||
return "unsupported"
|
||||
end
|
||||
end,
|
||||
on_beduino_request_data = function(pos, src, topic, payload)
|
||||
if topic == 142 then
|
||||
local node = techage.get_node_lvm(pos)
|
||||
if node.name == "techage:ta3_nodedetector_off" or node.name == "techage:ta4_nodedetector_off" then
|
||||
return 0, {0}
|
||||
else
|
||||
return 0, {1}
|
||||
end
|
||||
else
|
||||
return 2, ""
|
||||
end
|
||||
end,
|
||||
on_node_load = function(pos)
|
||||
minetest.get_node_timer(pos):start(CYCLE_TIME)
|
||||
end,
|
||||
})
|
||||
@@ -0,0 +1,382 @@
|
||||
--[[
|
||||
|
||||
TechAge
|
||||
=======
|
||||
|
||||
Copyright (C) 2017-2022 Joachim Stolberg
|
||||
|
||||
AGPL v3
|
||||
See LICENSE.txt for more information
|
||||
|
||||
TA3 & TA4 Player Detector
|
||||
|
||||
]]--
|
||||
|
||||
-- for lazy programmers
|
||||
local M = minetest.get_meta
|
||||
local S = techage.S
|
||||
local NDEF = function(pos) return (minetest.registered_nodes[techage.get_node_lvm(pos).name] or {}) end
|
||||
|
||||
local logic = techage.logic
|
||||
local CYCLE_TIME = 1
|
||||
|
||||
local WRENCH_MENU = {
|
||||
{
|
||||
type = "dropdown",
|
||||
choices = "1,2,3,4,5,6,7,8",
|
||||
name = "radius",
|
||||
label = S("Radius"),
|
||||
tooltip = S("Search radius"),
|
||||
default = "4",
|
||||
},
|
||||
{
|
||||
type = "numbers",
|
||||
name = "numbers",
|
||||
label = S("Number"),
|
||||
tooltip = S("Destination block number"),
|
||||
default = "",
|
||||
check = techage.check_numbers,
|
||||
},
|
||||
{
|
||||
type = "ascii",
|
||||
name = "command1",
|
||||
label = "On " .. S("Command"),
|
||||
tooltip = S("Command to send when player is detected"),
|
||||
default = "on",
|
||||
},
|
||||
{
|
||||
type = "ascii",
|
||||
name = "command2",
|
||||
label = "Off " .. S("Command"),
|
||||
tooltip = S("Command to send when player moves away"),
|
||||
default = "off",
|
||||
},
|
||||
}
|
||||
|
||||
local function switch_on(pos, stage)
|
||||
if logic.swap_node(pos, "techage:ta"..stage.."_playerdetector_on") then
|
||||
logic.send_cmnd(pos, "command1", "on")
|
||||
end
|
||||
end
|
||||
|
||||
local function switch_off(pos, stage)
|
||||
if logic.swap_node(pos, "techage:ta"..stage.."_playerdetector_off") then
|
||||
logic.send_cmnd(pos, "command2", "off")
|
||||
end
|
||||
end
|
||||
|
||||
local function scan_for_player(pos)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local names = meta:get_string("names") or ""
|
||||
local radius = meta:contains("radius") and meta:get_int("radius") or 4
|
||||
for _, object in pairs(minetest.get_objects_inside_radius(pos, radius)) do
|
||||
if object:is_player() then
|
||||
if names == "" then
|
||||
nvm.player_name = object:get_player_name()
|
||||
return true
|
||||
end
|
||||
for _,name in ipairs(string.split(names, " ")) do
|
||||
if object:get_player_name() == name then
|
||||
nvm.player_name = name
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
nvm.player_name = nil
|
||||
return false
|
||||
end
|
||||
|
||||
local function formspec_help()
|
||||
return "size[8,6]"..
|
||||
default.gui_bg..
|
||||
default.gui_bg_img..
|
||||
default.gui_slots..
|
||||
"label[3,0;Player Detector Help]"..
|
||||
"label[0,1;Input the number(s) of the destination node(s).\n"..
|
||||
"Separate numbers via blanks, like '123 234'.\n\n"..
|
||||
"Input the player name(s) separated by blanks,\nor empty for all players.]"..
|
||||
"button_exit[3,5;2,1;exit;close]"
|
||||
end
|
||||
|
||||
|
||||
local function formspec(meta)
|
||||
local numbers = meta:get_string("numbers") or ""
|
||||
local names = meta:get_string("names") or ""
|
||||
return "size[7,4]"..
|
||||
default.gui_bg..
|
||||
default.gui_bg_img..
|
||||
default.gui_slots..
|
||||
"field[0.3,0.6;7,1;numbers;"..S("Insert destination node number(s)")..";"..numbers.."]" ..
|
||||
"field[0.3,2;7,1;names;Insert player name(s) (optional):;"..names.."]" ..
|
||||
"button[0.9,3;2.5,1;help;help]"..
|
||||
"button_exit[3.5,3;2.5,1;exit;Save]"
|
||||
end
|
||||
|
||||
local function on_receive_fields(pos, formname, fields, player)
|
||||
if minetest.is_protected(pos, player:get_player_name()) then
|
||||
return
|
||||
end
|
||||
|
||||
local meta = minetest.get_meta(pos)
|
||||
if fields.exit == "Save" then
|
||||
if techage.check_numbers(fields.numbers, player:get_player_name()) then
|
||||
meta:set_string("numbers", fields.numbers)
|
||||
logic.infotext(M(pos), NDEF(pos).description)
|
||||
end
|
||||
meta:set_string("names", fields.names)
|
||||
meta:set_string("formspec", formspec(meta))
|
||||
elseif fields.help ~= nil then
|
||||
meta:set_string("formspec", formspec_help())
|
||||
elseif fields.exit == "close" then
|
||||
meta:set_string("formspec", formspec(meta))
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_node("techage:ta3_playerdetector_off", {
|
||||
description = S("TA3 Player Detector"),
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_playerdetector.png",
|
||||
},
|
||||
after_place_node = function(pos, placer)
|
||||
local meta = M(pos)
|
||||
logic.after_place_node(pos, placer, "techage:ta3_playerdetector_off", S("TA3 Player Detector"))
|
||||
logic.infotext(meta, S("TA3 Player Detector"))
|
||||
meta:set_string("formspec", formspec(meta))
|
||||
minetest.get_node_timer(pos):start(CYCLE_TIME)
|
||||
end,
|
||||
|
||||
on_receive_fields = on_receive_fields,
|
||||
|
||||
on_timer = function (pos, elapsed)
|
||||
if scan_for_player(pos) then
|
||||
switch_on(pos, 3)
|
||||
end
|
||||
return true
|
||||
end,
|
||||
|
||||
techage_set_numbers = function(pos, numbers, player_name)
|
||||
local meta = M(pos)
|
||||
local res = logic.set_numbers(pos, numbers, player_name, S("TA3 Player Detector"))
|
||||
meta:set_string("formspec", formspec(meta))
|
||||
return res
|
||||
end,
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
techage.del_mem(pos)
|
||||
end,
|
||||
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy=2, cracky=2, crumbly=2},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
})
|
||||
|
||||
minetest.register_node("techage:ta3_playerdetector_on", {
|
||||
description = "TA3 Player Detector",
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_playerdetector_on.png",
|
||||
},
|
||||
on_receive_fields = on_receive_fields,
|
||||
|
||||
on_timer = function (pos, elapsed)
|
||||
if not scan_for_player(pos) then
|
||||
switch_off(pos, 3)
|
||||
end
|
||||
return true
|
||||
end,
|
||||
|
||||
techage_set_numbers = function(pos, numbers, player_name)
|
||||
local meta = M(pos)
|
||||
local res = logic.set_numbers(pos, numbers, player_name, S("TA3 Player Detector"))
|
||||
meta:set_string("formspec", formspec(meta))
|
||||
return res
|
||||
end,
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
techage.del_mem(pos)
|
||||
end,
|
||||
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy=2, cracky=2, crumbly=2, not_in_creative_inventory=1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
drop = "techage:ta3_playerdetector_off"
|
||||
})
|
||||
|
||||
minetest.register_node("techage:ta4_playerdetector_off", {
|
||||
description = S("TA4 Player Detector"),
|
||||
inventory_image = 'techage_smartline_detector_inv.png',
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"techage_smartline.png",
|
||||
"techage_smartline.png",
|
||||
"techage_smartline.png",
|
||||
"techage_smartline.png",
|
||||
"techage_smartline.png",
|
||||
"techage_smartline.png^techage_smartline_detector.png",
|
||||
},
|
||||
|
||||
drawtype = "nodebox",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{ -6/32, -6/32, 14/32, 6/32, 6/32, 16/32},
|
||||
},
|
||||
},
|
||||
after_place_node = function(pos, placer)
|
||||
local meta = M(pos)
|
||||
logic.after_place_node(pos, placer, "techage:ta4_playerdetector_off", S("TA4 Player Detector"))
|
||||
logic.infotext(meta, S("TA4 Player Detector"))
|
||||
meta:set_string("formspec", formspec(meta))
|
||||
minetest.get_node_timer(pos):start(CYCLE_TIME)
|
||||
end,
|
||||
|
||||
on_receive_fields = on_receive_fields,
|
||||
|
||||
on_timer = function (pos, elapsed)
|
||||
if scan_for_player(pos) then
|
||||
switch_on(pos, 4)
|
||||
end
|
||||
return true
|
||||
end,
|
||||
|
||||
techage_set_numbers = function(pos, numbers, player_name)
|
||||
local meta = M(pos)
|
||||
local res = logic.set_numbers(pos, numbers, player_name, S("TA4 Player Detector"))
|
||||
meta:set_string("formspec", formspec(meta))
|
||||
return res
|
||||
end,
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
techage.del_mem(pos)
|
||||
end,
|
||||
|
||||
ta4_formspec = WRENCH_MENU,
|
||||
paramtype = "light",
|
||||
sunlight_propagates = true,
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy=2, cracky=2, crumbly=2},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
})
|
||||
|
||||
minetest.register_node("techage:ta4_playerdetector_on", {
|
||||
description = "TA4 Player Detector",
|
||||
inventory_image = 'techage_smartline_detector_inv.png',
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"techage_smartline.png",
|
||||
"techage_smartline.png",
|
||||
"techage_smartline.png",
|
||||
"techage_smartline.png",
|
||||
"techage_smartline.png",
|
||||
"techage_smartline.png^techage_smartline_detector_on.png",
|
||||
},
|
||||
|
||||
drawtype = "nodebox",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{ -6/32, -6/32, 14/32, 6/32, 6/32, 16/32},
|
||||
},
|
||||
},
|
||||
on_receive_fields = on_receive_fields,
|
||||
|
||||
on_timer = function (pos, elapsed)
|
||||
if not scan_for_player(pos) then
|
||||
switch_off(pos, 4)
|
||||
end
|
||||
return true
|
||||
end,
|
||||
|
||||
techage_set_numbers = function(pos, numbers, player_name)
|
||||
local meta = M(pos)
|
||||
local res = logic.set_numbers(pos, numbers, player_name, S("TA4 Player Detector"))
|
||||
meta:set_string("formspec", formspec(meta))
|
||||
return res
|
||||
end,
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
techage.del_mem(pos)
|
||||
end,
|
||||
|
||||
ta4_formspec = WRENCH_MENU,
|
||||
paramtype = "light",
|
||||
sunlight_propagates = true,
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy=2, cracky=2, crumbly=2, not_in_creative_inventory=1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
drop = "techage:ta4_playerdetector_off"
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:ta3_playerdetector_off",
|
||||
recipe = {
|
||||
{"", "group:wood", "default:mese_crystal"},
|
||||
{"", "default:copper_ingot", "techage:vacuum_tube"},
|
||||
{"", "group:wood", ""},
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:ta4_playerdetector_off",
|
||||
recipe = {
|
||||
{"", "techage:aluminum", "dye:blue"},
|
||||
{"", "default:copper_ingot", "techage:ta4_wlanchip"},
|
||||
},
|
||||
})
|
||||
|
||||
techage.register_node({
|
||||
"techage:ta3_playerdetector_off", "techage:ta3_playerdetector_on",
|
||||
"techage:ta4_playerdetector_off", "techage:ta4_playerdetector_on"
|
||||
}, {
|
||||
on_recv_message = function(pos, src, topic, payload)
|
||||
if topic == "name" then
|
||||
local nvm = techage.get_nvm(pos)
|
||||
return nvm.player_name or ""
|
||||
elseif topic == "state" then
|
||||
local node = techage.get_node_lvm(pos)
|
||||
if node.name == "techage:ta3_playerdetector_on" or
|
||||
node.name == "techage:ta4_playerdetector_on" then
|
||||
return "on"
|
||||
else
|
||||
return "off"
|
||||
end
|
||||
else
|
||||
return "unsupported"
|
||||
end
|
||||
end,
|
||||
on_beduino_request_data = function(pos, src, topic, payload)
|
||||
if topic == 144 then -- Player Name
|
||||
local nvm = techage.get_nvm(pos)
|
||||
return 0, nvm.player_name or ""
|
||||
elseif topic == 142 then -- Binary State
|
||||
local node = techage.get_node_lvm(pos)
|
||||
if node.name == "techage:ta3_playerdetector_on" or
|
||||
node.name == "techage:ta4_playerdetector_on" then
|
||||
return 0, {1}
|
||||
else
|
||||
return 0, {0}
|
||||
end
|
||||
else
|
||||
return 2, ""
|
||||
end
|
||||
end,
|
||||
on_node_load = function(pos)
|
||||
minetest.get_node_timer(pos):start(CYCLE_TIME)
|
||||
end,
|
||||
}
|
||||
)
|
||||
@@ -0,0 +1,100 @@
|
||||
--[[
|
||||
|
||||
TechAge
|
||||
=======
|
||||
|
||||
Copyright (C) 2017-2020 Joachim Stolberg
|
||||
|
||||
AGPL v3
|
||||
See LICENSE.txt for more information
|
||||
|
||||
Number programmer
|
||||
|
||||
]]--
|
||||
|
||||
-- for lazy programmers
|
||||
local M = minetest.get_meta
|
||||
local S = techage.S
|
||||
|
||||
local function join_to_string(tbl)
|
||||
local t = {}
|
||||
for key,_ in pairs(tbl) do
|
||||
t[#t + 1] = key
|
||||
end
|
||||
return table.concat(t, " ")
|
||||
end
|
||||
|
||||
local function reset_programmer(itemstack, user, pointed_thing)
|
||||
user:get_meta():set_string("techage_prog_numbers", "")
|
||||
minetest.chat_send_player(user:get_player_name(), S("[TechAge Programmer] programmer reset"))
|
||||
return itemstack
|
||||
end
|
||||
|
||||
local function read_number(itemstack, user, pointed_thing)
|
||||
local pos = pointed_thing.under
|
||||
if pos then
|
||||
local number = techage.get_node_number(pos)
|
||||
if number then
|
||||
local numbers = minetest.deserialize(user:get_meta():get_string("techage_prog_numbers")) or {}
|
||||
techage.add_to_set(numbers, number)
|
||||
user:get_meta():set_string("techage_prog_numbers", minetest.serialize(numbers))
|
||||
minetest.chat_send_player(user:get_player_name(), S("[TechAge Programmer] number").." "..number.." read")
|
||||
else
|
||||
minetest.chat_send_player(user:get_player_name(), S("[TechAge Programmer] Unknown node on").." "..minetest.pos_to_string(pos))
|
||||
end
|
||||
else
|
||||
return reset_programmer(itemstack, user, pointed_thing)
|
||||
end
|
||||
return itemstack
|
||||
end
|
||||
|
||||
local function program_numbers(itemstack, placer, pointed_thing)
|
||||
local pos = pointed_thing.under
|
||||
if pos then
|
||||
local meta = M(pos)
|
||||
local numbers = minetest.deserialize(placer:get_meta():get_string("techage_prog_numbers")) or {}
|
||||
placer:get_meta():set_string("techage_prog_numbers", "")
|
||||
local player_name = placer:get_player_name()
|
||||
if meta and meta:get_string("owner") ~= player_name then
|
||||
minetest.chat_send_player(player_name, S("[TechAge Programmer] foreign or unknown node!"))
|
||||
return itemstack
|
||||
end
|
||||
local text = table.concat(numbers, " ")
|
||||
local ndef = minetest.registered_nodes[minetest.get_node(pos).name]
|
||||
if ndef and ndef.techage_set_numbers then
|
||||
local res = ndef.techage_set_numbers(pos, text, player_name)
|
||||
if res == true then
|
||||
minetest.chat_send_player(player_name, S("[TechAge Programmer] node programmed!"))
|
||||
else
|
||||
minetest.chat_send_player(player_name, S("[TechAge Programmer] Error: invalid numbers!"))
|
||||
end
|
||||
else
|
||||
minetest.chat_send_player(player_name, S("[TechAge Programmer] Error: programmer not supported!"))
|
||||
end
|
||||
return itemstack
|
||||
else
|
||||
return reset_programmer(itemstack, placer, pointed_thing)
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_craftitem("techage:programmer", {
|
||||
description = S("TechAge Programmer (right = read number, left = write numbers)"),
|
||||
inventory_image = "techage_programmer.png",
|
||||
stack_max = 1,
|
||||
wield_image = "techage_programmer_wield.png",
|
||||
groups = {cracky=1, book=1},
|
||||
-- left mouse button = program
|
||||
on_use = program_numbers,
|
||||
on_secondary_use = reset_programmer,
|
||||
-- right mouse button = read
|
||||
on_place = read_number,
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:programmer",
|
||||
recipe = {
|
||||
{"", "default:steel_ingot", ""},
|
||||
{"", "techage:ta4_wlanchip", ""},
|
||||
{"", "dye:red", ""},
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,132 @@
|
||||
--[[
|
||||
|
||||
TechAge
|
||||
=======
|
||||
|
||||
Copyright (C) 2017-2020 Joachim Stolberg
|
||||
|
||||
AGPL v3
|
||||
See LICENSE.txt for more information
|
||||
|
||||
Signal Repeater
|
||||
|
||||
]]--
|
||||
|
||||
-- for lazy programmers
|
||||
local M = minetest.get_meta
|
||||
local S = techage.S
|
||||
|
||||
local logic = techage.logic
|
||||
local OVER_LOAD_MAX = 10
|
||||
local CYCLE_TIME = 2
|
||||
|
||||
local function formspec(meta)
|
||||
local numbers = meta:get_string("numbers") or ""
|
||||
return "size[7.5,3]"..
|
||||
"field[0.5,1;7,1;numbers;"..S("Insert destination node number(s)")..";"..numbers.."]" ..
|
||||
"button_exit[2,2;3,1;exit;"..S("Save").."]"
|
||||
end
|
||||
|
||||
minetest.register_node("techage:ta3_repeater", {
|
||||
description = S("TA3 Repeater"),
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_repeater.png",
|
||||
},
|
||||
|
||||
after_place_node = function(pos, placer)
|
||||
local meta = M(pos)
|
||||
local mem = techage.get_mem(pos)
|
||||
logic.after_place_node(pos, placer, "techage:ta3_repeater", S("TA3 Repeater"))
|
||||
logic.infotext(meta, S("TA3 Repeater"))
|
||||
meta:set_string("formspec", formspec(meta))
|
||||
mem.overload_cnt = 0
|
||||
minetest.get_node_timer(pos):start(CYCLE_TIME)
|
||||
end,
|
||||
|
||||
on_receive_fields = function(pos, formname, fields, player)
|
||||
if minetest.is_protected(pos, player:get_player_name()) then
|
||||
return
|
||||
end
|
||||
|
||||
local meta = M(pos)
|
||||
if techage.check_numbers(fields.numbers, player:get_player_name()) then
|
||||
meta:set_string("numbers", fields.numbers)
|
||||
logic.infotext(M(pos), S("TA3 Repeater"))
|
||||
meta:set_string("formspec", formspec(meta))
|
||||
end
|
||||
end,
|
||||
|
||||
on_timer = function(pos,elapsed)
|
||||
local mem = techage.get_mem(pos)
|
||||
mem.overload_cnt = 0
|
||||
return true
|
||||
end,
|
||||
|
||||
techage_set_numbers = function(pos, numbers, player_name)
|
||||
local meta = M(pos)
|
||||
local res = logic.set_numbers(pos, numbers, player_name, S("TA3 Repeater"))
|
||||
meta:set_string("formspec", formspec(meta))
|
||||
return res
|
||||
end,
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
techage.del_mem(pos)
|
||||
end,
|
||||
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy=2, cracky=2, crumbly=2},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
})
|
||||
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:ta3_repeater",
|
||||
recipe = {
|
||||
{"", "group:wood", ""},
|
||||
{"techage:vacuum_tube", "", "techage:vacuum_tube"},
|
||||
{"", "group:wood", ""},
|
||||
},
|
||||
})
|
||||
|
||||
techage.register_node({"techage:ta3_repeater"}, {
|
||||
on_recv_message = function(pos, src, topic, payload)
|
||||
local mem = techage.get_mem(pos)
|
||||
mem.overload_cnt = (mem.overload_cnt or 0) + 1
|
||||
if mem.overload_cnt > OVER_LOAD_MAX then
|
||||
logic.infotext(M(pos), S("TA3 Repeater"), "fault (overloaded)")
|
||||
minetest.get_node_timer(pos):stop()
|
||||
return false
|
||||
else
|
||||
local numbers = M(pos):get_string("numbers") or ""
|
||||
techage.counting_start(M(pos):get_string("owner"))
|
||||
techage.send_multi(src, numbers, topic, payload)
|
||||
techage.counting_stop()
|
||||
end
|
||||
end,
|
||||
on_beduino_receive_cmnd = function(pos, src, topic, payload)
|
||||
local mem = techage.get_mem(pos)
|
||||
mem.overload_cnt = (mem.overload_cnt or 0) + 1
|
||||
if mem.overload_cnt > OVER_LOAD_MAX then
|
||||
logic.infotext(M(pos), S("TA3 Repeater"), "fault (overloaded)")
|
||||
minetest.get_node_timer(pos):stop()
|
||||
return 3
|
||||
else
|
||||
if topic == 1 then
|
||||
local numbers = M(pos):get_string("numbers") or ""
|
||||
techage.counting_start(M(pos):get_string("owner"))
|
||||
techage.send_multi(src, numbers, payload[1] == 1 and "on" or "off")
|
||||
techage.counting_stop()
|
||||
return 0
|
||||
end
|
||||
end
|
||||
return 2
|
||||
end,
|
||||
on_node_load = function(pos)
|
||||
minetest.get_node_timer(pos):start(CYCLE_TIME)
|
||||
end,
|
||||
})
|
||||
@@ -0,0 +1,309 @@
|
||||
--[[
|
||||
|
||||
TechAge
|
||||
=======
|
||||
|
||||
Copyright (C) 2017-2022 Joachim Stolberg
|
||||
|
||||
AGPL v3
|
||||
See LICENSE.txt for more information
|
||||
|
||||
TA3 Sequencer
|
||||
|
||||
]]--
|
||||
|
||||
-- for lazy programmers
|
||||
local M = minetest.get_meta
|
||||
local S = techage.S
|
||||
|
||||
local logic = techage.logic
|
||||
local NUM_SLOTS = 8
|
||||
|
||||
local sAction = ",on,off"
|
||||
local kvAction = {[""]=1, ["on"]=2, ["off"]=3}
|
||||
local tAction = {nil, "on", "off"}
|
||||
|
||||
local function new_rules()
|
||||
local tbl = {}
|
||||
for idx = 1,NUM_SLOTS do
|
||||
tbl[idx] = {offs = "", num = "", act = 1}
|
||||
end
|
||||
return tbl
|
||||
end
|
||||
|
||||
local function formspec(state, rules, endless)
|
||||
local tbl = {"size[8,9.2]"..
|
||||
default.gui_bg..
|
||||
default.gui_bg_img..
|
||||
default.gui_slots..
|
||||
"label[0,0;Number(s)]label[2.1,0;Command]label[6.4,0;Offset/s]"}
|
||||
|
||||
for idx, rule in ipairs(rules or {}) do
|
||||
tbl[#tbl+1] = "field[0.2,"..(-0.2+idx)..";2,1;num"..idx..";;"..(rule.num or "").."]"
|
||||
tbl[#tbl+1] = "dropdown[2,"..(-0.4+idx)..";3.9,1;act"..idx..";"..sAction..";"..(rule.act or "").."]"
|
||||
tbl[#tbl+1] = "field[6.2,"..(-0.2+idx)..";2,1;offs"..idx..";;"..(rule.offs or "").."]"
|
||||
end
|
||||
tbl[#tbl+1] = "checkbox[0,8.5;endless;Run endless;"..dump(endless).."]"
|
||||
tbl[#tbl+1] = "button[2.2,8.5;1.5,1;help;help]"
|
||||
tbl[#tbl+1] = "button[4.2,8.5;1.5,1;save;Save]"
|
||||
tbl[#tbl+1] = "image_button[6.2,8.5;1,1;".. techage.state_button(state) ..";button;]"
|
||||
|
||||
return table.concat(tbl)
|
||||
end
|
||||
|
||||
local function formspec_help()
|
||||
return "size[8,9.2]"..
|
||||
default.gui_bg..
|
||||
default.gui_bg_img..
|
||||
default.gui_slots..
|
||||
"label[2,0;TA3 Sequencer Help]"..
|
||||
"label[0,1;Define a sequence of commands\nto control other machines.]"..
|
||||
"label[0,2.2;Numbers(s) are the node numbers,\nthe command shall sent to.]"..
|
||||
"label[0,3.4;The commands 'on'/'off' are used\n for machines and other nodes.]"..
|
||||
"label[0,4.6;Offset is the time to the\nnext line in seconds (0.2 to 999).]"..
|
||||
"label[0,5.8;If endless is set, the Sequencer\nrestarts again and again.]"..
|
||||
"label[0,7;The command ' ' does nothing,\nonly consuming the offset time.]"..
|
||||
"button[3,8;2,1;exit;close]"
|
||||
end
|
||||
|
||||
local function stop_the_sequencer(pos)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
local meta = M(pos)
|
||||
nvm.running = false
|
||||
nvm.endless = nvm.endless or false
|
||||
nvm.rules = nvm.rules or new_rules()
|
||||
logic.infotext(meta, S("TA3 Sequencer"), "stopped")
|
||||
meta:set_string("formspec", formspec(techage.STOPPED, nvm.rules, nvm.endless))
|
||||
minetest.get_node_timer(pos):stop()
|
||||
return false
|
||||
end
|
||||
|
||||
local function get_next_slot(idx, rules, endless)
|
||||
idx = idx + 1
|
||||
if idx <= #rules and rules[idx].offs ~= "" and rules[idx].num ~= "" then
|
||||
return idx
|
||||
elseif endless then
|
||||
return 1
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function restart_timer(pos, time)
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
if timer:is_started() then
|
||||
timer:stop()
|
||||
end
|
||||
if type(time) == "number" then
|
||||
time = math.max(time, 0.2)
|
||||
timer:start(time)
|
||||
end
|
||||
end
|
||||
|
||||
local function check_rules(pos, elapsed)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
local own_num = M(pos):get_string("node_number")
|
||||
nvm.rules = nvm.rules or new_rules()
|
||||
nvm.running = nvm.running or false
|
||||
nvm.index = nvm.index or 1
|
||||
nvm.endless = nvm.endless or false
|
||||
techage.counting_start(M(pos):get_string("owner"))
|
||||
while true do -- process all rules as long as offs == 0
|
||||
local rule = nvm.rules[nvm.index]
|
||||
local offs = tonumber(nvm.rules[nvm.index].offs or 1)
|
||||
techage.send_multi(own_num, rule.num, tAction[rule.act])
|
||||
nvm.index = get_next_slot(nvm.index, nvm.rules, nvm.endless)
|
||||
if nvm.index ~= nil and offs ~= nil and nvm.running then
|
||||
-- after the last rule a pause with 1 or more sec is required
|
||||
if nvm.index == 1 and offs < 1 then
|
||||
offs = 1
|
||||
end
|
||||
if offs > 0 then
|
||||
-- we can't restart the timer within the function om_timer
|
||||
minetest.after(0, restart_timer, pos, offs)
|
||||
techage.counting_stop()
|
||||
return false
|
||||
end
|
||||
else
|
||||
techage.counting_stop()
|
||||
return stop_the_sequencer(pos)
|
||||
end
|
||||
end
|
||||
techage.counting_stop()
|
||||
return false
|
||||
end
|
||||
|
||||
local function start_the_sequencer(pos)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
if not nvm.running then
|
||||
local meta = M(pos)
|
||||
nvm.running = true
|
||||
nvm.endless = nvm.endless or false
|
||||
nvm.rules = nvm.rules or new_rules()
|
||||
logic.infotext(meta, S("TA3 Sequencer"), "running")
|
||||
meta:set_string("formspec", formspec(techage.RUNNING, nvm.rules, nvm.endless))
|
||||
minetest.get_node_timer(pos):start(0.1)
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function on_receive_fields(pos, formname, fields, player)
|
||||
if minetest.is_protected(pos, player:get_player_name()) then
|
||||
return
|
||||
end
|
||||
|
||||
local meta = M(pos)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
nvm.running = nvm.running or false
|
||||
nvm.endless = nvm.endless or false
|
||||
nvm.rules = nvm.rules or new_rules()
|
||||
|
||||
if fields.help ~= nil then
|
||||
meta:set_string("formspec", formspec_help())
|
||||
return
|
||||
end
|
||||
|
||||
if fields.endless ~= nil then
|
||||
nvm.endless = fields.endless == "true"
|
||||
nvm.index = 1
|
||||
end
|
||||
|
||||
if fields.exit ~= nil then
|
||||
if nvm.running then
|
||||
meta:set_string("formspec", formspec(techage.RUNNING, nvm.rules, nvm.endless))
|
||||
else
|
||||
meta:set_string("formspec", formspec(techage.STOPPED, nvm.rules, nvm.endless))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
for idx = 1,NUM_SLOTS do
|
||||
if fields["offs"..idx] ~= nil then
|
||||
nvm.rules[idx].offs = tonumber(fields["offs"..idx]) or ""
|
||||
end
|
||||
if fields["num"..idx] ~= nil and
|
||||
techage.check_numbers(fields["num"..idx], player:get_player_name()) then
|
||||
nvm.rules[idx].num = fields["num"..idx]
|
||||
end
|
||||
if fields["act"..idx] ~= nil then
|
||||
nvm.rules[idx].act = kvAction[fields["act"..idx]]
|
||||
end
|
||||
end
|
||||
|
||||
if fields.button ~= nil then
|
||||
if nvm.running then
|
||||
stop_the_sequencer(pos)
|
||||
else
|
||||
start_the_sequencer(pos)
|
||||
end
|
||||
elseif fields.num1 ~= nil then -- any other change?
|
||||
stop_the_sequencer(pos)
|
||||
else
|
||||
if nvm.running then
|
||||
meta:set_string("formspec", formspec(techage.RUNNING, nvm.rules, nvm.endless))
|
||||
else
|
||||
meta:set_string("formspec", formspec(techage.STOPPED, nvm.rules, nvm.endless))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_node("techage:ta3_sequencer", {
|
||||
description = S("TA3 Sequencer"),
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_sequencer.png",
|
||||
},
|
||||
|
||||
after_place_node = function(pos, placer)
|
||||
local meta = M(pos)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
logic.after_place_node(pos, placer, "techage:ta3_sequencer", S("TA3 Sequencer"))
|
||||
logic.infotext(meta, S("TA3 Sequencer"), S("stopped"))
|
||||
nvm.rules = new_rules()
|
||||
nvm.index = 1
|
||||
nvm.running = false
|
||||
nvm.endless = false
|
||||
meta:set_string("formspec", formspec(techage.STOPPED, nvm.rules, nvm.endless))
|
||||
end,
|
||||
|
||||
on_receive_fields = on_receive_fields,
|
||||
|
||||
can_dig = function(pos, puncher)
|
||||
if minetest.is_protected(pos, puncher:get_player_name()) then
|
||||
return false
|
||||
end
|
||||
local nvm = techage.get_nvm(pos)
|
||||
return not nvm.running
|
||||
end,
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
techage.del_mem(pos)
|
||||
end,
|
||||
|
||||
on_timer = check_rules,
|
||||
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy=2, cracky=2, crumbly=2},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
})
|
||||
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:ta3_sequencer",
|
||||
recipe = {
|
||||
{"group:wood", "group:wood", ""},
|
||||
{"default:mese_crystal", "techage:vacuum_tube", ""},
|
||||
{"group:wood", "group:wood", ""},
|
||||
},
|
||||
})
|
||||
|
||||
techage.register_node({"techage:ta3_sequencer"}, {
|
||||
on_recv_message = function(pos, src, topic, payload)
|
||||
if topic == "on" then
|
||||
start_the_sequencer(pos)
|
||||
elseif topic == "off" then
|
||||
-- do not stop immediately
|
||||
local nvm = techage.get_nvm(pos)
|
||||
if not nvm.running then
|
||||
nvm.endless = not (nvm.endless or false)
|
||||
else
|
||||
nvm.endless = false
|
||||
end
|
||||
elseif topic == "pause" then
|
||||
stop_the_sequencer(pos)
|
||||
else
|
||||
return "unsupported"
|
||||
end
|
||||
end,
|
||||
on_beduino_receive_cmnd = function(pos, src, topic, payload)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
if topic == 7 then -- TA3 Sequenzer
|
||||
if payload[1] == 1 then
|
||||
start_the_sequencer(pos)
|
||||
return 0
|
||||
elseif payload[1] == 0 then
|
||||
-- do not stop immediately
|
||||
local nvm = techage.get_nvm(pos)
|
||||
if not nvm.running then
|
||||
nvm.endless = not (nvm.endless or false)
|
||||
else
|
||||
nvm.endless = false
|
||||
end
|
||||
return 0
|
||||
elseif payload[1] == 2 then
|
||||
stop_the_sequencer(pos)
|
||||
return 0
|
||||
end
|
||||
end
|
||||
return 2
|
||||
end,
|
||||
on_node_load = function(pos)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
if nvm.running then
|
||||
minetest.get_node_timer(pos):start(1)
|
||||
end
|
||||
end,
|
||||
})
|
||||
@@ -0,0 +1,409 @@
|
||||
--[[
|
||||
|
||||
TechAge
|
||||
=======
|
||||
|
||||
Copyright (C) 2017-2025 Joachim Stolberg
|
||||
|
||||
AGPL v3
|
||||
See LICENSE.txt for more information
|
||||
|
||||
TA4 Sequencer
|
||||
|
||||
]]--
|
||||
|
||||
-- for lazy programmers
|
||||
local M = minetest.get_meta
|
||||
local S = techage.S
|
||||
|
||||
local logic = techage.logic
|
||||
|
||||
local HELP = S("Syntax:\n") ..
|
||||
S("'[<num>] <command>'\n") ..
|
||||
S("\n") ..
|
||||
S("<num> is a number from 1 to 50000 and is\n") ..
|
||||
S("the timeslot when the command is executed.\n") ..
|
||||
S(" - 1 corresponds to 100 ms\n") ..
|
||||
S(" - 50000 corresponds to 4 game days\n") ..
|
||||
S("\n") ..
|
||||
S("<command> is one of the following:\n") ..
|
||||
S(" - 'send <node num> <cmnd>' (techage command)\n") ..
|
||||
S(" - 'goto <num>' (jump to another line)\n") ..
|
||||
S(" - 'stop' (stop the execution)\n") ..
|
||||
S(" - 'nop' (do nothing)\n") ..
|
||||
S("\n") ..
|
||||
S("Example:\n") ..
|
||||
" -- move controller commands\n" ..
|
||||
" [1] send 1234 a2b\n" ..
|
||||
" [30] send 1234 b2a\n" ..
|
||||
" [60] goto 1 -- keep going"
|
||||
|
||||
local WRENCH_MENU = {
|
||||
{
|
||||
type = "dropdown",
|
||||
choices = "100ms,200ms,500ms,1s,2s",
|
||||
name = "cycletime",
|
||||
label = S("Cycle time"),
|
||||
tooltip = S("Timer cycle time (default: 100 ms)"),
|
||||
default = "100ms",
|
||||
values = {0.1, 0.2, 0.5, 1.0, 2.0}
|
||||
},
|
||||
{
|
||||
type = "dropdown",
|
||||
choices = "no,yes",
|
||||
name = "ignore_off",
|
||||
label = S("Ignore OFF command"),
|
||||
tooltip = S("If 'yes' a received OFF command won't stop the sequencer"),
|
||||
default = "no",
|
||||
values = {0, 1}
|
||||
},
|
||||
{
|
||||
type = "dropdown",
|
||||
choices = "no,yes",
|
||||
name = "reset",
|
||||
label = S("Reset on reload"),
|
||||
tooltip = S("Restart the sequencer when the map block is reloaded"),
|
||||
default = "yes",
|
||||
values = {0, 1}
|
||||
},
|
||||
{
|
||||
type = "number",
|
||||
name = "delay",
|
||||
label = S("Delay on reload"),
|
||||
tooltip = S("Delay in seconds for start of execution when map block is reloaded"),
|
||||
default = "0",
|
||||
},
|
||||
}
|
||||
|
||||
local function cycle_time(pos)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
if not nvm.cycletime then
|
||||
nvm.cycletime = tonumber(M(pos):get_string("cycletime")) or 0.1
|
||||
end
|
||||
return nvm.cycletime
|
||||
end
|
||||
|
||||
|
||||
local function strsplit(text)
|
||||
text = text:gsub("\r\n", "\n")
|
||||
text = text:gsub("\r", "\n")
|
||||
return string.split(text, "\n", true)
|
||||
end
|
||||
|
||||
local function trim(s)
|
||||
return (s:gsub("^%s*(.-)%s*$", "%1"))
|
||||
end
|
||||
|
||||
local function command(s)
|
||||
local num, cmd, pld = unpack(string.split(s, " ", false, 2))
|
||||
if not num or not cmd then
|
||||
return S("Invalid command!")
|
||||
end
|
||||
return {number = num, cmnd = cmd, payload = pld}
|
||||
end
|
||||
|
||||
local function add_error(text, line_num)
|
||||
local tbl = {}
|
||||
for idx, line in ipairs(strsplit(text)) do
|
||||
if idx == line_num and not string.find(line, '--<<== error') then
|
||||
tbl[#tbl+1] = line.." --<<== error"
|
||||
else
|
||||
tbl[#tbl+1] = line
|
||||
end
|
||||
end
|
||||
return table.concat(tbl, "\n")
|
||||
end
|
||||
|
||||
local function exception(tRes, line, s)
|
||||
if tRes then
|
||||
tRes.line = line
|
||||
tRes.error = s
|
||||
end
|
||||
end
|
||||
|
||||
local function compile(s, tRes)
|
||||
local tCode = {}
|
||||
local old_idx = 0
|
||||
local start_idx
|
||||
|
||||
for i, line in ipairs(strsplit(s)) do
|
||||
line = trim(line)
|
||||
line = string.split(line, "--", true, 1)[1] or ""
|
||||
if line ~= "" then
|
||||
local idx, cmnd1, cmnd2 = unpack(string.split(line, " ", false, 2))
|
||||
idx = tonumber(string.match(idx, "^%[(%d+)%]$"))
|
||||
if not idx then
|
||||
return exception(tRes, i, "Syntax error!")
|
||||
end
|
||||
if idx > 50000 then
|
||||
return exception(tRes, i, "Order error!")
|
||||
end
|
||||
if idx <= old_idx then
|
||||
return exception(tRes, i, "Order error!")
|
||||
end
|
||||
start_idx = start_idx or idx
|
||||
if old_idx ~= 0 and tCode[old_idx] and not tCode[old_idx].next_idx then
|
||||
tCode[old_idx].next_idx = idx
|
||||
end
|
||||
if cmnd1 == "send" then
|
||||
local res = command(cmnd2)
|
||||
if type(res) == "string" then
|
||||
return exception(tRes, i, res)
|
||||
end
|
||||
tCode[idx] = res
|
||||
elseif cmnd1 == "goto" then
|
||||
tCode[idx] = {next_idx = tonumber(cmnd2) or 1}
|
||||
elseif cmnd1 == "stop" then
|
||||
tCode[idx] = false
|
||||
elseif cmnd1 == nil or cmnd1 == "nop" then
|
||||
tCode[idx] = {}
|
||||
end
|
||||
old_idx = idx
|
||||
end
|
||||
end
|
||||
-- Returns:
|
||||
-- {
|
||||
-- start_idx = 1,
|
||||
-- tCode = {
|
||||
-- <idx> = {number = <number>, cmnd = <string>, payload = <data>, next_idx = <idx>},
|
||||
-- ...
|
||||
-- },
|
||||
-- }
|
||||
return {start_idx=start_idx, tCode=tCode}
|
||||
end
|
||||
|
||||
local function check_syntax(meta)
|
||||
local tRes = {}
|
||||
local res = compile(meta:get_string("text"), tRes)
|
||||
if not res then
|
||||
meta:set_string("err_msg", tRes.error)
|
||||
meta:set_string("text", add_error(meta:get_string("text"), tRes.line))
|
||||
return false
|
||||
else
|
||||
meta:set_string("err_msg", "")
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
local function formspec(nvm, meta)
|
||||
local text = meta:get_string("text")
|
||||
text = minetest.formspec_escape(text)
|
||||
local bttn = nvm.running and ("stop;" .. S("Stop")) or ("start;" .. S("Start"))
|
||||
local style = nvm.running and "style_type[textarea;font=mono;textcolor=#888888;border=false]" or
|
||||
"style_type[textarea;font=mono;textcolor=#FFFFFF;border=false]"
|
||||
local textarea = nvm.running and "textarea[0.3,0.2;10,8.3;;;"..text.."]" or
|
||||
"textarea[0.3,0.2;10,8.3;text;;"..text.."]"
|
||||
|
||||
return "size[10,8]" ..
|
||||
style ..
|
||||
techage.wrench_image(9.3, -0.25) ..
|
||||
"tabheader[0,0;tab;edit,help;1;;true]" ..
|
||||
"label[0.1,-0.2;" .. S("Commands") .. ":]" ..
|
||||
textarea ..
|
||||
"background[0.1,0.3;9.8,7.0;techage_form_mask.png]" ..
|
||||
"label[0.1,7.5;" .. meta:get_string("err_msg") .. "]" ..
|
||||
"button_exit[3.4,7.5;2.2,1;cancel;" .. S("Cancel") .. "]" ..
|
||||
"button[5.6,7.5;2.2,1;save;" .. S("Save") .. "]" ..
|
||||
"button[7.8,7.5;2.2,1;" .. bttn .. "]"
|
||||
end
|
||||
|
||||
local function formspec_help(meta)
|
||||
local text = "" --minetest.formspec_escape("hepl")
|
||||
return "size[10,8]"..
|
||||
"style_type[textarea;font=mono;textcolor=#FFFFFF;border=false]"..
|
||||
"tabheader[0,0;tab;edit,help;2;;true]"..
|
||||
"textarea[0.3,0.3;10,9;;" .. S("Help") .. ":;"..minetest.formspec_escape(HELP).."]" ..
|
||||
"background[0.1,0.3;9.8,8.0;techage_form_mask.png]"
|
||||
end
|
||||
|
||||
local function restart_timer(pos, ticks)
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
if timer:is_started() then
|
||||
timer:stop()
|
||||
end
|
||||
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
|
||||
nvm.code = nvm.code or compile(M(pos):get_string("text"))
|
||||
if nvm.code then
|
||||
nvm.idx = nvm.idx or nvm.code.start_idx
|
||||
local code = nvm.code.tCode[nvm.idx]
|
||||
if code and code.cmnd then
|
||||
local src = M(pos):get_string("node_number")
|
||||
techage.counting_start(M(pos):get_string("owner"))
|
||||
techage.send_single(src, code.number, code.cmnd, code.payload)
|
||||
techage.counting_stop()
|
||||
end
|
||||
if code and code.next_idx then
|
||||
local offs = code.next_idx - nvm.idx
|
||||
minetest.after(0, restart_timer, pos, math.max(offs, 1))
|
||||
nvm.idx = code.next_idx
|
||||
else
|
||||
nvm.running = false
|
||||
local meta = M(pos)
|
||||
meta:set_string("formspec", formspec(nvm, meta))
|
||||
logic.infotext(meta, S("TA4 Sequencer"), S("stopped"))
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function on_receive_fields(pos, formname, fields, player)
|
||||
if minetest.is_protected(pos, player:get_player_name()) then
|
||||
return
|
||||
end
|
||||
|
||||
local meta = M(pos)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
nvm.running = nvm.running or false
|
||||
|
||||
if fields.stop then
|
||||
nvm.running = false
|
||||
minetest.get_node_timer(pos):stop()
|
||||
logic.infotext(meta, S("TA4 Sequencer"), S("stopped"))
|
||||
elseif not nvm.running then
|
||||
if fields.tab == "2" then
|
||||
meta:set_string("formspec", formspec_help(meta))
|
||||
return
|
||||
elseif fields.tab == "1" then
|
||||
meta:set_string("formspec", formspec(nvm, meta))
|
||||
return
|
||||
end
|
||||
|
||||
if fields.save then
|
||||
nvm.running = false
|
||||
meta:set_string("text", fields.text or "")
|
||||
nvm.code = nil
|
||||
nvm.idx = nil
|
||||
elseif fields.start then
|
||||
if check_syntax(meta) then
|
||||
nvm.running = true
|
||||
meta:set_string("text", fields.text or "")
|
||||
nvm.code = nil
|
||||
nvm.idx = nil
|
||||
nvm.cycletime = nil
|
||||
restart_timer(pos, 1)
|
||||
logic.infotext(meta, S("TA4 Sequencer"), S("running"))
|
||||
end
|
||||
end
|
||||
end
|
||||
meta:set_string("formspec", formspec(nvm, meta))
|
||||
end
|
||||
|
||||
minetest.register_node("techage:ta4_sequencer", {
|
||||
description = S("TA4 Sequencer"),
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"techage_filling_ta4.png^techage_frame_ta4_top.png",
|
||||
"techage_filling_ta4.png^techage_frame_ta4_top.png",
|
||||
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_sequencer.png",
|
||||
},
|
||||
|
||||
after_place_node = function(pos, placer)
|
||||
local meta = M(pos)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
logic.after_place_node(pos, placer, "techage:ta4_sequencer", S("TA4 Sequencer"))
|
||||
logic.infotext(meta, S("TA4 Sequencer"), S("stopped"))
|
||||
nvm.running = false
|
||||
meta:set_string("formspec", formspec(nvm, meta))
|
||||
end,
|
||||
|
||||
on_receive_fields = on_receive_fields,
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
techage.del_mem(pos)
|
||||
end,
|
||||
|
||||
on_timer = node_timer,
|
||||
ta4_formspec = WRENCH_MENU,
|
||||
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy=2, cracky=2, crumbly=2},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
})
|
||||
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:ta4_sequencer",
|
||||
recipe = {
|
||||
{"default:steel_ingot", "dye:blue", "default:steel_ingot"},
|
||||
{"techage:ta4_ramchip", "default:mese_crystal", "techage:ta4_wlanchip"},
|
||||
{"techage:aluminum", "group:wood", "techage:aluminum"},
|
||||
},
|
||||
})
|
||||
|
||||
local INFO = [[Commands: 'goto <num>', 'stop', '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
|
||||
nvm.running = true
|
||||
nvm.idx = tonumber(payload or 1) or 1
|
||||
restart_timer(pos, 1)
|
||||
logic.infotext(M(pos), S("TA4 Sequencer"), S("running"))
|
||||
elseif topic == "stop" or (topic == "off" and M(pos):get_int("ignore_off") == 0) then
|
||||
nvm.running = false
|
||||
minetest.get_node_timer(pos):stop()
|
||||
logic.infotext(M(pos), S("TA4 Sequencer"), S("stopped"))
|
||||
elseif topic == "info" then
|
||||
return INFO
|
||||
else
|
||||
return "unsupported"
|
||||
end
|
||||
end,
|
||||
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
|
||||
nvm.running = true
|
||||
nvm.idx = tonumber(payload or 1) or 1
|
||||
restart_timer(pos, 1)
|
||||
logic.infotext(M(pos), S("TA4 Sequencer"), S("running"))
|
||||
return 0
|
||||
elseif payload[1] == 0 then
|
||||
nvm.running = false
|
||||
minetest.get_node_timer(pos):stop()
|
||||
logic.infotext(M(pos), S("TA4 Sequencer"), S("stopped"))
|
||||
return 0
|
||||
end
|
||||
end
|
||||
return 2
|
||||
end,
|
||||
on_node_load = function(pos, node)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
local meta = M(pos)
|
||||
if not meta:contains("reset") then
|
||||
meta:set_int("reset", 1)
|
||||
end
|
||||
if not meta:contains("delay") then
|
||||
meta:set_int("delay", 1)
|
||||
end
|
||||
if nvm.running and meta:get_int("reset") == 1 then
|
||||
nvm.code = nil
|
||||
nvm.idx = nil
|
||||
nvm.cycletime = nil
|
||||
end
|
||||
if nvm.running and meta:get_int("delay") > 0 then
|
||||
restart_timer(pos, meta:get_int("delay") * 10)
|
||||
else
|
||||
restart_timer(pos, 1)
|
||||
end
|
||||
end,
|
||||
})
|
||||
@@ -0,0 +1,201 @@
|
||||
--[[
|
||||
|
||||
TechAge
|
||||
=======
|
||||
|
||||
Copyright (C) 2022-2023 Joachim Stolberg
|
||||
|
||||
AGPL v3
|
||||
See LICENSE.txt for more information
|
||||
|
||||
Colored Signal Lamps (with unifieddyes support)
|
||||
|
||||
]]--
|
||||
|
||||
-- for lazy programmers
|
||||
local M = minetest.get_meta
|
||||
local S = techage.S
|
||||
|
||||
local logic = techage.logic
|
||||
|
||||
local COLORED = minetest.get_modpath("unifieddyes") and minetest.global_exists("unifieddyes")
|
||||
|
||||
local LampsOff = {}
|
||||
local LampsOn = {}
|
||||
|
||||
local function switch_on(pos, node, player, color)
|
||||
if player and minetest.is_protected(pos, player:get_player_name()) then
|
||||
return
|
||||
end
|
||||
color = tonumber(color) or node.param2
|
||||
if LampsOff[node.name] then
|
||||
node.name = LampsOff[node.name]
|
||||
node.param2 = color
|
||||
minetest.swap_node(pos, node)
|
||||
elseif LampsOn[node.name] and color ~= node.param2 then
|
||||
node.param2 = color
|
||||
minetest.swap_node(pos, node)
|
||||
end
|
||||
end
|
||||
|
||||
local function switch_off(pos, node, player)
|
||||
if player and minetest.is_protected(pos, player:get_player_name()) then
|
||||
return
|
||||
end
|
||||
if LampsOn[node.name] then
|
||||
node.name = LampsOn[node.name]
|
||||
minetest.swap_node(pos, node)
|
||||
end
|
||||
end
|
||||
|
||||
local function register_signallamp(name, description, tiles_off, tiles_on, node_box)
|
||||
LampsOff[name .. "_off"] = name .. "_on"
|
||||
LampsOn[name .. "_on"] = name .. "_off"
|
||||
|
||||
minetest.register_node(name .. "_off", {
|
||||
description = description,
|
||||
tiles = tiles_off,
|
||||
drawtype = node_box and "nodebox",
|
||||
node_box = node_box,
|
||||
|
||||
after_place_node = function(pos, placer, itemstack, pointed_thing)
|
||||
logic.after_place_node(pos, placer, name .. "_off", description)
|
||||
logic.infotext(M(pos), description)
|
||||
if COLORED then
|
||||
unifieddyes.recolor_on_place(pos, placer, itemstack, pointed_thing)
|
||||
else
|
||||
local node = minetest.get_node(pos)
|
||||
node.param2 = 35
|
||||
minetest.swap_node(pos, node)
|
||||
end
|
||||
end,
|
||||
|
||||
on_rightclick = switch_on,
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
if COLORED then
|
||||
unifieddyes.after_dig_node(pos, oldnode, oldmetadata, digger)
|
||||
end
|
||||
end,
|
||||
|
||||
on_construct = COLORED and unifieddyes.on_construct or nil,
|
||||
on_dig = COLORED and unifieddyes.on_dig or nil,
|
||||
|
||||
paramtype = "light",
|
||||
paramtype2 = "color",
|
||||
--palette = "techage_palette256.png",
|
||||
palette = COLORED and "unifieddyes_palette_extended.png" or "techage_palette256.png",
|
||||
place_param2 = 240,
|
||||
sunlight_propagates = true,
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
groups = {choppy=2, cracky=1, ud_param2_colorable = 1},
|
||||
is_ground_content = false,
|
||||
drop = name .. "_off"
|
||||
})
|
||||
|
||||
minetest.register_node(name .. "_on", {
|
||||
description = description,
|
||||
tiles = tiles_on,
|
||||
drawtype = node_box and "nodebox",
|
||||
node_box = node_box,
|
||||
|
||||
on_rightclick = switch_off,
|
||||
|
||||
paramtype = "light",
|
||||
paramtype2 = "color",
|
||||
palette = COLORED and "unifieddyes_palette_extended.png" or "techage_palette256.png",
|
||||
groups = {choppy=2, cracky=1, not_in_creative_inventory=1, ud_param2_colorable = 1},
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
if COLORED then
|
||||
unifieddyes.after_dig_node(pos, oldnode, oldmetadata, digger)
|
||||
end
|
||||
end,
|
||||
|
||||
on_dig = COLORED and unifieddyes.on_dig or nil,
|
||||
light_source = 10,
|
||||
is_ground_content = false,
|
||||
drop = name .. "_off"
|
||||
})
|
||||
|
||||
techage.register_node({name .. "_off", name .. "_on"}, {
|
||||
on_recv_message = function(pos, src, topic, payload)
|
||||
if topic == "on" then
|
||||
local node = techage.get_node_lvm(pos)
|
||||
switch_on(pos, node)
|
||||
return true
|
||||
elseif topic == "off" then
|
||||
local node = techage.get_node_lvm(pos)
|
||||
switch_off(pos, node)
|
||||
return true
|
||||
elseif topic == "color" then
|
||||
local node = techage.get_node_lvm(pos)
|
||||
switch_on(pos, node, nil, payload)
|
||||
return true
|
||||
else
|
||||
return "unsupported"
|
||||
end
|
||||
end,
|
||||
on_beduino_receive_cmnd = function(pos, src, topic, payload)
|
||||
if topic == 1 and payload[1] == 1 then
|
||||
local node = techage.get_node_lvm(pos)
|
||||
switch_on(pos, node)
|
||||
return 0
|
||||
elseif topic == 1 and payload[1] == 0 then
|
||||
local node = techage.get_node_lvm(pos)
|
||||
switch_off(pos, node)
|
||||
return 0
|
||||
elseif topic == 70 or topic == 22 then
|
||||
local node = techage.get_node_lvm(pos)
|
||||
switch_on(pos, node, nil, payload[1])
|
||||
return 0
|
||||
else
|
||||
return 2
|
||||
end
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
register_signallamp("techage:color_lamp",
|
||||
S("TechAge Color Lamp"),
|
||||
{"techage_signal_lamp.png^[colorize:#000000:80"},
|
||||
{"techage_signal_lamp.png"},
|
||||
{
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{-6/16, -6/16, -6/16, 6/16, 6/16, 6/16},
|
||||
{-4/16, -10/16, -4/16, 4/16, -6/16, 4/16},
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
register_signallamp("techage:color_lamp2",
|
||||
S("TechAge Color Lamp 2"),
|
||||
{"techage_signallamp2.png^[colorize:#000000:80"},
|
||||
{"techage_signallamp2.png"}
|
||||
)
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:signal_lamp_off",
|
||||
recipe = {
|
||||
{"", "wool:white", ""},
|
||||
{"", "default:torch", ""},
|
||||
{"", "techage:vacuum_tube", ""},
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:signal_lamp2_off",
|
||||
recipe = {
|
||||
{"", "default:glass", ""},
|
||||
{"", "default:torch", ""},
|
||||
{"", "techage:vacuum_tube", ""},
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_alias("techage:signal_lamp_off", "techage:color_lamp_off")
|
||||
minetest.register_alias("techage:signal_lamp2_off", "techage:color_lamp2_off")
|
||||
minetest.register_alias("techage:signal_lamp_on", "techage:color_lamp_on")
|
||||
minetest.register_alias("techage:signal_lamp2_on", "techage:color_lamp2_on")
|
||||
@@ -0,0 +1,164 @@
|
||||
--[[
|
||||
|
||||
TechAge
|
||||
=======
|
||||
|
||||
Copyright (C) 2017-2022 Joachim Stolberg
|
||||
|
||||
AGPL v3
|
||||
See LICENSE.txt for more information
|
||||
|
||||
TA4 Logic twofold signal lamp
|
||||
|
||||
]]--
|
||||
|
||||
-- for lazy programmers
|
||||
local M = minetest.get_meta
|
||||
local S = techage.S
|
||||
|
||||
local OFF = 0
|
||||
local GREEN = 1
|
||||
local AMBER = 2
|
||||
local RED = 3
|
||||
|
||||
local WRENCH_MENU = {
|
||||
{
|
||||
type = "ascii",
|
||||
name = "label1",
|
||||
label = S("Label") .. " 1",
|
||||
tooltip = S("Label for the lamp"),
|
||||
default = "1",
|
||||
},
|
||||
{
|
||||
type = "ascii",
|
||||
name = "label2",
|
||||
label = S("Label") .. " 2",
|
||||
tooltip = S("Label for the lamp"),
|
||||
default = "2",
|
||||
},
|
||||
}
|
||||
|
||||
local function lamp_update(pos, objref)
|
||||
local meta = M(pos)
|
||||
pos = vector.round(pos)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
nvm.lamp = nvm.lamp or {}
|
||||
local tbl = {" ", " ", meta:get_string("label1"), " ", meta:get_string("label2")}
|
||||
local text = "< " .. table.concat(tbl, "\n< ")
|
||||
local texture = lcdlib.make_multiline_texture("default", text, 96, 96, 7, "top", "#000", 6)
|
||||
|
||||
if nvm.lamp[1] == RED then
|
||||
texture = texture .. "^techage_smartline_signal_red2.png"
|
||||
elseif nvm.lamp[1] == GREEN then
|
||||
texture = texture .. "^techage_smartline_signal_green2.png"
|
||||
elseif nvm.lamp[1] == AMBER then
|
||||
texture = texture .. "^techage_smartline_signal_amber2.png"
|
||||
end
|
||||
|
||||
if nvm.lamp[2] == RED then
|
||||
texture = texture .. "^techage_smartline_signal_red3.png"
|
||||
elseif nvm.lamp[2] == GREEN then
|
||||
texture = texture .. "^techage_smartline_signal_green3.png"
|
||||
elseif nvm.lamp[2] == AMBER then
|
||||
texture = texture .. "^techage_smartline_signal_amber3.png"
|
||||
end
|
||||
|
||||
objref:set_properties({ textures = {texture}, visual_size = {x=1, y=1} })
|
||||
end
|
||||
|
||||
local lcd_box = {-8/16, -4/16, 7.75/16, 8/16, 4/16, 8/16}
|
||||
|
||||
minetest.register_node("techage:ta4_signallamp_2x", {
|
||||
description = S("TA4 2x Signal Lamp"),
|
||||
inventory_image = 'techage_smartline_signal_2x.png^techage_smartline_signal_green2.png^techage_smartline_signal_amber3.png',
|
||||
tiles = {'techage_smartline_signal_2x.png'},
|
||||
drawtype = "nodebox",
|
||||
paramtype = "light",
|
||||
use_texture_alpha = "clip",
|
||||
sunlight_propagates = true,
|
||||
paramtype2 = "facedir",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = lcd_box,
|
||||
},
|
||||
light_source = 6,
|
||||
|
||||
display_entities = {
|
||||
["techage:display_entity"] = { depth = 0.48,
|
||||
on_display_update = lamp_update},
|
||||
},
|
||||
|
||||
after_place_node = function(pos, placer)
|
||||
local number = techage.add_node(pos, "techage:ta4_signallamp_2x")
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("node_number", number)
|
||||
meta:set_string("owner", placer:get_player_name())
|
||||
meta:set_string("infotext", S("TA4 2x Signal Lamp") .. " " .. number)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
nvm.lamp = {}
|
||||
lcdlib.update_entities(pos)
|
||||
end,
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
end,
|
||||
|
||||
ta_after_formspec = function(pos, fields, playername)
|
||||
lcdlib.update_entities(pos)
|
||||
end,
|
||||
|
||||
ta3_formspec = WRENCH_MENU,
|
||||
on_place = lcdlib.on_place,
|
||||
on_construct = lcdlib.on_construct,
|
||||
on_destruct = lcdlib.on_destruct,
|
||||
on_rotate = lcdlib.on_rotate,
|
||||
groups = {cracky=2, crumbly=2},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
})
|
||||
|
||||
techage.register_node({"techage:ta4_signallamp_2x"}, {
|
||||
on_recv_message = function(pos, src, topic, payload)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
nvm.lamp = nvm.lamp or {}
|
||||
if topic == "green" then
|
||||
local num = math.min(tonumber(payload) or 0, 2)
|
||||
nvm.lamp[num] = GREEN
|
||||
lcdlib.update_entities(pos)
|
||||
elseif topic == "amber" then
|
||||
local num = math.min(tonumber(payload) or 0, 2)
|
||||
nvm.lamp[num] = AMBER
|
||||
lcdlib.update_entities(pos)
|
||||
elseif topic == "red" then
|
||||
local num = math.min(tonumber(payload) or 0, 2)
|
||||
nvm.lamp[num] = RED
|
||||
lcdlib.update_entities(pos)
|
||||
elseif topic == "off" then
|
||||
local num = math.min(tonumber(payload) or 0, 2)
|
||||
nvm.lamp[num] = OFF
|
||||
lcdlib.update_entities(pos)
|
||||
end
|
||||
end,
|
||||
on_beduino_receive_cmnd = function(pos, src, topic, payload)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
nvm.lamp = nvm.lamp or {}
|
||||
if topic == 3 then -- Signal Lamp
|
||||
local num = math.min(payload[1] or 1, 2)
|
||||
local color = math.min(payload[2] or 0, 3)
|
||||
nvm.lamp[num] = color
|
||||
lcdlib.update_entities(pos)
|
||||
return 0
|
||||
else
|
||||
return 2
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:ta4_signallamp_2x",
|
||||
recipe = {
|
||||
{"", "techage:aluminum", "dye:blue"},
|
||||
{"", "default:glass", "techage:ta4_wlanchip"},
|
||||
{"", "techage:ta4_leds", "techage:ta4_leds"},
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,195 @@
|
||||
--[[
|
||||
|
||||
TechAge
|
||||
=======
|
||||
|
||||
Copyright (C) 2017-2022 Joachim Stolberg
|
||||
|
||||
AGPL v3
|
||||
See LICENSE.txt for more information
|
||||
|
||||
TA4 Logic fourfold signal lamp
|
||||
|
||||
]]--
|
||||
|
||||
-- for lazy programmers
|
||||
local M = minetest.get_meta
|
||||
local S = techage.S
|
||||
|
||||
local OFF = 0
|
||||
local GREEN = 1
|
||||
local AMBER = 2
|
||||
local RED = 3
|
||||
|
||||
local WRENCH_MENU = {
|
||||
{
|
||||
type = "ascii",
|
||||
name = "label1",
|
||||
label = S("Label") .. " 1",
|
||||
tooltip = S("Label for the lamp"),
|
||||
default = "1",
|
||||
},
|
||||
{
|
||||
type = "ascii",
|
||||
name = "label2",
|
||||
label = S("Label") .. " 2",
|
||||
tooltip = S("Label for the lamp"),
|
||||
default = "2",
|
||||
},
|
||||
{
|
||||
type = "ascii",
|
||||
name = "label3",
|
||||
label = S("Label") .. " 3",
|
||||
tooltip = S("Label for the lamp"),
|
||||
default = "3",
|
||||
},
|
||||
{
|
||||
type = "ascii",
|
||||
name = "label4",
|
||||
label = S("Label") .. " 4",
|
||||
tooltip = S("Label for the lamp"),
|
||||
default = "4",
|
||||
},
|
||||
}
|
||||
|
||||
local function lamp_update(pos, objref)
|
||||
local meta = M(pos)
|
||||
pos = vector.round(pos)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
nvm.lamp = nvm.lamp or {}
|
||||
local tbl = {meta:get_string("label1"), " ", meta:get_string("label2"), " ", meta:get_string("label3"), " ", meta:get_string("label4")}
|
||||
local text = "< " .. table.concat(tbl, "\n< ")
|
||||
local texture = lcdlib.make_multiline_texture("default", text, 96, 96, 7, "top", "#000", 6)
|
||||
|
||||
if nvm.lamp[1] == RED then
|
||||
texture = texture .. "^techage_smartline_signal_red1.png"
|
||||
elseif nvm.lamp[1] == GREEN then
|
||||
texture = texture .. "^techage_smartline_signal_green1.png"
|
||||
elseif nvm.lamp[1] == AMBER then
|
||||
texture = texture .. "^techage_smartline_signal_amber1.png"
|
||||
end
|
||||
|
||||
if nvm.lamp[2] == RED then
|
||||
texture = texture .. "^techage_smartline_signal_red2.png"
|
||||
elseif nvm.lamp[2] == GREEN then
|
||||
texture = texture .. "^techage_smartline_signal_green2.png"
|
||||
elseif nvm.lamp[2] == AMBER then
|
||||
texture = texture .. "^techage_smartline_signal_amber2.png"
|
||||
end
|
||||
|
||||
if nvm.lamp[3] == RED then
|
||||
texture = texture .. "^techage_smartline_signal_red3.png"
|
||||
elseif nvm.lamp[3] == GREEN then
|
||||
texture = texture .. "^techage_smartline_signal_green3.png"
|
||||
elseif nvm.lamp[3] == AMBER then
|
||||
texture = texture .. "^techage_smartline_signal_amber3.png"
|
||||
end
|
||||
|
||||
if nvm.lamp[4] == RED then
|
||||
texture = texture .. "^techage_smartline_signal_red4.png"
|
||||
elseif nvm.lamp[4] == GREEN then
|
||||
texture = texture .. "^techage_smartline_signal_green4.png"
|
||||
elseif nvm.lamp[4] == AMBER then
|
||||
texture = texture .. "^techage_smartline_signal_amber4.png"
|
||||
end
|
||||
|
||||
objref:set_properties({ textures = {texture}, visual_size = {x=1, y=1} })
|
||||
end
|
||||
|
||||
local lcd_box = {-8/16, -8/16, 7.75/16, 8/16, 8/16, 8/16}
|
||||
|
||||
minetest.register_node("techage:ta4_signallamp_4x", {
|
||||
description = S("TA4 4x Signal Lamp"),
|
||||
inventory_image = 'techage_smartline_signal_4x.png^techage_smartline_signal_off1.png^techage_smartline_signal_green2.png^techage_smartline_signal_amber3.png^techage_smartline_signal_red4.png',
|
||||
tiles = {'techage_smartline_signal_4x.png'},
|
||||
drawtype = "nodebox",
|
||||
paramtype = "light",
|
||||
use_texture_alpha = "clip",
|
||||
sunlight_propagates = true,
|
||||
paramtype2 = "facedir",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = lcd_box,
|
||||
},
|
||||
light_source = 6,
|
||||
|
||||
display_entities = {
|
||||
["techage:display_entity"] = { depth = 0.48,
|
||||
on_display_update = lamp_update},
|
||||
},
|
||||
|
||||
after_place_node = function(pos, placer)
|
||||
local number = techage.add_node(pos, "techage:ta4_signallamp_4x")
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("node_number", number)
|
||||
meta:set_string("owner", placer:get_player_name())
|
||||
meta:set_string("infotext", S("TA4 4x Signal Lamp") .. " " .. number)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
nvm.text = {"1", "", "2", "", "3", "", "4"}
|
||||
nvm.lamp = {}
|
||||
lcdlib.update_entities(pos)
|
||||
end,
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
end,
|
||||
|
||||
ta_after_formspec = function(pos, fields, playername)
|
||||
lcdlib.update_entities(pos)
|
||||
end,
|
||||
|
||||
ta3_formspec = WRENCH_MENU,
|
||||
on_place = lcdlib.on_place,
|
||||
on_construct = lcdlib.on_construct,
|
||||
on_destruct = lcdlib.on_destruct,
|
||||
on_rotate = lcdlib.on_rotate,
|
||||
groups = {cracky=2, crumbly=2},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
})
|
||||
|
||||
techage.register_node({"techage:ta4_signallamp_4x"}, {
|
||||
on_recv_message = function(pos, src, topic, payload)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
nvm.lamp = nvm.lamp or {}
|
||||
if topic == "green" then
|
||||
local num = math.min(tonumber(payload) or 0, 4)
|
||||
nvm.lamp[num] = GREEN
|
||||
lcdlib.update_entities(pos)
|
||||
elseif topic == "amber" then
|
||||
local num = math.min(tonumber(payload) or 0, 4)
|
||||
nvm.lamp[num] = AMBER
|
||||
lcdlib.update_entities(pos)
|
||||
elseif topic == "red" then
|
||||
local num = math.min(tonumber(payload) or 0, 4)
|
||||
nvm.lamp[num] = RED
|
||||
lcdlib.update_entities(pos)
|
||||
elseif topic == "off" then
|
||||
local num = math.min(tonumber(payload) or 0, 4)
|
||||
nvm.lamp[num] = OFF
|
||||
lcdlib.update_entities(pos)
|
||||
end
|
||||
end,
|
||||
on_beduino_receive_cmnd = function(pos, src, topic, payload)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
nvm.lamp = nvm.lamp or {}
|
||||
if topic == 3 then -- Signal Lamp
|
||||
local num = math.min(payload[1] or 1, 4)
|
||||
local color = math.min(payload[2] or 0, 3)
|
||||
nvm.lamp[num] = color
|
||||
lcdlib.update_entities(pos)
|
||||
return 0
|
||||
else
|
||||
return 2
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:ta4_signallamp_4x",
|
||||
recipe = {
|
||||
{"", "techage:ta4_signallamp_2x", ""},
|
||||
{"", "techage:ta4_signallamp_2x", ""},
|
||||
{"", "", ""},
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,493 @@
|
||||
--[[
|
||||
|
||||
Terminal
|
||||
========
|
||||
|
||||
Copyright (C) 2018-2024 Joachim Stolberg
|
||||
|
||||
AGPL v3
|
||||
See LICENSE.txt for more information
|
||||
|
||||
terminal.lua:
|
||||
|
||||
]]--
|
||||
|
||||
local M = minetest.get_meta
|
||||
local S = techage.S
|
||||
|
||||
local HELP_TA3 = [[ #### TA3 Terminal ####
|
||||
Send commands to machines and output the results.
|
||||
Local commands:
|
||||
- Clear screen with 'clear'
|
||||
- Output this message with 'help'
|
||||
- Switch to public use of buttons with 'pub'
|
||||
- Switch to private use of buttons with 'priv'
|
||||
- Output techage version with 'vers'
|
||||
- Program a user button with
|
||||
'set <button-num> <button-text> <command>'
|
||||
Example: 'set 1 ON cmd 1234 on'
|
||||
- send a command with 'cmd <num> <cmnd>'
|
||||
Example: 'cmd 1234 on']]
|
||||
|
||||
local HELP_TA4 = [[ #### TA4 Terminal ####
|
||||
Send commands to machines and output the results.
|
||||
Local commands:
|
||||
- Clear screen with 'clear'
|
||||
- Output this message with 'help'
|
||||
- Switch to public use of buttons with 'pub'
|
||||
- Switch to private use of buttons with 'priv'
|
||||
- Output techage version with 'vers'
|
||||
- Program a user button with
|
||||
'set <button-num> <button-text> <command>'
|
||||
Example: 'set 1 ON cmd 1234 on'
|
||||
- send a command with 'cmd <num> <cmnd>'
|
||||
Example: 'cmd 1234 on'
|
||||
- Connect to a machine with 'connect <num>'
|
||||
If connected, compact commands like 'status'
|
||||
are possible.]]
|
||||
|
||||
local SYNTAX_ERR = S("Syntax error, try help")
|
||||
|
||||
local WRENCH_MENU = {
|
||||
[0] = {"techage:terminal2"}, --valid_nodes
|
||||
{
|
||||
type = "dropdown",
|
||||
choices = "all players,me",
|
||||
name = "public",
|
||||
label = S("Access allowed for"),
|
||||
tooltip = S("Friends are players for whom this area is not protected"),
|
||||
default = "1",
|
||||
values = {1,0}
|
||||
},
|
||||
{
|
||||
type = "dropdown",
|
||||
choices = "terminal,basic",
|
||||
name = "opmode",
|
||||
label = S("Operational mode"),
|
||||
tooltip = S("Switch between TA3 terminal and BASIC computer"),
|
||||
default = "terminal",
|
||||
},
|
||||
}
|
||||
|
||||
local function get_string(meta, num, default)
|
||||
local s = meta:get_string("bttn_text"..num)
|
||||
if not s or s == "" then
|
||||
return default
|
||||
end
|
||||
return s
|
||||
end
|
||||
|
||||
local function formspec2(pos, meta)
|
||||
local output = meta:get_string("output")
|
||||
local command = meta:get_string("command")
|
||||
output = minetest.formspec_escape(output)
|
||||
output = output:gsub("\n", ",")
|
||||
local bttn_text1 = get_string(meta, 1, "User1")
|
||||
local bttn_text2 = get_string(meta, 2, "User2")
|
||||
local bttn_text3 = get_string(meta, 3, "User3")
|
||||
local bttn_text4 = get_string(meta, 4, "User4")
|
||||
local bttn_text5 = get_string(meta, 5, "User5")
|
||||
local bttn_text6 = get_string(meta, 6, "User6")
|
||||
local bttn_text7 = get_string(meta, 7, "User7")
|
||||
local bttn_text8 = get_string(meta, 8, "User8")
|
||||
local bttn_text9 = get_string(meta, 9, "User9")
|
||||
local wrench_image = ""
|
||||
if minetest.get_node(pos).name == "techage:terminal2" then
|
||||
wrench_image = techage.wrench_image(9.6, -0.2)
|
||||
end
|
||||
return "size[10,8.5]"..
|
||||
--"style_type[table,field;font=mono]"..
|
||||
wrench_image ..
|
||||
"button[0,-0.2;3.3,1;bttn1;"..bttn_text1.."]button[3.3,-0.2;3.3,1;bttn2;"..bttn_text2.."]button[6.6,-0.2;3.2,1;bttn3;"..bttn_text3.."]"..
|
||||
"button[0,0.6;3.3,1;bttn4;"..bttn_text4.."]button[3.3,0.6;3.3,1;bttn5;"..bttn_text5.."]button[6.6,0.6;3.4,1;bttn6;"..bttn_text6.."]"..
|
||||
"button[0,1.4;3.3,1;bttn7;"..bttn_text7.."]button[3.3,1.4;3.3,1;bttn8;"..bttn_text8.."]button[6.6,1.4;3.4,1;bttn9;"..bttn_text9.."]"..
|
||||
"table[0,2.3;9.8,5.6;output;"..output..";200]"..
|
||||
"field[0.4,8.2;7.6,1;cmnd;;"..command.."]" ..
|
||||
"field_close_on_enter[cmnd;false]"..
|
||||
"button[7.9,7.9;2,1;ok;"..S("Enter").."]"
|
||||
end
|
||||
|
||||
local function output(pos, text)
|
||||
local meta = minetest.get_meta(pos)
|
||||
text = meta:get_string("output") .. "\n" .. (text or "")
|
||||
text = text:sub(-1000,-1)
|
||||
meta:set_string("output", text)
|
||||
meta:set_string("formspec", formspec2(pos, meta))
|
||||
end
|
||||
|
||||
local function append(pos, text)
|
||||
local meta = minetest.get_meta(pos)
|
||||
text = meta:get_string("output") .. (text or "")
|
||||
meta:set_string("output", text)
|
||||
meta:set_string("formspec", formspec2(pos, meta))
|
||||
end
|
||||
|
||||
local function get_line_text(pos, num)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local text = meta:get_string("output") or ""
|
||||
local lines = string.split(text, "\n", true)
|
||||
local line = lines[num] or ""
|
||||
return line:gsub("^[%s$]*(.-)%s*$", "%1")
|
||||
end
|
||||
|
||||
local function server_debug(pos, command, player)
|
||||
local cmnd, payload = command:match('^pipe%s+([%w_]+)%s*(.*)$')
|
||||
if cmnd then
|
||||
if not minetest.check_player_privs(player, "server") then
|
||||
output(pos, "server privs missing")
|
||||
return
|
||||
end
|
||||
local resp = techage.transfer(
|
||||
pos,
|
||||
"B", -- outdir
|
||||
cmnd, -- topic
|
||||
payload, -- payload
|
||||
techage.LiquidPipe, -- network
|
||||
nil) -- valid nodes
|
||||
output(pos, dump(resp))
|
||||
return true
|
||||
end
|
||||
|
||||
cmnd, payload = command:match('^axle%s+([%w_]+)%s*(.*)$')
|
||||
if cmnd then
|
||||
if not minetest.check_player_privs(player, "server") then
|
||||
output(pos, "server privs missing")
|
||||
return
|
||||
end
|
||||
local resp = techage.transfer(
|
||||
pos,
|
||||
"B", -- outdir
|
||||
cmnd, -- topic
|
||||
payload, -- payload
|
||||
techage.TA1Axle, -- network
|
||||
nil) -- valid nodes
|
||||
output(pos, dump(resp))
|
||||
return true
|
||||
end
|
||||
|
||||
cmnd, payload = command:match('^vtube%s+([%w_]+)%s*(.*)$')
|
||||
if cmnd then
|
||||
if not minetest.check_player_privs(player, "server") then
|
||||
output(pos, "server privs missing")
|
||||
return
|
||||
end
|
||||
local resp = techage.transfer(
|
||||
pos,
|
||||
"B", -- outdir
|
||||
cmnd, -- topic
|
||||
payload, -- payload
|
||||
techage.VTube, -- network
|
||||
nil) -- valid nodes
|
||||
output(pos, dump(resp))
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
local function command(pos, command, player, is_ta4)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local owner = meta:get_string("owner") or ""
|
||||
|
||||
command = command:sub(1,80)
|
||||
command = string.trim(command)
|
||||
local cmnd, data = command:match('^(%w+)%s*(.*)$')
|
||||
|
||||
if cmnd == "clear" then
|
||||
meta:set_string("output", "")
|
||||
meta:set_string("formspec", formspec2(pos, meta))
|
||||
elseif cmnd == "" then
|
||||
output(pos, "$")
|
||||
elseif cmnd == "help" then
|
||||
if is_ta4 then
|
||||
output(pos, HELP_TA4)
|
||||
else
|
||||
output(pos, HELP_TA3)
|
||||
end
|
||||
elseif cmnd == "pub" then
|
||||
meta:set_int("public", 1)
|
||||
output(pos, "$ "..command)
|
||||
output(pos, "Switched to public buttons!")
|
||||
elseif cmnd == "priv" then
|
||||
meta:set_int("public", 0)
|
||||
output(pos, "$ "..command)
|
||||
output(pos, "Switched to private buttons!")
|
||||
elseif cmnd == "vers" then
|
||||
output(pos, "$ "..command)
|
||||
output(pos, "Techage version = " .. techage.version)
|
||||
elseif cmnd == "connect" and data then
|
||||
output(pos, "$ "..command)
|
||||
if techage.not_protected(data, owner) then
|
||||
local own_num = meta:get_string("node_number")
|
||||
local resp = techage.send_single(own_num, data, cmnd)
|
||||
if resp then
|
||||
meta:set_string("connected_to", data)
|
||||
output(pos, "Connected.")
|
||||
else
|
||||
meta:set_string("connected_to", "")
|
||||
output(pos, "Not connected!")
|
||||
end
|
||||
else
|
||||
output(pos, "Protection error!")
|
||||
end
|
||||
else
|
||||
output(pos, "$ "..command)
|
||||
local own_num = meta:get_string("node_number")
|
||||
local connected_to = meta:contains("connected_to") and meta:get_string("connected_to")
|
||||
local bttn_num, label, num, cmnd, payload
|
||||
|
||||
num, cmnd, payload = command:match('^cmd%s+([0-9]+)%s+(%w+)%s*(.*)$')
|
||||
if num and cmnd then
|
||||
if techage.not_protected(num, owner) then
|
||||
local resp = techage.send_single(own_num, num, cmnd, payload)
|
||||
if type(resp) == "string" then
|
||||
output(pos, resp)
|
||||
else
|
||||
output(pos, dump(resp))
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
num, cmnd = command:match('^turn%s+([0-9]+)%s+([onf]+)$')
|
||||
if num and (cmnd == "on" or cmnd == "off") then
|
||||
if techage.not_protected(num, owner) then
|
||||
local resp = techage.send_single(own_num, num, cmnd)
|
||||
output(pos, dump(resp))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
bttn_num, label, cmnd = command:match('^set%s+([1-9])%s+([%w_]+)%s+(.+)$')
|
||||
if bttn_num and label and cmnd then
|
||||
meta:set_string("bttn_text"..bttn_num, label)
|
||||
meta:set_string("bttn_cmnd"..bttn_num, cmnd)
|
||||
meta:set_string("formspec", formspec2(pos, meta))
|
||||
return
|
||||
end
|
||||
|
||||
if server_debug(pos, command, player) then
|
||||
return
|
||||
end
|
||||
|
||||
if connected_to then
|
||||
local cmnd, payload = command:match('^(%w+)%s*(.*)$')
|
||||
if cmnd then
|
||||
local resp = techage.send_single(own_num, connected_to, cmnd, payload)
|
||||
if resp ~= true then
|
||||
if type(resp) == "string" then
|
||||
output(pos, resp)
|
||||
else
|
||||
output(pos, dump(resp))
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if command ~= "" then
|
||||
output(pos, SYNTAX_ERR)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function send_cmnd(pos, meta, num)
|
||||
local cmnd = meta:get_string("bttn_cmnd"..num)
|
||||
local owner = meta:get_string("owner") or ""
|
||||
command(pos, cmnd, owner)
|
||||
end
|
||||
|
||||
local function register_terminal(name, description, tiles, node_box, selection_box)
|
||||
minetest.register_node("techage:"..name, {
|
||||
description = description,
|
||||
tiles = tiles,
|
||||
drawtype = "nodebox",
|
||||
node_box = node_box,
|
||||
selection_box = selection_box,
|
||||
|
||||
after_place_node = function(pos, placer)
|
||||
local number = techage.add_node(pos, minetest.get_node(pos).name)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("node_number", number)
|
||||
meta:set_string("command", S("commands like: help"))
|
||||
meta:set_string("formspec", formspec2(pos, meta))
|
||||
if placer then
|
||||
meta:set_string("owner", placer:get_player_name())
|
||||
end
|
||||
meta:set_string("infotext", description .. " " .. number)
|
||||
end,
|
||||
|
||||
on_receive_fields = function(pos, formname, fields, player)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local public = meta:get_int("public") ~= 0
|
||||
local protected = minetest.is_protected(pos, player:get_player_name())
|
||||
|
||||
if not protected then
|
||||
local evt = minetest.explode_table_event(fields.output)
|
||||
if evt.type == "DCL" then
|
||||
local s = get_line_text(pos, evt.row)
|
||||
meta:set_string("command", s)
|
||||
meta:set_string("formspec", formspec2(pos, meta))
|
||||
return
|
||||
elseif (fields.ok or fields.key_enter_field) and fields.cmnd then
|
||||
local is_ta4 = string.find(description, "TA4")
|
||||
command(pos, fields.cmnd, player:get_player_name(), is_ta4)
|
||||
techage.historybuffer_add(pos, fields.cmnd)
|
||||
meta:set_string("command", "")
|
||||
meta:set_string("formspec", formspec2(pos, meta))
|
||||
return
|
||||
elseif fields.key_up then
|
||||
meta:set_string("command", techage.historybuffer_priv(pos))
|
||||
meta:set_string("formspec", formspec2(pos, meta))
|
||||
return
|
||||
elseif fields.key_down then
|
||||
meta:set_string("command", techage.historybuffer_next(pos))
|
||||
meta:set_string("formspec", formspec2(pos, meta))
|
||||
return
|
||||
end
|
||||
end
|
||||
if public or not protected then
|
||||
if fields.bttn1 then send_cmnd(pos, meta, 1)
|
||||
elseif fields.bttn2 then send_cmnd(pos, meta, 2)
|
||||
elseif fields.bttn3 then send_cmnd(pos, meta, 3)
|
||||
elseif fields.bttn4 then send_cmnd(pos, meta, 4)
|
||||
elseif fields.bttn5 then send_cmnd(pos, meta, 5)
|
||||
elseif fields.bttn6 then send_cmnd(pos, meta, 6)
|
||||
elseif fields.bttn7 then send_cmnd(pos, meta, 7)
|
||||
elseif fields.bttn8 then send_cmnd(pos, meta, 8)
|
||||
elseif fields.bttn9 then send_cmnd(pos, meta, 9)
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
ta_after_formspec = function(pos, fields, playername)
|
||||
if fields.save and minetest.get_node(pos).name == "techage:terminal2" then
|
||||
if M(pos):get_string("opmode") == "basic" then
|
||||
if minetest.global_exists("nanobasic") then
|
||||
local node = techage.get_node_lvm(pos)
|
||||
node.name = "techage:basic_terminal"
|
||||
minetest.swap_node(pos, node)
|
||||
local ndef = minetest.registered_nodes["techage:basic_terminal"]
|
||||
ndef.after_place_node(pos)
|
||||
else
|
||||
output(pos, "\nBASIC is not supported. Talk to your server staff!")
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
end,
|
||||
|
||||
ta_preserve_nodedata = techage.preserve_nodedata,
|
||||
ta_restore_nodedata = techage.restore_nodedata,
|
||||
|
||||
ta3_formspec = WRENCH_MENU,
|
||||
paramtype = "light",
|
||||
use_texture_alpha = techage.CLIP,
|
||||
sunlight_propagates = true,
|
||||
paramtype2 = "facedir",
|
||||
groups = {choppy=2, cracky=2, crumbly=2},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
})
|
||||
end
|
||||
|
||||
register_terminal("terminal2", S("TA3 Terminal"), {
|
||||
-- up, down, right, left, back, front
|
||||
'techage_terminal2_top.png',
|
||||
'techage_terminal2_side.png',
|
||||
'techage_terminal2_side.png^[transformFX',
|
||||
'techage_terminal2_side.png',
|
||||
'techage_terminal2_back.png',
|
||||
"techage_terminal2_front.png",
|
||||
},
|
||||
{
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{-12/32, -16/32, -16/32, 12/32, -14/32, 16/32},
|
||||
{-12/32, -14/32, -3/32, 12/32, 6/32, 16/32},
|
||||
{-10/32, -12/32, 14/32, 10/32, 4/32, 18/32},
|
||||
{-12/32, 4/32, -4/32, 12/32, 6/32, 16/32},
|
||||
{-12/32, -16/32, -4/32, -10/32, 6/32, 16/32},
|
||||
{ 10/32, -16/32, -4/32, 12/32, 6/32, 16/32},
|
||||
{-12/32, -14/32, -4/32, 12/32, -12/32, 16/32},
|
||||
},
|
||||
},
|
||||
{
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{-12/32, -16/32, -4/32, 12/32, 6/32, 16/32},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
register_terminal("terminal3", S("TA4 Terminal"), {
|
||||
-- up, down, right, left, back, front
|
||||
'techage_terminal1_top.png',
|
||||
'techage_terminal1_bottom.png',
|
||||
'techage_terminal1_side.png',
|
||||
'techage_terminal1_side.png',
|
||||
'techage_terminal1_bottom.png',
|
||||
"techage_terminal1_front.png",
|
||||
},
|
||||
{
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{-12/32, -16/32, -8/32, 12/32, -14/32, 12/32},
|
||||
{-12/32, -14/32, 12/32, 12/32, 6/32, 14/32},
|
||||
},
|
||||
},
|
||||
{
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{-12/32, -16/32, -8/32, 12/32, -14/32, 12/32},
|
||||
{-12/32, -14/32, 12/32, 12/32, 6/32, 14/32},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:terminal2",
|
||||
recipe = {
|
||||
{"", "", ""},
|
||||
{"techage:basalt_glass_thin", "techage:vacuum_tube", "default:copper_ingot"},
|
||||
{"dye:grey", "default:steel_ingot", "techage:usmium_nuggets"},
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:terminal3",
|
||||
recipe = {
|
||||
{"techage:basalt_glass_thin", "", ""},
|
||||
{"techage:ta4_leds", "", ""},
|
||||
{"techage:aluminum", "techage:ta4_wlanchip", "techage:ta4_ramchip"},
|
||||
},
|
||||
})
|
||||
|
||||
techage.register_node({"techage:terminal2"}, {
|
||||
on_recv_message = function(pos, src, topic, payload)
|
||||
output(pos, "src="..src..", cmd="..dump(topic)..", data="..dump(payload))
|
||||
return true
|
||||
end,
|
||||
on_node_load = function(pos)
|
||||
local meta = M(pos)
|
||||
local number = meta:get_string("number") or ""
|
||||
if number ~= "" then
|
||||
meta:set_string("node_number", number)
|
||||
meta:set_string("number", "")
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
techage.register_node({"techage:terminal3"}, {
|
||||
on_recv_message = function(pos, src, topic, payload)
|
||||
if topic == "text" then
|
||||
output(pos, payload)
|
||||
elseif topic == "append" then
|
||||
append(pos, payload)
|
||||
else
|
||||
output(pos, "src="..src..", cmd="..dump(topic)..", data="..dump(payload))
|
||||
end
|
||||
return true
|
||||
end,
|
||||
})
|
||||
@@ -0,0 +1,209 @@
|
||||
--[[
|
||||
|
||||
TechAge
|
||||
=======
|
||||
|
||||
Copyright (C) 2017-2019 Joachim Stolberg
|
||||
|
||||
AGPL v3
|
||||
See LICENSE.txt for more information
|
||||
|
||||
TA3 Sequencer
|
||||
|
||||
]]--
|
||||
|
||||
-- for lazy programmers
|
||||
local M = minetest.get_meta
|
||||
local S = techage.S
|
||||
|
||||
local logic = techage.logic
|
||||
local CYCLE_TIME = 8
|
||||
|
||||
local tTime = {
|
||||
["00:00"] = 1, ["02:00"] = 2, ["04:00"] = 3,
|
||||
["06:00"] = 4, ["08:00"] = 5, ["10:00"] = 6,
|
||||
["12:00"] = 7, ["14:00"] = 8, ["16:00"] = 9,
|
||||
["18:00"] =10, ["20:00"] =11, ["22:00"] =12,
|
||||
}
|
||||
|
||||
local sTime = "00:00,02:00,04:00,06:00,08:00,10:00,12:00,14:00,16:00,18:00,20:00,22:00"
|
||||
|
||||
local tAction = {
|
||||
[""] = 1,
|
||||
["on"] = 2,
|
||||
["off"] = 3,
|
||||
}
|
||||
|
||||
local sAction = ",on,off"
|
||||
|
||||
local function deserialize(meta, name)
|
||||
local s = meta:get_string(name) or ""
|
||||
if s ~= "" then
|
||||
return minetest.deserialize(s)
|
||||
end
|
||||
end
|
||||
|
||||
local function formspec(events, numbers, actions)
|
||||
return "size[8,8]"..
|
||||
default.gui_bg..
|
||||
default.gui_bg_img..
|
||||
default.gui_slots..
|
||||
|
||||
"label[0,0;Time]label[2.3,0;Number(s)]label[4.5,0;Command]"..
|
||||
"dropdown[0,1;2,1;e1;"..sTime..";"..events[1].."]"..
|
||||
"field[2.3,1.2;2,1;n1;;"..numbers[1].."]" ..
|
||||
"dropdown[4.5,1;3,1;a1;"..sAction..";"..tAction[actions[1]].."]"..
|
||||
|
||||
"dropdown[0,2;2,1;e2;"..sTime..";"..events[2].."]"..
|
||||
"field[2.3,2.2;2,1;n2;;"..numbers[2].."]" ..
|
||||
"dropdown[4.5,2;3,1;a2;"..sAction..";"..tAction[actions[2]].."]"..
|
||||
|
||||
"dropdown[0,3;2,1;e3;"..sTime..";"..events[3].."]"..
|
||||
"field[2.3,3.2;2,1;n3;;"..numbers[3].."]" ..
|
||||
"dropdown[4.5,3;3,1;a3;"..sAction..";"..tAction[actions[3]].."]"..
|
||||
|
||||
"dropdown[0,4;2,1;e4;"..sTime..";"..events[4].."]"..
|
||||
"field[2.3,4.2;2,1;n4;;"..numbers[4].."]" ..
|
||||
"dropdown[4.5,4;3,1;a4;"..sAction..";"..tAction[actions[4]].."]"..
|
||||
|
||||
"dropdown[0,5;2,1;e5;"..sTime..";"..events[5].."]"..
|
||||
"field[2.3,5.2;2,1;n5;;"..numbers[5].."]" ..
|
||||
"dropdown[4.5,5;3,1;a5;"..sAction..";"..tAction[actions[5]].."]"..
|
||||
|
||||
"dropdown[0,6;2,1;e6;"..sTime..";"..events[6].."]"..
|
||||
"field[2.3,6.2;2,1;n6;;"..numbers[6].."]" ..
|
||||
"dropdown[4.5,6;3,1;a6;"..sAction..";"..tAction[actions[6]].."]"..
|
||||
|
||||
"button_exit[3,7;2,1;exit;close]"
|
||||
end
|
||||
|
||||
|
||||
local function check_rules(pos,elapsed)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
nvm.done = nvm.done or {false,false,false,false,false,false}
|
||||
local hour = math.floor(minetest.get_timeofday() * 24)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local events = deserialize(meta, "events")
|
||||
local numbers = deserialize(meta, "numbers")
|
||||
local actions = deserialize(meta, "actions")
|
||||
local number = meta:get_string("node_number")
|
||||
|
||||
if events and numbers and actions then
|
||||
-- check all rules
|
||||
for idx,act in ipairs(actions) do
|
||||
if act ~= "" and numbers[idx] ~= "" then
|
||||
local hr = (events[idx] - 1) * 2
|
||||
if ((hour - hr) % 24) <= 4 then -- last 4 hours?
|
||||
if nvm.done[idx] == false then -- not already executed?
|
||||
techage.send_multi(number, numbers[idx], act)
|
||||
nvm.done[idx] = true
|
||||
end
|
||||
else
|
||||
nvm.done[idx] = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- prepare for the next day
|
||||
if hour == 23 then
|
||||
nvm.done = {false,false,false,false,false,false}
|
||||
end
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
minetest.register_node("techage:ta3_timer", {
|
||||
description = S("TA3 Timer"),
|
||||
tiles = {
|
||||
-- up, down, right, left, back, front
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3_top.png",
|
||||
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_timer.png",
|
||||
},
|
||||
|
||||
after_place_node = function(pos, placer)
|
||||
local meta = M(pos)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
logic.after_place_node(pos, placer, "techage:ta3_timer", S("TA3 Timer"))
|
||||
logic.infotext(meta, S("TA3 Timer"))
|
||||
local events = {1,1,1,1,1,1}
|
||||
local numbers = {"0000","","","","",""}
|
||||
local actions = {"","","","","",""}
|
||||
nvm.done = {false,false,false,false,false,false}
|
||||
meta:set_string("events", minetest.serialize(events))
|
||||
meta:set_string("numbers", minetest.serialize(numbers))
|
||||
meta:set_string("actions", minetest.serialize(actions))
|
||||
meta:set_string("formspec", formspec(events, numbers, actions))
|
||||
minetest.get_node_timer(pos):start(CYCLE_TIME)
|
||||
end,
|
||||
|
||||
on_receive_fields = function(pos, formname, fields, player)
|
||||
local meta = minetest.get_meta(pos)
|
||||
if minetest.is_protected(pos, player:get_player_name()) then
|
||||
return
|
||||
end
|
||||
|
||||
local events = minetest.deserialize(meta:get_string("events"))
|
||||
for idx, evt in ipairs({fields.e1, fields.e2, fields.e3, fields.e4, fields.e5, fields.e6}) do
|
||||
if evt ~= nil then
|
||||
events[idx] = tTime[evt]
|
||||
end
|
||||
end
|
||||
meta:set_string("events", minetest.serialize(events))
|
||||
|
||||
local numbers = minetest.deserialize(meta:get_string("numbers"))
|
||||
for idx, num in ipairs({fields.n1, fields.n2, fields.n3, fields.n4, fields.n5, fields.n6}) do
|
||||
if num ~= nil and techage.check_numbers(num, player:get_player_name()) then
|
||||
numbers[idx] = num
|
||||
end
|
||||
end
|
||||
meta:set_string("numbers", minetest.serialize(numbers))
|
||||
|
||||
local actions = minetest.deserialize(meta:get_string("actions"))
|
||||
for idx, act in ipairs({fields.a1, fields.a2, fields.a3, fields.a4, fields.a5, fields.a6}) do
|
||||
if act ~= nil then
|
||||
actions[idx] = act
|
||||
end
|
||||
end
|
||||
meta:set_string("actions", minetest.serialize(actions))
|
||||
meta:set_string("formspec", formspec(events, numbers, actions))
|
||||
local nvm = techage.get_nvm(pos)
|
||||
nvm.done = {false,false,false,false,false,false}
|
||||
end,
|
||||
|
||||
on_timer = check_rules,
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
techage.del_mem(pos)
|
||||
end,
|
||||
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
sunlight_propagates = true,
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
groups = {choppy=2, cracky=2, crumbly=2},
|
||||
is_ground_content = false,
|
||||
})
|
||||
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:ta3_timer",
|
||||
recipe = {
|
||||
{"group:wood", "group:wood", ""},
|
||||
{"default:gold_ingot", "techage:vacuum_tube", ""},
|
||||
{"group:wood", "group:wood", ""},
|
||||
},
|
||||
})
|
||||
|
||||
techage.register_node({"techage:ta3_timer"}, {
|
||||
on_node_load = function(pos)
|
||||
minetest.get_node_timer(pos):start(CYCLE_TIME)
|
||||
-- check rules for just loaded areas
|
||||
local nvm = techage.get_nvm(pos)
|
||||
nvm.done = {false,false,false,false,false,false}
|
||||
check_rules(pos,0)
|
||||
end,
|
||||
})
|
||||
@@ -0,0 +1,540 @@
|
||||
--[[
|
||||
|
||||
TechAge
|
||||
=======
|
||||
|
||||
Copyright (C) 2019-2025 Joachim Stolberg
|
||||
|
||||
AGPL v3
|
||||
See LICENSE.txt for more information
|
||||
|
||||
Traffic Lights
|
||||
|
||||
]]--
|
||||
|
||||
local S = techage.S
|
||||
local M = minetest.get_meta
|
||||
local P2S = minetest.pos_to_string
|
||||
|
||||
local TITLE = S("TA4 Traffic Light")
|
||||
|
||||
local
|
||||
ConvertTo = {
|
||||
off = {
|
||||
["techage:ta4_trafficlight1_red"] = "techage:ta4_trafficlight1",
|
||||
["techage:ta4_trafficlight1_amber"] = "techage:ta4_trafficlight1",
|
||||
["techage:ta4_trafficlight1_green"] = "techage:ta4_trafficlight1",
|
||||
["techage:ta4_trafficlight1B_red"] = "techage:ta4_trafficlight1B",
|
||||
["techage:ta4_trafficlight1B_amber"] = "techage:ta4_trafficlight1B",
|
||||
["techage:ta4_trafficlight1B_green"] = "techage:ta4_trafficlight1B",
|
||||
["techage:ta4_trafficlight2_red"] = "techage:ta4_trafficlight2",
|
||||
["techage:ta4_trafficlight2_amber"] = "techage:ta4_trafficlight2",
|
||||
["techage:ta4_trafficlight2_green"] = "techage:ta4_trafficlight2",
|
||||
["techage:ta4_trafficlight2B_red"] = "techage:ta4_trafficlight2B",
|
||||
["techage:ta4_trafficlight2B_amber"] = "techage:ta4_trafficlight2B",
|
||||
["techage:ta4_trafficlight2B_green"] = "techage:ta4_trafficlight2B",
|
||||
},
|
||||
green = {
|
||||
["techage:ta4_trafficlight1_red"] = "techage:ta4_trafficlight1_green",
|
||||
["techage:ta4_trafficlight1_amber"] = "techage:ta4_trafficlight1_green",
|
||||
["techage:ta4_trafficlight1"] = "techage:ta4_trafficlight1_green",
|
||||
["techage:ta4_trafficlight1B_red"] = "techage:ta4_trafficlight1B_green",
|
||||
["techage:ta4_trafficlight1B_amber"] = "techage:ta4_trafficlight1B_green",
|
||||
["techage:ta4_trafficlight1B"] = "techage:ta4_trafficlight1B_green",
|
||||
["techage:ta4_trafficlight2_red"] = "techage:ta4_trafficlight2_green",
|
||||
["techage:ta4_trafficlight2_amber"] = "techage:ta4_trafficlight2_green",
|
||||
["techage:ta4_trafficlight2"] = "techage:ta4_trafficlight2_green",
|
||||
["techage:ta4_trafficlight2B_red"] = "techage:ta4_trafficlight2B_green",
|
||||
["techage:ta4_trafficlight2B_amber"] = "techage:ta4_trafficlight2B_green",
|
||||
["techage:ta4_trafficlight2B"] = "techage:ta4_trafficlight2B_green",
|
||||
},
|
||||
amber = {
|
||||
["techage:ta4_trafficlight1_red"] = "techage:ta4_trafficlight1_amber",
|
||||
["techage:ta4_trafficlight1_green"] = "techage:ta4_trafficlight1_amber",
|
||||
["techage:ta4_trafficlight1"] = "techage:ta4_trafficlight1_amber",
|
||||
["techage:ta4_trafficlight1B_red"] = "techage:ta4_trafficlight1B_amber",
|
||||
["techage:ta4_trafficlight1B_green"] = "techage:ta4_trafficlight1B_amber",
|
||||
["techage:ta4_trafficlight1B"] = "techage:ta4_trafficlight1B_amber",
|
||||
["techage:ta4_trafficlight2_red"] = "techage:ta4_trafficlight2_amber",
|
||||
["techage:ta4_trafficlight2_green"] = "techage:ta4_trafficlight2_amber",
|
||||
["techage:ta4_trafficlight2"] = "techage:ta4_trafficlight2_amber",
|
||||
["techage:ta4_trafficlight2B_red"] = "techage:ta4_trafficlight2B_amber",
|
||||
["techage:ta4_trafficlight2B_green"] = "techage:ta4_trafficlight2B_amber",
|
||||
["techage:ta4_trafficlight2B"] = "techage:ta4_trafficlight2B_amber",
|
||||
},
|
||||
red = {
|
||||
["techage:ta4_trafficlight1_amber"] = "techage:ta4_trafficlight1_red",
|
||||
["techage:ta4_trafficlight1_green"] = "techage:ta4_trafficlight1_red",
|
||||
["techage:ta4_trafficlight1"] = "techage:ta4_trafficlight1_red",
|
||||
["techage:ta4_trafficlight1B_amber"] = "techage:ta4_trafficlight1B_red",
|
||||
["techage:ta4_trafficlight1B_green"] = "techage:ta4_trafficlight1B_red",
|
||||
["techage:ta4_trafficlight1B"] = "techage:ta4_trafficlight1B_red",
|
||||
["techage:ta4_trafficlight2_amber"] = "techage:ta4_trafficlight2_red",
|
||||
["techage:ta4_trafficlight2_green"] = "techage:ta4_trafficlight2_red",
|
||||
["techage:ta4_trafficlight2"] = "techage:ta4_trafficlight2_red",
|
||||
["techage:ta4_trafficlight2B_amber"] = "techage:ta4_trafficlight2B_red",
|
||||
["techage:ta4_trafficlight2B_green"] = "techage:ta4_trafficlight2B_red",
|
||||
["techage:ta4_trafficlight2B"] = "techage:ta4_trafficlight2B_red",
|
||||
},
|
||||
}
|
||||
|
||||
local SelectionBox = {
|
||||
type = "fixed",
|
||||
fixed = {-5/32, -15/32, 6/32, 5/32, 15/32, 24/32},
|
||||
}
|
||||
|
||||
|
||||
local function is_pole(pos)
|
||||
local node = minetest.get_node(pos)
|
||||
local dir = tubelib2.side_to_dir("B", node.param2)
|
||||
local pos2 = tubelib2.get_pos(pos, dir)
|
||||
local name = minetest.get_node(pos2).name
|
||||
return name == "techage:trafficlight_connector" or name == "techage:trafficlight_pole"
|
||||
end
|
||||
|
||||
local function switch_on(pos, color)
|
||||
local node = techage.get_node_lvm(pos)
|
||||
if ConvertTo[color][node.name] then
|
||||
node.name = ConvertTo[color][node.name]
|
||||
M(pos):set_string("state", color)
|
||||
minetest.swap_node(pos, node)
|
||||
end
|
||||
end
|
||||
|
||||
local function switch_off(pos)
|
||||
local node = techage.get_node_lvm(pos)
|
||||
if ConvertTo["off"][node.name] then
|
||||
node.name = ConvertTo["off"][node.name]
|
||||
M(pos):set_string("state", "off")
|
||||
minetest.swap_node(pos, node)
|
||||
end
|
||||
end
|
||||
|
||||
local function on_rightclick(pos, node, clicker)
|
||||
if not minetest.is_protected(pos, clicker:get_player_name()) then
|
||||
local state = M(pos):get_string("state")
|
||||
if state == "off" then
|
||||
switch_on(pos, "green")
|
||||
else
|
||||
switch_off(pos)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function after_dig_node(pos, oldnode, oldmetadata)
|
||||
techage.remove_node(pos, oldnode, oldmetadata)
|
||||
end
|
||||
|
||||
minetest.register_node("techage:ta4_trafficlight1", {
|
||||
description = TITLE,
|
||||
tiles = {"techage_trafficlight1.png"},
|
||||
drawtype = "mesh",
|
||||
mesh = "techage_traffic_light.obj",
|
||||
selection_box = SelectionBox,
|
||||
|
||||
after_place_node = function(pos, placer)
|
||||
local number
|
||||
if is_pole(pos) then
|
||||
local node = minetest.get_node(pos)
|
||||
node.name = "techage:ta4_trafficlight1B"
|
||||
minetest.swap_node(pos, node)
|
||||
number = techage.add_node(pos, "techage:ta4_trafficlight1B")
|
||||
else
|
||||
number = techage.add_node(pos, "techage:ta4_trafficlight1")
|
||||
end
|
||||
local meta = M(pos)
|
||||
meta:set_string("state", "off")
|
||||
meta:set_string("infotext", TITLE .. " " .. number)
|
||||
end,
|
||||
|
||||
on_rightclick = on_rightclick,
|
||||
after_dig_node = after_dig_node,
|
||||
|
||||
paramtype = "light",
|
||||
use_texture_alpha = techage.CLIP,
|
||||
light_source = 0,
|
||||
sunlight_propagates = true,
|
||||
paramtype2 = "facedir",
|
||||
groups = {cracky=2, crumbly=2},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
})
|
||||
|
||||
for _,color in ipairs({"green", "amber", "red"}) do
|
||||
local tiles = {"techage_trafficlight1_" .. color .. '.png'}
|
||||
minetest.register_node("techage:ta4_trafficlight1_" .. color, {
|
||||
description = TITLE,
|
||||
tiles = tiles,
|
||||
drawtype = "mesh",
|
||||
mesh = "techage_traffic_light.obj",
|
||||
selection_box = SelectionBox,
|
||||
|
||||
on_rightclick = on_rightclick,
|
||||
after_dig_node = after_dig_node,
|
||||
|
||||
paramtype = "light",
|
||||
use_texture_alpha = techage.CLIP,
|
||||
light_source = 10,
|
||||
sunlight_propagates = true,
|
||||
paramtype2 = "facedir",
|
||||
groups = {crumbly=0, not_in_creative_inventory=1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
drop = "techage:ta4_trafficlight1",
|
||||
})
|
||||
end
|
||||
|
||||
minetest.register_node("techage:ta4_trafficlight1B", {
|
||||
description = TITLE,
|
||||
tiles = {"techage_trafficlight1.png"},
|
||||
drawtype = "mesh",
|
||||
mesh = "techage_traffic_lightB.obj",
|
||||
selection_box = SelectionBox,
|
||||
|
||||
on_rightclick = on_rightclick,
|
||||
after_dig_node = after_dig_node,
|
||||
|
||||
paramtype = "light",
|
||||
use_texture_alpha = techage.CLIP,
|
||||
light_source = 0,
|
||||
sunlight_propagates = true,
|
||||
paramtype2 = "facedir",
|
||||
groups = {cracky=2, crumbly=2, not_in_creative_inventory=1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
drop = "techage:ta4_trafficlight1",
|
||||
})
|
||||
|
||||
for _,color in ipairs({"green", "amber", "red"}) do
|
||||
local tiles = {"techage_trafficlight1_" .. color .. '.png'}
|
||||
minetest.register_node("techage:ta4_trafficlight1B_" .. color, {
|
||||
description = TITLE,
|
||||
tiles = tiles,
|
||||
drawtype = "mesh",
|
||||
mesh = "techage_traffic_lightB.obj",
|
||||
selection_box = SelectionBox,
|
||||
|
||||
on_rightclick = on_rightclick,
|
||||
after_dig_node = after_dig_node,
|
||||
|
||||
paramtype = "light",
|
||||
use_texture_alpha = techage.CLIP,
|
||||
light_source = 10,
|
||||
sunlight_propagates = true,
|
||||
paramtype2 = "facedir",
|
||||
groups = {crumbly=0, not_in_creative_inventory=1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
drop = "techage:ta4_trafficlight1",
|
||||
})
|
||||
end
|
||||
|
||||
minetest.register_node("techage:ta4_trafficlight2", {
|
||||
description = TITLE,
|
||||
tiles = {"techage_trafficlight2.png"},
|
||||
drawtype = "mesh",
|
||||
mesh = "techage_traffic_light.obj",
|
||||
selection_box = SelectionBox,
|
||||
|
||||
after_place_node = function(pos, placer)
|
||||
local number
|
||||
if is_pole(pos) then
|
||||
local node = minetest.get_node(pos)
|
||||
node.name = "techage:ta4_trafficlight2B"
|
||||
minetest.swap_node(pos, node)
|
||||
number = techage.add_node(pos, "techage:ta4_trafficlight2B")
|
||||
else
|
||||
number = techage.add_node(pos, "techage:ta4_trafficlight2")
|
||||
end
|
||||
local meta = M(pos)
|
||||
meta:set_string("state", "off")
|
||||
meta:set_string("infotext", TITLE .. " " .. number)
|
||||
end,
|
||||
|
||||
on_rightclick = on_rightclick,
|
||||
after_dig_node = after_dig_node,
|
||||
|
||||
paramtype = "light",
|
||||
use_texture_alpha = techage.CLIP,
|
||||
light_source = 0,
|
||||
sunlight_propagates = true,
|
||||
paramtype2 = "facedir",
|
||||
groups = {cracky=2, crumbly=2},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
})
|
||||
|
||||
for _,color in ipairs({"green", "amber", "red"}) do
|
||||
local tiles = {"techage_trafficlight2_" .. color .. '.png'}
|
||||
minetest.register_node("techage:ta4_trafficlight2_" .. color, {
|
||||
description = TITLE,
|
||||
tiles = tiles,
|
||||
drawtype = "mesh",
|
||||
mesh = "techage_traffic_light.obj",
|
||||
selection_box = SelectionBox,
|
||||
|
||||
on_rightclick = on_rightclick,
|
||||
after_dig_node = after_dig_node,
|
||||
|
||||
paramtype = "light",
|
||||
use_texture_alpha = techage.CLIP,
|
||||
light_source = 10,
|
||||
sunlight_propagates = true,
|
||||
paramtype2 = "facedir",
|
||||
groups = {crumbly=0, not_in_creative_inventory=1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
drop = "techage:ta4_trafficlight2",
|
||||
})
|
||||
end
|
||||
|
||||
minetest.register_node("techage:ta4_trafficlight2B", {
|
||||
description = TITLE,
|
||||
tiles = {"techage_trafficlight2.png"},
|
||||
drawtype = "mesh",
|
||||
mesh = "techage_traffic_lightB.obj",
|
||||
selection_box = SelectionBox,
|
||||
|
||||
on_rightclick = on_rightclick,
|
||||
after_dig_node = after_dig_node,
|
||||
|
||||
paramtype = "light",
|
||||
use_texture_alpha = techage.CLIP,
|
||||
light_source = 0,
|
||||
sunlight_propagates = true,
|
||||
paramtype2 = "facedir",
|
||||
groups = {cracky=2, crumbly=2, not_in_creative_inventory=1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
drop = "techage:ta4_trafficlight2",
|
||||
})
|
||||
|
||||
for _,color in ipairs({"green", "amber", "red"}) do
|
||||
local tiles = {"techage_trafficlight2_" .. color .. '.png'}
|
||||
minetest.register_node("techage:ta4_trafficlight2B_" .. color, {
|
||||
description = TITLE,
|
||||
tiles = tiles,
|
||||
drawtype = "mesh",
|
||||
mesh = "techage_traffic_lightB.obj",
|
||||
selection_box = SelectionBox,
|
||||
|
||||
on_rightclick = on_rightclick,
|
||||
after_dig_node = after_dig_node,
|
||||
|
||||
paramtype = "light",
|
||||
use_texture_alpha = techage.CLIP,
|
||||
light_source = 10,
|
||||
sunlight_propagates = true,
|
||||
paramtype2 = "facedir",
|
||||
groups = {crumbly=0, not_in_creative_inventory=1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
drop = "techage:ta4_trafficlight2",
|
||||
})
|
||||
end
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:ta4_trafficlight1",
|
||||
recipe = {
|
||||
{"", "dye:black", ""},
|
||||
{"", "techage:ta4_signaltower", ""},
|
||||
{"", "default:steel_ingot", ""},
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:ta4_trafficlight2",
|
||||
recipe = {
|
||||
{"", "dye:orange", ""},
|
||||
{"", "techage:ta4_signaltower", ""},
|
||||
{"", "default:steel_ingot", ""},
|
||||
},
|
||||
})
|
||||
|
||||
techage.register_node({
|
||||
"techage:ta4_trafficlight1",
|
||||
"techage:ta4_trafficlight1_green",
|
||||
"techage:ta4_trafficlight1_amber",
|
||||
"techage:ta4_trafficlight1_red",
|
||||
"techage:ta4_trafficlight2",
|
||||
"techage:ta4_trafficlight2_green",
|
||||
"techage:ta4_trafficlight2_amber",
|
||||
"techage:ta4_trafficlight2_red",
|
||||
"techage:ta4_trafficlight1B",
|
||||
"techage:ta4_trafficlight1B_green",
|
||||
"techage:ta4_trafficlight1B_amber",
|
||||
"techage:ta4_trafficlight1B_red",
|
||||
"techage:ta4_trafficlight2B",
|
||||
"techage:ta4_trafficlight2B_green",
|
||||
"techage:ta4_trafficlight2B_amber",
|
||||
"techage:ta4_trafficlight2B_red"}, {
|
||||
on_recv_message = function(pos, src, topic, payload)
|
||||
if topic == "green" then
|
||||
switch_on(pos, "green")
|
||||
elseif topic == "amber" then
|
||||
switch_on(pos, "amber")
|
||||
elseif topic == "red" then
|
||||
switch_on(pos, "red")
|
||||
elseif topic == "off" then
|
||||
switch_off(pos)
|
||||
elseif topic == "state" then
|
||||
local meta = minetest.get_meta(pos)
|
||||
return meta:get_string("state")
|
||||
end
|
||||
end,
|
||||
on_beduino_receive_cmnd = function(pos, src, topic, payload)
|
||||
if topic == 2 then
|
||||
local color = ({"green", "amber", "red"})[payload[1]]
|
||||
if color then
|
||||
switch_on(pos, color)
|
||||
else
|
||||
switch_off(pos)
|
||||
end
|
||||
return 0
|
||||
else
|
||||
return 2 -- unknown or invalid topic
|
||||
end
|
||||
end,
|
||||
on_beduino_request_data = function(pos, src, topic, payload)
|
||||
if topic == 130 then
|
||||
local meta = minetest.get_meta(pos)
|
||||
local color = ({off = 0, green = 1, amber = 2, red = 3})[meta:get_string("state")] or 1
|
||||
return 0, {color}
|
||||
else
|
||||
return 2, "" -- unknown or invalid topic
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_node("techage:trafficlight_pole", {
|
||||
description = S("TA4 Traffic Light Pole"),
|
||||
tiles = {
|
||||
"techage_trafficlight_pole.png",
|
||||
},
|
||||
|
||||
paramtype2 = "facedir", -- important!
|
||||
drawtype = "nodebox",
|
||||
node_box = {
|
||||
type = "connected",
|
||||
fixed = {{ -4/32, -16/32, -4/32, 4/32, 16/32, 4/32}},
|
||||
connect_left = {{-16/32, 0/32, -3/32, 3/32, 6/32, 3/32}},
|
||||
connect_right = {{ -3/32, 0/32, -3/32, 16/32, 6/32, 3/32}},
|
||||
connect_back = {{ -3/32, 0/32, -3/32, 3/32, 6/32, 16/32}},
|
||||
connect_front = {{ -3/32, 0/32, -16/32, 3/32, 6/32, 3/32}},
|
||||
},
|
||||
connects_to = {
|
||||
"techage:trafficlight_arm",
|
||||
"techage:trafficlight_connector",
|
||||
"techage:ta4_trafficlight1",
|
||||
"techage:ta4_trafficlight1B",
|
||||
"techage:ta4_trafficlight1_red",
|
||||
"techage:ta4_trafficlight1_amber",
|
||||
"techage:ta4_trafficlight1_green",
|
||||
"techage:ta4_trafficlight1B_red",
|
||||
"techage:ta4_trafficlight1B_amber",
|
||||
"techage:ta4_trafficlight1B_green",
|
||||
"techage:ta4_trafficlight2",
|
||||
"techage:ta4_trafficlight2B",
|
||||
"techage:ta4_trafficlight2_red",
|
||||
"techage:ta4_trafficlight2_amber",
|
||||
"techage:ta4_trafficlight2_green",
|
||||
"techage:ta4_trafficlight2B_red",
|
||||
"techage:ta4_trafficlight2B_amber",
|
||||
"techage:ta4_trafficlight2B_green",
|
||||
},
|
||||
paramtype = "light",
|
||||
sunlight_propagates = true,
|
||||
is_ground_content = false,
|
||||
groups = {cracky=2, crumbly=2, choppy=2},
|
||||
sounds = default.node_sound_defaults(),
|
||||
})
|
||||
|
||||
minetest.register_node("techage:trafficlight_connector", {
|
||||
description = S("TA4 Traffic Light Connector"),
|
||||
tiles = {
|
||||
"techage_trafficlight_pole.png",
|
||||
},
|
||||
|
||||
paramtype2 = "facedir", -- important!
|
||||
drawtype = "nodebox",
|
||||
node_box = {
|
||||
type = "connected",
|
||||
fixed = {{ -4/32, -4/32, -4/32, 4/32, 10/32, 4/32}},
|
||||
connect_left = {{-16/32, 0/32, -3/32, 3/32, 6/32, 3/32}},
|
||||
connect_right = {{ -3/32, 0/32, -3/32, 16/32, 6/32, 3/32}},
|
||||
connect_back = {{ -3/32, 0/32, -3/32, 3/32, 6/32, 16/32}},
|
||||
connect_front = {{ -3/32, 0/32, -16/32, 3/32, 6/32, 3/32}},
|
||||
},
|
||||
connects_to = {
|
||||
"techage:trafficlight_arm",
|
||||
"techage:trafficlight_connector",
|
||||
"techage:trafficlight_pole",
|
||||
"techage:ta4_trafficlight1",
|
||||
"techage:ta4_trafficlight1B",
|
||||
"techage:ta4_trafficlight1_red",
|
||||
"techage:ta4_trafficlight1_amber",
|
||||
"techage:ta4_trafficlight1_green",
|
||||
"techage:ta4_trafficlight1B_red",
|
||||
"techage:ta4_trafficlight1B_amber",
|
||||
"techage:ta4_trafficlight1B_green",
|
||||
"techage:ta4_trafficlight2",
|
||||
"techage:ta4_trafficlight2B",
|
||||
"techage:ta4_trafficlight2_red",
|
||||
"techage:ta4_trafficlight2_amber",
|
||||
"techage:ta4_trafficlight2_green",
|
||||
"techage:ta4_trafficlight2B_red",
|
||||
"techage:ta4_trafficlight2B_amber",
|
||||
"techage:ta4_trafficlight2B_green",
|
||||
},
|
||||
paramtype = "light",
|
||||
sunlight_propagates = true,
|
||||
is_ground_content = false,
|
||||
groups = {cracky=2, crumbly=2, choppy=2},
|
||||
sounds = default.node_sound_defaults(),
|
||||
})
|
||||
|
||||
minetest.register_node("techage:trafficlight_arm", {
|
||||
description = S("TA4 Traffic Light Arm"),
|
||||
tiles = {
|
||||
"techage_trafficlight_pole.png",
|
||||
},
|
||||
|
||||
paramtype2 = "facedir", -- important!
|
||||
drawtype = "nodebox",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {{ -3/32, 0/32, -16/32, 3/32, 6/32, 16/32}},
|
||||
},
|
||||
paramtype = "light",
|
||||
sunlight_propagates = true,
|
||||
is_ground_content = false,
|
||||
groups = {cracky=2, crumbly=2, choppy=2},
|
||||
sounds = default.node_sound_defaults(),
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:trafficlight_pole",
|
||||
recipe = {
|
||||
{"", "basic_materials:steel_bar", ""},
|
||||
{"", "basic_materials:steel_bar", "dye:dark_grey"},
|
||||
{"", "basic_materials:steel_bar", ""},
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:trafficlight_arm",
|
||||
recipe = {
|
||||
{"", "dye:dark_grey", ""},
|
||||
{"basic_materials:steel_bar", "basic_materials:steel_bar", "basic_materials:steel_bar"},
|
||||
{"", "", ""},
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "techage:trafficlight_connector",
|
||||
recipe = {
|
||||
{"dye:dark_grey", "basic_materials:steel_bar", ""},
|
||||
{"basic_materials:steel_bar", "", ""},
|
||||
{"", "", ""},
|
||||
},
|
||||
})
|
||||
Reference in new issue
Block a user