mirror of
https://github.com/joe7575/techpack.git
synced 2024-11-25 16:43:50 +01:00
V1.13 Smartline Controller revised. Liquid Sampler node added. Release notes added
This commit is contained in:
parent
4c86e4e6b5
commit
3719bb6071
4
.gitignore
vendored
4
.gitignore
vendored
@ -44,4 +44,6 @@ luac.out
|
|||||||
org.eclipse.*
|
org.eclipse.*
|
||||||
*.lua.new
|
*.lua.new
|
||||||
|
|
||||||
test_*.lua
|
test_*.lua
|
||||||
|
|
||||||
|
shrink.py
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# TechPack V1.12
|
# TechPack V1.13
|
||||||
|
|
||||||
TechPack, a Mining, Crafting, & Farming Modpack for Minetest.
|
TechPack, a Mining, Crafting, & Farming Modpack for Minetest.
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ Gravelsieve optional: moreores, hopper, pipeworks
|
|||||||
tubelib_addons1 optional: unified_inventory
|
tubelib_addons1 optional: unified_inventory
|
||||||
|
|
||||||
|
|
||||||
### History
|
### History
|
||||||
- 2018-03-18 V1.00 * Tubelib, tubelib_addons1, tubelib_addons2, smartline, and gravelsieve combined to one modpack.
|
- 2018-03-18 V1.00 * Tubelib, tubelib_addons1, tubelib_addons2, smartline, and gravelsieve combined to one modpack.
|
||||||
- 2018-03-24 V1.01 * Support for Ethereal added
|
- 2018-03-24 V1.01 * Support for Ethereal added
|
||||||
- 2018-03-27 V1.02 * Timer improvements for unloaded areas
|
- 2018-03-27 V1.02 * Timer improvements for unloaded areas
|
||||||
@ -91,3 +91,6 @@ tubelib_addons1 optional: unified_inventory
|
|||||||
- 2018-08-08 V1.10 * tubelib_addon3 with high performance nodes added
|
- 2018-08-08 V1.10 * tubelib_addon3 with high performance nodes added
|
||||||
- 2018-08-13 V1.11 * Detector node added
|
- 2018-08-13 V1.11 * Detector node added
|
||||||
- 2018-08-14 V1.12 * Teleporter node added
|
- 2018-08-14 V1.12 * Teleporter node added
|
||||||
|
- 2018-08-28 V1.13 * Smartline Controller completely revised. Liquid Sampler added
|
||||||
|
|
||||||
|
See releasenotes.txt for further information
|
33
releasenotes.md
Normal file
33
releasenotes.md
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# Release Notes of the ModPack TechPack [techpack]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## V1.13 Beta (2018-08-28)
|
||||||
|
|
||||||
|
|
||||||
|
### Additions
|
||||||
|
|
||||||
|
- A Liquid Sampler node is added. It is able to take all kind or renewable liquids (registered via bucket.register_liquid)
|
||||||
|
Currently only useful for recipes where a water-bucket is needed.
|
||||||
|
- Smartline has a new IF-THIS-THEN-THAT Controller V2 which should be much simpler to use.
|
||||||
|
It will replace the current one (V1).
|
||||||
|
Currently both are active, but if you dig a controller V1 it will be converted to a controller V2.
|
||||||
|
- The new controller needs batteries. Thus, Smartline has now its own battery node. The sl_controller.battery will not be
|
||||||
|
needed any more.
|
||||||
|
|
||||||
|
|
||||||
|
### Removals
|
||||||
|
|
||||||
|
- recipe for sl_controller/batteries removed.
|
||||||
|
- Recipe for Smartline controller V1 removed.
|
||||||
|
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
|
||||||
|
- Quarry can no go direct from FAULT into RUNNING without reset the digging position
|
||||||
|
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
|
||||||
|
- bug in open/close door command for Minetest v0.4.17+ fixed
|
||||||
|
|
@ -9,6 +9,8 @@
|
|||||||
See LICENSE.txt for more information
|
See LICENSE.txt for more information
|
||||||
|
|
||||||
battery.lua:
|
battery.lua:
|
||||||
|
|
||||||
|
REPLACED BY SMARTLINE BATTERY !!!
|
||||||
|
|
||||||
]]--
|
]]--
|
||||||
|
|
||||||
@ -71,13 +73,13 @@ local function register_battery(ext, percent, nici)
|
|||||||
local percent = calc_percent(tonumber(oldmetadata.fields.content))
|
local percent = calc_percent(tonumber(oldmetadata.fields.content))
|
||||||
local stack
|
local stack
|
||||||
if percent > 95 then
|
if percent > 95 then
|
||||||
stack = ItemStack("sl_controller:battery")
|
stack = ItemStack("smartline:battery")
|
||||||
elseif percent > 75 then
|
elseif percent > 75 then
|
||||||
stack = ItemStack("sl_controller:battery75")
|
stack = ItemStack("smartline:battery75")
|
||||||
elseif percent > 50 then
|
elseif percent > 50 then
|
||||||
stack = ItemStack("sl_controller:battery50")
|
stack = ItemStack("smartline:battery50")
|
||||||
elseif percent > 25 then
|
elseif percent > 25 then
|
||||||
stack = ItemStack("sl_controller:battery25")
|
stack = ItemStack("smartline:battery25")
|
||||||
else
|
else
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@ -95,7 +97,7 @@ local function register_battery(ext, percent, nici)
|
|||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
register_battery("", 1.0, 0)
|
register_battery("", 1.0, 1)
|
||||||
register_battery("75", 0.75, 1)
|
register_battery("75", 0.75, 1)
|
||||||
register_battery("50", 0.5, 1)
|
register_battery("50", 0.5, 1)
|
||||||
register_battery("25", 0.25, 1)
|
register_battery("25", 0.25, 1)
|
||||||
@ -135,22 +137,22 @@ minetest.register_node("sl_controller:battery_empty", {
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
if minetest.global_exists("moreores") then
|
--if minetest.global_exists("moreores") then
|
||||||
minetest.register_craft({
|
-- minetest.register_craft({
|
||||||
output = "sl_controller:battery 2",
|
-- output = "sl_controller:battery 2",
|
||||||
recipe = {
|
-- recipe = {
|
||||||
{"", "moreores:silver_ingot", ""},
|
-- {"", "moreores:silver_ingot", ""},
|
||||||
{"", "default:copper_ingot", ""},
|
-- {"", "default:copper_ingot", ""},
|
||||||
{"", "moreores:silver_ingot", ""},
|
-- {"", "moreores:silver_ingot", ""},
|
||||||
}
|
-- }
|
||||||
})
|
-- })
|
||||||
else
|
--else
|
||||||
minetest.register_craft({
|
-- minetest.register_craft({
|
||||||
output = "sl_controller:battery 2",
|
-- output = "sl_controller:battery 2",
|
||||||
recipe = {
|
-- recipe = {
|
||||||
{"", "default:tin_ingot", ""},
|
-- {"", "default:tin_ingot", ""},
|
||||||
{"", "default:copper_ingot", ""},
|
-- {"", "default:copper_ingot", ""},
|
||||||
{"", "default:tin_ingot", ""},
|
-- {"", "default:tin_ingot", ""},
|
||||||
}
|
-- }
|
||||||
})
|
-- })
|
||||||
end
|
--end
|
||||||
|
@ -181,6 +181,7 @@ sl_controller.register_action("door", {
|
|||||||
if door then
|
if door then
|
||||||
local player = {
|
local player = {
|
||||||
get_player_name = function() return self.meta.owner end,
|
get_player_name = function() return self.meta.owner end,
|
||||||
|
is_player = function() return true end,
|
||||||
}
|
}
|
||||||
if text == "open" then
|
if text == "open" then
|
||||||
door:open(player)
|
door:open(player)
|
||||||
|
@ -230,7 +230,7 @@ local function compile(pos, meta, number)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function battery(pos)
|
local function battery(pos)
|
||||||
local battery_pos = minetest.find_node_near(pos, 1, {"sl_controller:battery"})
|
local battery_pos = minetest.find_node_near(pos, 1, {"sl_controller:battery", "smartline:battery"})
|
||||||
if battery_pos then
|
if battery_pos then
|
||||||
local meta = minetest.get_meta(pos)
|
local meta = minetest.get_meta(pos)
|
||||||
meta:set_string("battery", minetest.pos_to_string(battery_pos))
|
meta:set_string("battery", minetest.pos_to_string(battery_pos))
|
||||||
@ -448,13 +448,13 @@ minetest.register_craft({
|
|||||||
local function set_input(pos, number, input, val)
|
local function set_input(pos, number, input, val)
|
||||||
if input then
|
if input then
|
||||||
if Cache[number] and Cache[number].inputs then
|
if Cache[number] and Cache[number].inputs then
|
||||||
|
Cache[number].inputs[input] = val
|
||||||
-- only one event per second
|
-- only one event per second
|
||||||
local t = minetest.get_us_time()
|
local t = minetest.get_us_time()
|
||||||
if not Cache[number].last_event or Cache[number].last_event < t then
|
if not Cache[number].last_event or Cache[number].last_event < t then
|
||||||
Cache[number].inputs[input] = val
|
|
||||||
local meta = minetest.get_meta(pos)
|
local meta = minetest.get_meta(pos)
|
||||||
minetest.after(0.1, call_loop, pos, meta, -1)
|
minetest.after(0.01, call_loop, pos, meta, -1)
|
||||||
Cache[number].last_event = t + 1000000 -- add one second
|
Cache[number].last_event = t + 500000 -- add 500 ms
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -584,6 +584,7 @@ local function door_toggle(pos, owner, state)
|
|||||||
if door then
|
if door then
|
||||||
local player = {
|
local player = {
|
||||||
get_player_name = function() return owner end,
|
get_player_name = function() return owner end,
|
||||||
|
is_player = function() return true end,
|
||||||
}
|
}
|
||||||
if state == "open" then
|
if state == "open" then
|
||||||
door:open(player)
|
door:open(player)
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
controller.lua:
|
controller.lua:
|
||||||
|
|
||||||
|
REPLACED BY SMARTLINE CONTROLLER2 !!!
|
||||||
]]--
|
]]--
|
||||||
|
|
||||||
|
|
||||||
@ -63,7 +64,6 @@ The colors show, if conditions are true or false and
|
|||||||
if actions were already executed or not.
|
if actions were already executed or not.
|
||||||
It has a 'update' button to update the view.
|
It has a 'update' button to update the view.
|
||||||
|
|
||||||
For more information, see: goo.gl/fF5ap6
|
|
||||||
]]
|
]]
|
||||||
|
|
||||||
local sOUTPUT = "Press 'help' for edit commands"
|
local sOUTPUT = "Press 'help' for edit commands"
|
||||||
@ -117,8 +117,6 @@ local function exec_action(data, environ, number)
|
|||||||
ActnRunTimeHandlers[data.__idx__](data, environ, number)
|
ActnRunTimeHandlers[data.__idx__](data, environ, number)
|
||||||
end
|
end
|
||||||
|
|
||||||
smartline = {}
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- API functions for condition/action registrations
|
-- API functions for condition/action registrations
|
||||||
--
|
--
|
||||||
@ -845,9 +843,10 @@ minetest.register_node("smartline:controller", {
|
|||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
sunlight_propagates = true,
|
sunlight_propagates = true,
|
||||||
paramtype2 = "facedir",
|
paramtype2 = "facedir",
|
||||||
groups = {choppy=1, cracky=1, crumbly=1},
|
groups = {choppy=1, cracky=1, crumbly=1, not_in_creative_inventory=1},
|
||||||
is_ground_content = false,
|
is_ground_content = false,
|
||||||
sounds = default.node_sound_stone_defaults(),
|
sounds = default.node_sound_stone_defaults(),
|
||||||
|
drop = "smartline:controller2",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
105
smartline/icta/action.lua
Normal file
105
smartline/icta/action.lua
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
ICTA Controller
|
||||||
|
===============
|
||||||
|
|
||||||
|
Part of the SmartLine mod
|
||||||
|
|
||||||
|
Copyright (C) 2018 Joachim Stolberg
|
||||||
|
|
||||||
|
LGPLv2.1+
|
||||||
|
See LICENSE.txt for more information
|
||||||
|
|
||||||
|
action.lua
|
||||||
|
|
||||||
|
]]--
|
||||||
|
|
||||||
|
local sl = smartline
|
||||||
|
|
||||||
|
--local mail_exists = minetest.get_modpath("mail") and mail ~= nil TODO
|
||||||
|
|
||||||
|
-- tables with all data from action registrations
|
||||||
|
local kvRegisteredActn = {}
|
||||||
|
|
||||||
|
-- list of keys for actions
|
||||||
|
local aActnTypes = {}
|
||||||
|
|
||||||
|
-- list of titles for actions
|
||||||
|
local aActnTitles = {}
|
||||||
|
|
||||||
|
--
|
||||||
|
-- API function for action registrations
|
||||||
|
--
|
||||||
|
function sl.icta_register_action(key, tData)
|
||||||
|
table.insert(aActnTypes, key)
|
||||||
|
table.insert(aActnTitles, tData.title)
|
||||||
|
tData.__idx__ = #aActnTypes
|
||||||
|
if kvRegisteredActn[key] ~= nil then
|
||||||
|
print("[SmartLine] Action registration error "..key)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
kvRegisteredActn[key] = tData
|
||||||
|
for _,item in ipairs(tData.formspec) do
|
||||||
|
if item.type == "textlist" then
|
||||||
|
item.tChoices = string.split(item.choices, ",")
|
||||||
|
item.num_choices = #item.tChoices
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- return formspec string
|
||||||
|
function sl.actn_formspec(row, kvSelect)
|
||||||
|
return sl.submenu_generate_formspec(
|
||||||
|
row, "actn", "Action type", aActnTypes, aActnTitles, kvRegisteredActn, kvSelect)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- evaluate the row action input
|
||||||
|
-- and return new data
|
||||||
|
function sl.actn_eval_input(kvSelect, fields)
|
||||||
|
kvSelect = sl.submenu_eval_input(kvRegisteredActn, aActnTypes, aActnTitles, kvSelect, fields)
|
||||||
|
return kvSelect
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- return the Lua code
|
||||||
|
function sl.code_action(kvSelect, environ)
|
||||||
|
if kvSelect and kvRegisteredActn[kvSelect.choice] then
|
||||||
|
if smartline.submenu_verify(kvRegisteredActn, kvSelect) then
|
||||||
|
return kvRegisteredActn[kvSelect.choice].code(kvSelect, environ)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
sl.icta_register_action("default", {
|
||||||
|
title = "",
|
||||||
|
formspec = {},
|
||||||
|
code = function(data, environ) return false, false end,
|
||||||
|
button = function(data, environ) return "..." end,
|
||||||
|
})
|
||||||
|
|
||||||
|
sl.icta_register_action("print", {
|
||||||
|
title = "print to output window",
|
||||||
|
formspec = {
|
||||||
|
{
|
||||||
|
type = "ascii",
|
||||||
|
name = "text",
|
||||||
|
label = "Output the following text",
|
||||||
|
default = "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type = "label",
|
||||||
|
name = "lbl",
|
||||||
|
label = "Hint: Use a '*' character as reference to any\ncondition state",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
button = function(data, environ)
|
||||||
|
return 'print(...)'
|
||||||
|
end,
|
||||||
|
code = function(data, environ)
|
||||||
|
local s1 = 'local text = string.gsub("'..(smartline.escape(data.text))..'", "*", env.result[#])'
|
||||||
|
local s2 = 'output(env.pos, text)'
|
||||||
|
return s1.."\n\t"..s2
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
123
smartline/icta/balancer.lua
Normal file
123
smartline/icta/balancer.lua
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
ICTA Controller
|
||||||
|
===============
|
||||||
|
|
||||||
|
Part of the SmartLine mod
|
||||||
|
|
||||||
|
Copyright (C) 2018 Joachim Stolberg
|
||||||
|
|
||||||
|
LGPLv2.1+
|
||||||
|
See LICENSE.txt for more information
|
||||||
|
|
||||||
|
balancer.lua
|
||||||
|
|
||||||
|
]]--
|
||||||
|
|
||||||
|
local MAX_DIFF = 10
|
||||||
|
|
||||||
|
function smartline.balancer_condition(number1, number2, ratio1, ratio2, owner)
|
||||||
|
local cnt1 = tubelib.send_request(number1, "counter", nil) / ratio1
|
||||||
|
local cnt2 = tubelib.send_request(number2, "counter", nil) / ratio2
|
||||||
|
if cnt1 > cnt2 + MAX_DIFF then
|
||||||
|
tubelib.send_message(number1, owner, nil, "off", nil)
|
||||||
|
return number1
|
||||||
|
elseif cnt2 > cnt1 + MAX_DIFF then
|
||||||
|
tubelib.send_message(number2, owner, nil, "off", nil)
|
||||||
|
return number2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
smartline.icta_register_condition("ratio", {
|
||||||
|
title = "Balancer ratio",
|
||||||
|
formspec = {
|
||||||
|
{
|
||||||
|
type = "numbers",
|
||||||
|
name = "number1",
|
||||||
|
label = "Pusher1",
|
||||||
|
default = "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type = "digits",
|
||||||
|
name = "ratio1",
|
||||||
|
label = "Ratio1",
|
||||||
|
default = "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type = "numbers",
|
||||||
|
name = "number2",
|
||||||
|
label = "Pusher2",
|
||||||
|
default = "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type = "digits",
|
||||||
|
name = "ratio2",
|
||||||
|
label = "Ratio1",
|
||||||
|
default = "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type = "label",
|
||||||
|
name = "lbl",
|
||||||
|
label = "Hint: Pusher1:Pusher2 shall have a\nitem counter ratio of Ratio1:Ratio2.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
-- Return two chunks of executable Lua code for the controller, according:
|
||||||
|
-- return <read condition>, <expected result>
|
||||||
|
code = function(data, environ)
|
||||||
|
local s = 'smartline.balancer_condition("%s", "%s", %s, %s, "%s")'
|
||||||
|
return s:format(data.number1, data.number2, data.ratio1, data.ratio2, environ.owner), '~= nil'
|
||||||
|
end,
|
||||||
|
button = function(data, environ)
|
||||||
|
return "ratio("..(data.ratio1 or "???").."/"..(data.ratio2 or "???")..")"
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
smartline.icta_register_action("balancer", {
|
||||||
|
title = "Balancer Control",
|
||||||
|
formspec = {
|
||||||
|
{
|
||||||
|
type = "label",
|
||||||
|
name = "lbl",
|
||||||
|
label = "Hint: Stop one Pusher and start\nit again after 'after' seconds.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
button = function(data, environ)
|
||||||
|
return 'balancer()'
|
||||||
|
end,
|
||||||
|
code = function(data, environ)
|
||||||
|
local s = 'tubelib.send_message(env.result[#], "%s", nil, "on", nil)'
|
||||||
|
return string.format(s, data.number, environ.owner)
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
smartline.icta_register_action("clearcounter", {
|
||||||
|
title = "Balancer clear counter",
|
||||||
|
formspec = {
|
||||||
|
{
|
||||||
|
type = "numbers",
|
||||||
|
name = "number1",
|
||||||
|
label = "Pusher1",
|
||||||
|
default = "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type = "numbers",
|
||||||
|
name = "number2",
|
||||||
|
label = "Pusher2",
|
||||||
|
default = "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type = "label",
|
||||||
|
name = "lbl",
|
||||||
|
label = "Hint: Clear both Pusher counters.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
button = function(data, environ)
|
||||||
|
return 'balancer()'
|
||||||
|
end,
|
||||||
|
code = function(data, environ)
|
||||||
|
local s = [[tubelib.send_message("%s", "%s", nil, "clear_counter", nil)
|
||||||
|
tubelib.send_message("%s", "%s", nil, "clear_counter", nil)]]
|
||||||
|
return string.format(s, data.number1, environ.owner, data.number2, environ.owner)
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
158
smartline/icta/battery.lua
Normal file
158
smartline/icta/battery.lua
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
ICTA Controller
|
||||||
|
===============
|
||||||
|
|
||||||
|
Copyright (C) 2018 Joachim Stolberg
|
||||||
|
|
||||||
|
LGPLv2.1+
|
||||||
|
See LICENSE.txt for more information
|
||||||
|
|
||||||
|
battery.lua
|
||||||
|
|
||||||
|
]]--
|
||||||
|
|
||||||
|
local BATTERY_CAPACITY = 5000000
|
||||||
|
|
||||||
|
local function calc_percent(content)
|
||||||
|
local val = (BATTERY_CAPACITY - math.min(content or 0, BATTERY_CAPACITY))
|
||||||
|
return 100 - math.floor((val * 100.0 / BATTERY_CAPACITY))
|
||||||
|
end
|
||||||
|
|
||||||
|
local function on_timer(pos, elapsed)
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
local percent = calc_percent(meta:get_int("content"))
|
||||||
|
meta:set_string("infotext", "Battery ("..percent.."%)")
|
||||||
|
if percent == 0 then
|
||||||
|
local node = minetest.get_node(pos)
|
||||||
|
node.name = "smartline:battery_empty"
|
||||||
|
minetest.swap_node(pos, node)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
local function register_battery(ext, percent, nici)
|
||||||
|
minetest.register_node("smartline:battery"..ext, {
|
||||||
|
description = "Battery "..ext,
|
||||||
|
inventory_image = 'smartline_battery_inventory.png',
|
||||||
|
wield_image = 'smartline_battery_inventory.png',
|
||||||
|
tiles = {
|
||||||
|
-- up, down, right, left, back, front
|
||||||
|
"smartline.png",
|
||||||
|
"smartline.png",
|
||||||
|
"smartline.png",
|
||||||
|
"smartline.png",
|
||||||
|
"smartline.png",
|
||||||
|
"smartline.png^smartline_battery_green.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 = minetest.get_meta(pos)
|
||||||
|
meta:set_int("content", BATTERY_CAPACITY * percent)
|
||||||
|
local node = minetest.get_node(pos)
|
||||||
|
node.name = "smartline:battery"
|
||||||
|
minetest.swap_node(pos, node)
|
||||||
|
on_timer(pos, 1)
|
||||||
|
minetest.get_node_timer(pos):start(30)
|
||||||
|
end,
|
||||||
|
|
||||||
|
on_timer = on_timer,
|
||||||
|
|
||||||
|
|
||||||
|
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||||
|
local percent = calc_percent(tonumber(oldmetadata.fields.content))
|
||||||
|
local stack
|
||||||
|
if percent > 95 then
|
||||||
|
stack = ItemStack("smartline:battery")
|
||||||
|
elseif percent > 75 then
|
||||||
|
stack = ItemStack("smartline:battery75")
|
||||||
|
elseif percent > 50 then
|
||||||
|
stack = ItemStack("smartline:battery50")
|
||||||
|
elseif percent > 25 then
|
||||||
|
stack = ItemStack("smartline:battery25")
|
||||||
|
else
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local inv = minetest.get_inventory({type="player", name=digger:get_player_name()})
|
||||||
|
inv:add_item("main", stack)
|
||||||
|
end,
|
||||||
|
|
||||||
|
paramtype = "light",
|
||||||
|
sunlight_propagates = true,
|
||||||
|
paramtype2 = "facedir",
|
||||||
|
groups = {choppy=1, cracky=1, crumbly=1, not_in_creative_inventory=nici},
|
||||||
|
drop = "",
|
||||||
|
is_ground_content = false,
|
||||||
|
sounds = default.node_sound_stone_defaults(),
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
register_battery("", 1.0, 0)
|
||||||
|
register_battery("75", 0.75, 1)
|
||||||
|
register_battery("50", 0.5, 1)
|
||||||
|
register_battery("25", 0.25, 1)
|
||||||
|
|
||||||
|
minetest.register_node("smartline:battery_empty", {
|
||||||
|
description = "Battery",
|
||||||
|
tiles = {
|
||||||
|
-- up, down, right, left, back, front
|
||||||
|
"smartline.png",
|
||||||
|
"smartline.png",
|
||||||
|
"smartline.png",
|
||||||
|
"smartline.png",
|
||||||
|
"smartline.png",
|
||||||
|
"smartline.png^smartline_battery_red.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 = minetest.get_meta(pos)
|
||||||
|
meta:set_int("content", 0)
|
||||||
|
end,
|
||||||
|
|
||||||
|
paramtype = "light",
|
||||||
|
sunlight_propagates = true,
|
||||||
|
paramtype2 = "facedir",
|
||||||
|
groups = {choppy=1, cracky=1, crumbly=1, not_in_creative_inventory=1},
|
||||||
|
drop = "",
|
||||||
|
is_ground_content = false,
|
||||||
|
sounds = default.node_sound_stone_defaults(),
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
if minetest.global_exists("moreores") then
|
||||||
|
minetest.register_craft({
|
||||||
|
output = "smartline:battery 2",
|
||||||
|
recipe = {
|
||||||
|
{"", "moreores:silver_ingot", ""},
|
||||||
|
{"", "default:copper_ingot", ""},
|
||||||
|
{"", "moreores:silver_ingot", ""},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
else
|
||||||
|
minetest.register_craft({
|
||||||
|
output = "smartline:battery 2",
|
||||||
|
recipe = {
|
||||||
|
{"", "default:tin_ingot", ""},
|
||||||
|
{"", "default:copper_ingot", ""},
|
||||||
|
{"", "default:tin_ingot", ""},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
481
smartline/icta/commands.lua
Normal file
481
smartline/icta/commands.lua
Normal file
@ -0,0 +1,481 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
ICTA Controller
|
||||||
|
===============
|
||||||
|
|
||||||
|
Part of the SmartLine mod
|
||||||
|
|
||||||
|
Copyright (C) 2018 Joachim Stolberg
|
||||||
|
|
||||||
|
LGPLv2.1+
|
||||||
|
See LICENSE.txt for more information
|
||||||
|
|
||||||
|
command.lua:
|
||||||
|
|
||||||
|
Register all controller commands
|
||||||
|
|
||||||
|
]]--
|
||||||
|
|
||||||
|
local sl = smartline
|
||||||
|
|
||||||
|
function sl.operand(s)
|
||||||
|
if s == "is" then
|
||||||
|
return "== "
|
||||||
|
else
|
||||||
|
return "~= "
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- '#' is used as placeholder for rule numbers and has to be escaped
|
||||||
|
function smartline.escape(s)
|
||||||
|
return s:gsub("#", '"..string.char(35).."')
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
smartline.icta_register_condition("once", {
|
||||||
|
title = "once",
|
||||||
|
formspec = {
|
||||||
|
{
|
||||||
|
type = "label",
|
||||||
|
name = "lbl",
|
||||||
|
label = "Hint: Once after start.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
-- Return two chunks of executable Lua code for the controller, according:
|
||||||
|
-- return <read condition>, <expected result>
|
||||||
|
code = function(data, environ)
|
||||||
|
return 'env.ticks', '== 1'
|
||||||
|
end,
|
||||||
|
button = function(data, environ) return "once" end,
|
||||||
|
})
|
||||||
|
|
||||||
|
smartline.icta_register_condition("true", {
|
||||||
|
title = "true",
|
||||||
|
formspec = {
|
||||||
|
{
|
||||||
|
type = "label",
|
||||||
|
name = "lbl",
|
||||||
|
label = "Hint: Condition is always true.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
code = function(data, environ)
|
||||||
|
return '"true"', '== "true"'
|
||||||
|
end,
|
||||||
|
button = function(data, environ) return "true" end,
|
||||||
|
})
|
||||||
|
|
||||||
|
smartline.icta_register_condition("condition", {
|
||||||
|
title = "Condition",
|
||||||
|
formspec = {
|
||||||
|
{
|
||||||
|
type = "textlist",
|
||||||
|
name = "condition",
|
||||||
|
label = "the action is executed, if",
|
||||||
|
choices = "condition 1,condition 2,condition 3,condition 4,condition 5,condition 6,condition 7,condition 8",
|
||||||
|
default = "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type = "textlist",
|
||||||
|
name = "operand",
|
||||||
|
choices = "was true, was not true",
|
||||||
|
default = "was true",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type = "label",
|
||||||
|
name = "lbl",
|
||||||
|
label = "Hint: Execute two or several actions\nbased on one condition.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
code = function(data, environ)
|
||||||
|
local idx = data.condition:byte(-1) - 0x30
|
||||||
|
local expected_result = "== false"
|
||||||
|
if data.operand == "was true" then
|
||||||
|
expected_result = "== true"
|
||||||
|
end
|
||||||
|
return "env.condition["..idx.."]", expected_result
|
||||||
|
end,
|
||||||
|
button = function(data, environ) return data.condition or "???" end,
|
||||||
|
})
|
||||||
|
|
||||||
|
smartline.icta_register_condition("input", {
|
||||||
|
title = "inputs",
|
||||||
|
formspec = {
|
||||||
|
{
|
||||||
|
type = "digits",
|
||||||
|
name = "number",
|
||||||
|
label = "input from node with number",
|
||||||
|
default = "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type = "textlist",
|
||||||
|
name = "operand",
|
||||||
|
choices = "is,is not",
|
||||||
|
default = "is",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type = "textlist",
|
||||||
|
name = "value",
|
||||||
|
choices = "on,off,false",
|
||||||
|
default = "on",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type = "label",
|
||||||
|
name = "lbl",
|
||||||
|
label = "Hint: An input is only available,\nif a nodes sends on/of\ncommands to the controller.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
button = function(data, environ) -- default button label
|
||||||
|
return 'input('..(data.number or "???")..')'
|
||||||
|
end,
|
||||||
|
code = function(data, environ)
|
||||||
|
return 'env.input["'..data.number..'"]',
|
||||||
|
sl.operand(data.operand)..'"'..data.value..'"'
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
smartline.icta_register_condition("state", {
|
||||||
|
title = "node state request",
|
||||||
|
formspec = {
|
||||||
|
{
|
||||||
|
type = "digits",
|
||||||
|
name = "number",
|
||||||
|
label = "state from node with number",
|
||||||
|
default = "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type = "textlist",
|
||||||
|
name = "operand",
|
||||||
|
label = "",
|
||||||
|
choices = "is,is not",
|
||||||
|
default = "is",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type = "textlist",
|
||||||
|
name = "value",
|
||||||
|
label = "",
|
||||||
|
choices = "stopped,running,standby,blocked,fault",
|
||||||
|
default = "stopped",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type = "label",
|
||||||
|
name = "lbl",
|
||||||
|
label = "Hint: Read the state from another node.\nWorks for Pusher, Harvester, Quarry,\nand others.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
button = function(data, environ) -- default button label
|
||||||
|
return 'state('..(data.number or "???")..')'
|
||||||
|
end,
|
||||||
|
code = function(data, environ)
|
||||||
|
return 'tubelib.send_request("'..data.number..'", "state", "")',
|
||||||
|
sl.operand(data.operand)..'"'..data.value..'"'
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
smartline.icta_register_condition("fuel", {
|
||||||
|
title = "fuel state request",
|
||||||
|
formspec = {
|
||||||
|
{
|
||||||
|
type = "digits",
|
||||||
|
name = "number",
|
||||||
|
label = "fuel state from node with number",
|
||||||
|
default = "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type = "textlist",
|
||||||
|
name = "operand",
|
||||||
|
label = "",
|
||||||
|
choices = "is,is not",
|
||||||
|
default = "is",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type = "textlist",
|
||||||
|
name = "value",
|
||||||
|
label = "",
|
||||||
|
choices = "full,loaded,empty",
|
||||||
|
default = "full"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type = "label",
|
||||||
|
name = "lbl",
|
||||||
|
label = "Hint: Read the fuel state from another node.\nWorks for Harvester and Quarry",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
button = function(data, environ)
|
||||||
|
return 'fuel('..(data.number or "???")..')'
|
||||||
|
end,
|
||||||
|
code = function(data, environ)
|
||||||
|
return 'tubelib.send_request("'..data.number..'", "fuel", "")',
|
||||||
|
sl.operand(data.operand)..'"'..data.value..'"'
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
smartline.icta_register_condition("signaltower", {
|
||||||
|
title = "Signal Tower state request",
|
||||||
|
formspec = {
|
||||||
|
{
|
||||||
|
type = "digits",
|
||||||
|
name = "number",
|
||||||
|
label = "state from Signal Tower with number",
|
||||||
|
default = "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type = "textlist",
|
||||||
|
name = "operand",
|
||||||
|
label = "",
|
||||||
|
choices = "is,is not",
|
||||||
|
default = "is",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type = "textlist",
|
||||||
|
name = "value",
|
||||||
|
label = "",
|
||||||
|
choices = "off,green,amber,red",
|
||||||
|
default = "off",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type = "label",
|
||||||
|
name = "lbl",
|
||||||
|
label = "Hint: Read the state from a Signal Tower.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
button = function(data, environ) -- default button label
|
||||||
|
return 'tower('..(data.number or "???")..')'
|
||||||
|
end,
|
||||||
|
code = function(data, environ)
|
||||||
|
return 'tubelib.send_request("'..data.number..'", "state", "")',
|
||||||
|
sl.operand(data.operand)..'"'..data.value..'"'
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
smartline.icta_register_action("signaltower", {
|
||||||
|
title = "Signal Tower command",
|
||||||
|
formspec = {
|
||||||
|
{
|
||||||
|
type = "numbers",
|
||||||
|
name = "number",
|
||||||
|
label = "set Signal Tower with number",
|
||||||
|
default = "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type = "textlist",
|
||||||
|
name = "value",
|
||||||
|
label = "to color",
|
||||||
|
choices = "off,green,amber,red",
|
||||||
|
default = "red",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type = "label",
|
||||||
|
name = "lbl",
|
||||||
|
label = "Hint: Turn on a lamp from a Signal Tower.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
button = function(data, environ)
|
||||||
|
return 'tower('..(data.value or "???")..')'
|
||||||
|
end,
|
||||||
|
code = function(data, environ)
|
||||||
|
local s = 'tubelib.send_message("%s", "%s", nil, "%s", nil)'
|
||||||
|
return string.format(s, data.number, environ.owner, data.value)
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
smartline.icta_register_action("switch", {
|
||||||
|
title = "node on/off command",
|
||||||
|
formspec = {
|
||||||
|
{
|
||||||
|
type = "numbers",
|
||||||
|
name = "number",
|
||||||
|
label = "set node with number",
|
||||||
|
default = "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type = "textlist",
|
||||||
|
name = "value",
|
||||||
|
label = "to state",
|
||||||
|
choices = "on,off",
|
||||||
|
default = "on",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type = "label",
|
||||||
|
name = "lbl",
|
||||||
|
label = "Hint: Used for pushers, lamps, machines, gates,...",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
button = function(data, environ)
|
||||||
|
return 'turn('..(data.value or "???")..')'
|
||||||
|
end,
|
||||||
|
code = function(data, environ)
|
||||||
|
local s = 'tubelib.send_message("%s", "%s", nil, "%s", nil)'
|
||||||
|
return string.format(s, data.number, environ.owner, data.value)
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
smartline.icta_register_action("display", {
|
||||||
|
title = "Display: overwrite one line",
|
||||||
|
formspec = {
|
||||||
|
{
|
||||||
|
type = "numbers",
|
||||||
|
name = "number",
|
||||||
|
label = "output to Display with number",
|
||||||
|
default = "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type = "textlist",
|
||||||
|
name = "row",
|
||||||
|
label = "Display line",
|
||||||
|
choices = "1,2,3,4,5,6,7,8,9",
|
||||||
|
default = "1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type = "ascii",
|
||||||
|
name = "text",
|
||||||
|
label = "the following text",
|
||||||
|
default = "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type = "label",
|
||||||
|
name = "lbl",
|
||||||
|
label = "Hint: Use a '*' character as reference to any\ncondition state",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
code = function(data, environ)
|
||||||
|
local s1 = string.format('local text = string.gsub("%s", "*", env.result[#])', smartline.escape(data.text))
|
||||||
|
local s2 = string.format('local payload = {row = %s, str = text}', data.row)
|
||||||
|
local s3 = string.format('tubelib.send_message("%s", "%s", nil, "row", payload)', data.number, environ.owner)
|
||||||
|
return s1.."\n\t"..s2.."\n\t"..s3
|
||||||
|
end,
|
||||||
|
button = function(data, environ)
|
||||||
|
return "display("..(data.number or "???")..")"
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
smartline.icta_register_action("cleardisplay", {
|
||||||
|
title = "Display: Clear screen",
|
||||||
|
formspec = {
|
||||||
|
{
|
||||||
|
type = "numbers",
|
||||||
|
name = "number",
|
||||||
|
label = "Display number",
|
||||||
|
default = "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
code = function(data, environ)
|
||||||
|
return 'tubelib.send_message("'..data.number..'", "'..environ.owner..'", nil, "clear", nil)'
|
||||||
|
end,
|
||||||
|
button = function(data, environ)
|
||||||
|
return "clear("..(data.number or "???")..")"
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
smartline.icta_register_action("chat", {
|
||||||
|
title = "chat send",
|
||||||
|
formspec = {
|
||||||
|
{
|
||||||
|
type = "ascii",
|
||||||
|
name = "text",
|
||||||
|
label = "send the message",
|
||||||
|
default = "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type = "label",
|
||||||
|
name = "lbl",
|
||||||
|
label = "Hint: The chat message is send to the\nController owner, only.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
code = function(data, environ)
|
||||||
|
return 'minetest.chat_send_player("'..environ.owner..'", "[SmartLine Controller] '..data.text..'")'
|
||||||
|
end,
|
||||||
|
button = function(data, environ)
|
||||||
|
return "chat(...)"
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
function smartline.icta_door_toggle(pos, owner, state)
|
||||||
|
pos = minetest.string_to_pos("("..pos..")")
|
||||||
|
if pos then
|
||||||
|
local door = doors.get(pos)
|
||||||
|
if door then
|
||||||
|
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
|
||||||
|
end
|
||||||
|
|
||||||
|
smartline.icta_register_action("door", {
|
||||||
|
title = "doors open/close",
|
||||||
|
formspec = {
|
||||||
|
{
|
||||||
|
type = "digits",
|
||||||
|
name = "pos",
|
||||||
|
label = "door position like: 123,7,-1200",
|
||||||
|
default = "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type = "textlist",
|
||||||
|
name = "door_state",
|
||||||
|
label = "set",
|
||||||
|
choices = "open,close",
|
||||||
|
default = "open",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type = "label",
|
||||||
|
name = "lbl1",
|
||||||
|
label = "For standard doors like the Steel Doors.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type = "label",
|
||||||
|
name = "lbl2",
|
||||||
|
label = "Hint: Use the Tubelib Programmer to\ndetermine the door position.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
code = function(data, environ)
|
||||||
|
return 'smartline.icta_door_toggle("'..data.pos..'", "'..environ.owner..'", "'..data.door_state..'")'
|
||||||
|
end,
|
||||||
|
button = function(data, environ)
|
||||||
|
return "door("..(data.door_state or "???")..")"
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
function smartline.icta_player_detect(number, name)
|
||||||
|
local state = tubelib.send_request(number, "name", nil)
|
||||||
|
if (name == "*" and state ~= "") or state == name then
|
||||||
|
return state
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
smartline.icta_register_condition("playerdetector", {
|
||||||
|
title = "Player Detector: name request",
|
||||||
|
formspec = {
|
||||||
|
{
|
||||||
|
type = "digits",
|
||||||
|
name = "number",
|
||||||
|
label = "name from player detector with number",
|
||||||
|
default = "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type = "ascii",
|
||||||
|
name = "name",
|
||||||
|
label = "is",
|
||||||
|
default = "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type = "label",
|
||||||
|
name = "lbl",
|
||||||
|
label = "Hint: Read and check the name\nfrom a Player Detector.\n Use a '*' character for all player names.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
code = function(data, environ)
|
||||||
|
return 'smartline.icta_player_detect("'..data.number..'", "'..data.name..'")', "~= nil"
|
||||||
|
end,
|
||||||
|
button = function(data, environ)
|
||||||
|
return "detector()"
|
||||||
|
end,
|
||||||
|
})
|
76
smartline/icta/condition.lua
Normal file
76
smartline/icta/condition.lua
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
ICTA Controller
|
||||||
|
===============
|
||||||
|
|
||||||
|
Part of the SmartLine mod
|
||||||
|
|
||||||
|
Copyright (C) 2018 Joachim Stolberg
|
||||||
|
|
||||||
|
LGPLv2.1+
|
||||||
|
See LICENSE.txt for more information
|
||||||
|
|
||||||
|
condition.lua
|
||||||
|
|
||||||
|
]]--
|
||||||
|
|
||||||
|
local sl = smartline
|
||||||
|
|
||||||
|
-- tables with all data from condition registrations
|
||||||
|
local kvRegisteredCond = {}
|
||||||
|
|
||||||
|
-- list of keys for conditions
|
||||||
|
local aCondTypes = {}
|
||||||
|
|
||||||
|
-- list of titles for conditions
|
||||||
|
local aCondTitles = {}
|
||||||
|
|
||||||
|
--
|
||||||
|
-- API functions for condition registrations
|
||||||
|
--
|
||||||
|
function sl.icta_register_condition(key, tData)
|
||||||
|
table.insert(aCondTypes, key)
|
||||||
|
table.insert(aCondTitles, tData.title)
|
||||||
|
if kvRegisteredCond[key] ~= nil then
|
||||||
|
print("[SmartLine] Condition registration error "..key)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
kvRegisteredCond[key] = tData
|
||||||
|
for _,item in ipairs(tData.formspec) do
|
||||||
|
if item.type == "textlist" then
|
||||||
|
item.tChoices = string.split(item.choices, ",")
|
||||||
|
item.num_choices = #item.tChoices
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- return formspec string
|
||||||
|
function sl.cond_formspec(row, kvSelect)
|
||||||
|
return sl.submenu_generate_formspec(
|
||||||
|
row, "cond", "Condition type", aCondTypes, aCondTitles, kvRegisteredCond, kvSelect)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- evaluate the row condition input
|
||||||
|
-- and return new data
|
||||||
|
function sl.cond_eval_input(kvSelect, fields)
|
||||||
|
kvSelect = sl.submenu_eval_input(kvRegisteredCond, aCondTypes, aCondTitles, kvSelect, fields)
|
||||||
|
return kvSelect
|
||||||
|
end
|
||||||
|
|
||||||
|
-- return the Lua code
|
||||||
|
function sl.code_condition(kvSelect, environ)
|
||||||
|
if kvSelect and kvRegisteredCond[kvSelect.choice] then
|
||||||
|
if smartline.submenu_verify(kvRegisteredCond, kvSelect) then
|
||||||
|
return kvRegisteredCond[kvSelect.choice].code(kvSelect, environ)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nil, nil
|
||||||
|
end
|
||||||
|
|
||||||
|
sl.icta_register_condition("default", {
|
||||||
|
title = "",
|
||||||
|
formspec = {},
|
||||||
|
code = function(data, environ) return false, false end,
|
||||||
|
button = function(data, environ) return "..." end,
|
||||||
|
})
|
||||||
|
|
463
smartline/icta/controller.lua
Normal file
463
smartline/icta/controller.lua
Normal file
@ -0,0 +1,463 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
ICTA Controller
|
||||||
|
===============
|
||||||
|
|
||||||
|
Part of the SmartLine mod
|
||||||
|
|
||||||
|
Copyright (C) 2018 Joachim Stolberg
|
||||||
|
|
||||||
|
LGPLv2.1+
|
||||||
|
See LICENSE.txt for more information
|
||||||
|
|
||||||
|
controller.lua
|
||||||
|
|
||||||
|
]]--
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Helper functions
|
||||||
|
--
|
||||||
|
local function gen_table(size, val)
|
||||||
|
local tbl = {}
|
||||||
|
for idx = 1,size do
|
||||||
|
if type(val) == "table" then
|
||||||
|
tbl[idx] = table.copy(val)
|
||||||
|
else
|
||||||
|
tbl[idx] = val
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return tbl
|
||||||
|
end
|
||||||
|
|
||||||
|
local function integer(s, min, max)
|
||||||
|
if s and s ~= "" and s:find("^%d+$") then
|
||||||
|
local num = tonumber(s)
|
||||||
|
if num < min then num = min end
|
||||||
|
if num > max then num = max end
|
||||||
|
return num
|
||||||
|
end
|
||||||
|
return min
|
||||||
|
end
|
||||||
|
|
||||||
|
local sOUTPUT = "Edit commands"
|
||||||
|
local Cache = {}
|
||||||
|
local FS_DATA = gen_table(smartline.NUM_RULES, {})
|
||||||
|
|
||||||
|
|
||||||
|
local function output(pos, text)
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
text = meta:get_string("output") .. "\n" .. (text or "")
|
||||||
|
text = text:sub(-500,-1)
|
||||||
|
meta:set_string("output", text)
|
||||||
|
meta:set_string("formspec", smartline.formspecOutput(meta))
|
||||||
|
end
|
||||||
|
|
||||||
|
----------------- template -------------------------------
|
||||||
|
-- -- Rule 1
|
||||||
|
-- if env.blocked[1] == false and env.ticks % <cycle> == 0 then
|
||||||
|
-- env.result[1] = <check condition>
|
||||||
|
-- env.blocked[1] = env.result[1] <expected result>
|
||||||
|
-- if env.blocked[1] then
|
||||||
|
-- env.timer[1] = env.ticks + <after>
|
||||||
|
-- end
|
||||||
|
-- env.conditions[1] = env.blocked[1]
|
||||||
|
-- else
|
||||||
|
-- env.conditions[1] = false
|
||||||
|
-- end
|
||||||
|
-- if env.blocked[1] and env.timer[1] == env.ticks then
|
||||||
|
-- <action>
|
||||||
|
-- env.blocked[1] = false
|
||||||
|
-- end
|
||||||
|
|
||||||
|
-- cyclic execution
|
||||||
|
local TemplCyc = [[
|
||||||
|
-- Rule #
|
||||||
|
if env.blocked[#] == false and env.ticks %% %s == 0 then
|
||||||
|
env.result[#] = %s
|
||||||
|
env.blocked[#] = env.result[#] %s
|
||||||
|
if env.blocked[#] then
|
||||||
|
env.timer[#] = env.ticks + %s
|
||||||
|
end
|
||||||
|
env.condition[#] = env.blocked[#]
|
||||||
|
else
|
||||||
|
env.condition[#] = false
|
||||||
|
end
|
||||||
|
if env.blocked[#] and env.timer[#] == env.ticks then
|
||||||
|
%s
|
||||||
|
env.blocked[#] = false
|
||||||
|
end
|
||||||
|
]]
|
||||||
|
|
||||||
|
-- event based execution
|
||||||
|
local TemplEvt = [[
|
||||||
|
-- Rule #
|
||||||
|
if env.blocked[#] == false and env.event then
|
||||||
|
env.result[#] = %s
|
||||||
|
env.blocked[#] = env.result[#] %s
|
||||||
|
if env.blocked[#] then
|
||||||
|
env.timer[#] = env.ticks + %s
|
||||||
|
end
|
||||||
|
env.condition[#] = env.blocked[#]
|
||||||
|
else
|
||||||
|
env.condition[#] = false
|
||||||
|
end
|
||||||
|
if env.blocked[#] and env.timer[#] == env.ticks then
|
||||||
|
%s
|
||||||
|
env.blocked[#] = false
|
||||||
|
end
|
||||||
|
]]
|
||||||
|
|
||||||
|
-- generate the Lua code from the NUM_RULES rules
|
||||||
|
local function generate(pos, meta, environ)
|
||||||
|
local fs_data = minetest.deserialize(meta:get_string("fs_data")) or FS_DATA
|
||||||
|
-- chunks are compiled as vararg functions. Parameters are available via: local a, b, c = ...
|
||||||
|
local tbl = {"local env, output = ...\n"}
|
||||||
|
for idx = 1,smartline.NUM_RULES do
|
||||||
|
local cycle = integer(fs_data[idx].cycle, 0, 1000)
|
||||||
|
local cond, result = smartline.code_condition(fs_data[idx].cond, environ)
|
||||||
|
local after = integer(fs_data[idx].after, 0, 1000)
|
||||||
|
local actn = smartline.code_action(fs_data[idx].actn, environ)
|
||||||
|
-- valid rule?
|
||||||
|
if cycle and cond and after and actn then
|
||||||
|
-- add rule number
|
||||||
|
local s
|
||||||
|
if cycle == 0 then -- event?
|
||||||
|
s = string.format(TemplEvt, cond, result, after, actn)
|
||||||
|
else -- cyclic
|
||||||
|
s = string.format(TemplCyc, cycle, cond, result, after, actn)
|
||||||
|
end
|
||||||
|
-- add to list of rules
|
||||||
|
tbl[#tbl+1] = s:gsub("#", idx)
|
||||||
|
elseif cond ~= nil and actn == nil then
|
||||||
|
output(pos, "Error in action in rule "..idx)
|
||||||
|
elseif cond == nil and actn ~= nil then
|
||||||
|
output(pos, "Error in condition in rule "..idx)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return table.concat(tbl)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function runtime_environ(pos)
|
||||||
|
return {
|
||||||
|
ticks = 0,
|
||||||
|
pos = pos,
|
||||||
|
timer = gen_table(8, 0),
|
||||||
|
blocked = gen_table(8, false),
|
||||||
|
result = gen_table(8, false),
|
||||||
|
condition = gen_table(8, false),
|
||||||
|
input = {}, -- node number is key
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local function compile(pos, meta, number)
|
||||||
|
local gen_environ = {
|
||||||
|
meta = meta,
|
||||||
|
pos = pos,
|
||||||
|
number = number,
|
||||||
|
owner = meta:get_string("owner"),
|
||||||
|
}
|
||||||
|
local text = generate(pos, meta, gen_environ)
|
||||||
|
if text then
|
||||||
|
local code, err = loadstring(text)
|
||||||
|
if code then
|
||||||
|
Cache[number] = {
|
||||||
|
code = code,
|
||||||
|
env = runtime_environ(pos),
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
output(pos, err)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local function execute(pos, number, event)
|
||||||
|
local code = Cache[number].code
|
||||||
|
local env = Cache[number].env
|
||||||
|
if event then
|
||||||
|
env.event = true
|
||||||
|
else
|
||||||
|
env.event = false
|
||||||
|
env.ticks = env.ticks + 1
|
||||||
|
end
|
||||||
|
local res, err = pcall(code, env, output)
|
||||||
|
if not res then
|
||||||
|
output(pos, err)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function battery(pos)
|
||||||
|
local battery_pos = minetest.find_node_near(pos, 1, {"smartline:battery", "sl_controller:battery"})
|
||||||
|
if battery_pos then
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
meta:set_string("battery", minetest.pos_to_string(battery_pos))
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local function start_controller(pos, meta)
|
||||||
|
local number = meta:get_string("number")
|
||||||
|
if not battery(pos) then
|
||||||
|
meta:set_string("formspec", smartline.formspecError(meta))
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
meta:set_string("output", "<press update>")
|
||||||
|
meta:set_int("cpu", 0)
|
||||||
|
|
||||||
|
if compile(pos, meta, number) then
|
||||||
|
meta:set_int("state", tubelib.RUNNING)
|
||||||
|
minetest.get_node_timer(pos):start(1)
|
||||||
|
meta:set_string("formspec", smartline.formspecOutput(meta))
|
||||||
|
meta:set_string("infotext", "Controller "..number..": running")
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local function stop_controller(pos, meta)
|
||||||
|
local number = meta:get_string("number")
|
||||||
|
meta:set_int("state", tubelib.STOPPED)
|
||||||
|
minetest.get_node_timer(pos):stop()
|
||||||
|
meta:set_string("infotext", "Controller "..number..": stopped")
|
||||||
|
local fs_data = minetest.deserialize(meta:get_string("fs_data")) or FS_DATA
|
||||||
|
meta:set_string("formspec", smartline.formspecRules(meta, fs_data, sOUTPUT))
|
||||||
|
end
|
||||||
|
|
||||||
|
local function no_battery(pos)
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
local number = meta:get_string("number")
|
||||||
|
meta:set_int("state", tubelib.STOPPED)
|
||||||
|
minetest.get_node_timer(pos):stop()
|
||||||
|
meta:set_string("infotext", "Controller "..number..": No battery")
|
||||||
|
meta:set_string("formspec", smartline.formspecError(meta))
|
||||||
|
end
|
||||||
|
|
||||||
|
local function update_battery(meta, cpu)
|
||||||
|
local pos = minetest.string_to_pos(meta:get_string("battery"))
|
||||||
|
if pos then
|
||||||
|
meta = minetest.get_meta(pos)
|
||||||
|
local content = meta:get_int("content") - cpu
|
||||||
|
if content <= 0 then
|
||||||
|
meta:set_int("content", 0)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
meta:set_int("content", content)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function on_timer(pos, elapsed)
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
local t = minetest.get_us_time()
|
||||||
|
local number = meta:get_string("number")
|
||||||
|
if Cache[number] or compile(pos, meta, number) then
|
||||||
|
local res = execute(pos, number, elapsed == -1)
|
||||||
|
if res then
|
||||||
|
t = minetest.get_us_time() - t
|
||||||
|
if not update_battery(meta, t) then
|
||||||
|
no_battery(pos)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
--print("on_timer", t)
|
||||||
|
return res
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local function on_receive_fields(pos, formname, fields, player)
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
local owner = meta:get_string("owner")
|
||||||
|
if not player or not player:is_player() then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local readonly = player:get_player_name() ~= owner
|
||||||
|
|
||||||
|
--print("fields", dump(fields))
|
||||||
|
if fields.quit then -- cancel button
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if fields.notes then -- notes tab?
|
||||||
|
meta:set_string("notes", fields.notes)
|
||||||
|
end
|
||||||
|
if fields.go then
|
||||||
|
if not readonly then
|
||||||
|
local fs_data = minetest.deserialize(meta:get_string("fs_data")) or FS_DATA
|
||||||
|
local output = smartline.edit_command(fs_data, fields.cmnd)
|
||||||
|
stop_controller(pos, meta)
|
||||||
|
meta:set_string("formspec", smartline.formspecRules(meta, fs_data, output))
|
||||||
|
meta:set_string("fs_data", minetest.serialize(fs_data))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if fields._type_ == "main" then
|
||||||
|
if not readonly then
|
||||||
|
smartline.store_main_form_data(meta, fields)
|
||||||
|
end
|
||||||
|
local key = smartline.main_form_button_pressed(fields)
|
||||||
|
if key then
|
||||||
|
-- store data before going into sub-menu
|
||||||
|
meta:set_string("fs_old", meta:get_string("fs_data"))
|
||||||
|
meta:set_string("formspec", smartline.formspecSubMenu(meta, key))
|
||||||
|
end
|
||||||
|
elseif fields._col_ == "cond" then
|
||||||
|
smartline.cond_formspec_update(meta, fields)
|
||||||
|
elseif fields._col_ == "actn" then
|
||||||
|
smartline.actn_formspec_update(meta, fields)
|
||||||
|
end
|
||||||
|
if fields._exit_ == "ok" then -- exit from sub-menu?
|
||||||
|
if fields._button_ then
|
||||||
|
smartline.formspec_button_update(meta, fields)
|
||||||
|
end
|
||||||
|
-- simulate tab selection
|
||||||
|
fields.tab = "1"
|
||||||
|
elseif fields._cancel_ == "cancel" then -- abort from sub-menu?
|
||||||
|
-- restore old data
|
||||||
|
meta:set_string("fs_data", meta:get_string("fs_old"))
|
||||||
|
-- simulate tab selection
|
||||||
|
fields.tab = "1"
|
||||||
|
elseif fields.save == "Save" then -- abort from sub-menu?
|
||||||
|
-- store as old data
|
||||||
|
meta:set_string("fs_old", meta:get_string("fs_data"))
|
||||||
|
-- simulate tab selection
|
||||||
|
fields.tab = "1"
|
||||||
|
elseif fields.sb_help then
|
||||||
|
local evt = minetest.explode_scrollbar_event(fields.sb_help)
|
||||||
|
meta:set_string("formspec", smartline.formspecHelp(evt.value))
|
||||||
|
end
|
||||||
|
if fields.update then
|
||||||
|
meta:set_string("formspec", smartline.formspecOutput(meta))
|
||||||
|
elseif fields.clear then
|
||||||
|
meta:set_string("output", "<press update>")
|
||||||
|
meta:set_string("formspec", smartline.formspecOutput(meta))
|
||||||
|
elseif fields.tab == "1" then
|
||||||
|
local fs_data = minetest.deserialize(meta:get_string("fs_data")) or FS_DATA
|
||||||
|
meta:set_string("formspec", smartline.formspecRules(meta, fs_data, sOUTPUT))
|
||||||
|
elseif fields.tab == "2" then
|
||||||
|
meta:set_string("formspec", smartline.formspecOutput(meta))
|
||||||
|
elseif fields.tab == "3" then
|
||||||
|
meta:set_string("formspec", smartline.formspecNotes(meta))
|
||||||
|
elseif fields.tab == "4" then
|
||||||
|
meta:set_string("formspec", smartline.formspecHelp(1))
|
||||||
|
elseif fields.start == "Start" then
|
||||||
|
local environ = {
|
||||||
|
meta = meta,
|
||||||
|
pos = pos,
|
||||||
|
number = meta:get_string("number"),
|
||||||
|
owner = meta:get_string("owner"),
|
||||||
|
}
|
||||||
|
--print("CODE:", generate(pos, meta, environ))
|
||||||
|
start_controller(pos, meta)
|
||||||
|
minetest.log("action", player:get_player_name() ..
|
||||||
|
" starts the smartline_controller2 at ".. minetest.pos_to_string(pos))
|
||||||
|
elseif fields.stop == "Stop" then
|
||||||
|
stop_controller(pos, meta)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_node("smartline:controller2", {
|
||||||
|
description = "SmartLine Controller",
|
||||||
|
inventory_image = "smartline_controller_inventory.png",
|
||||||
|
wield_image = "smartline_controller_inventory.png",
|
||||||
|
stack_max = 1,
|
||||||
|
tiles = {
|
||||||
|
-- up, down, right, left, back, front
|
||||||
|
"smartline.png",
|
||||||
|
"smartline.png",
|
||||||
|
"smartline.png",
|
||||||
|
"smartline.png",
|
||||||
|
"smartline.png",
|
||||||
|
"smartline.png^smartline_controller.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 = minetest.get_meta(pos)
|
||||||
|
local number = tubelib.add_node(pos, "smartline:controller2")
|
||||||
|
local fs_data = FS_DATA
|
||||||
|
meta:set_string("fs_data", minetest.serialize(fs_data))
|
||||||
|
meta:set_string("owner", placer:get_player_name())
|
||||||
|
meta:set_string("number", number)
|
||||||
|
meta:set_int("state", tubelib.STOPPED)
|
||||||
|
meta:set_string("formspec", smartline.formspecRules(meta, fs_data, sOUTPUT))
|
||||||
|
--meta:set_string("formspec", smartline.cond_formspec(1, 1, nil))
|
||||||
|
meta:set_string("infotext", "SmartLine Controller "..number..": stopped")
|
||||||
|
end,
|
||||||
|
|
||||||
|
on_receive_fields = on_receive_fields,
|
||||||
|
|
||||||
|
on_dig = function(pos, node, puncher, pointed_thing)
|
||||||
|
if minetest.is_protected(pos, puncher:get_player_name()) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.node_dig(pos, node, puncher, pointed_thing)
|
||||||
|
tubelib.remove_node(pos)
|
||||||
|
end,
|
||||||
|
|
||||||
|
on_timer = on_timer,
|
||||||
|
|
||||||
|
paramtype = "light",
|
||||||
|
sunlight_propagates = true,
|
||||||
|
paramtype2 = "facedir",
|
||||||
|
groups = {choppy=1, cracky=1, crumbly=1},
|
||||||
|
is_ground_content = false,
|
||||||
|
sounds = default.node_sound_stone_defaults(),
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
--minetest.register_craft({
|
||||||
|
-- output = "smartline:controller2",
|
||||||
|
-- recipe = {
|
||||||
|
-- {"", "default:mese_crystal", ""},
|
||||||
|
-- {"dye:blue", "default:copper_ingot", "tubelib:wlanchip"},
|
||||||
|
-- {"", "default:mese_crystal", ""},
|
||||||
|
-- },
|
||||||
|
--})
|
||||||
|
|
||||||
|
-- write inputs from remote nodes
|
||||||
|
local function set_input(pos, own_number, rmt_number, val)
|
||||||
|
if rmt_number then
|
||||||
|
if Cache[own_number] and Cache[own_number].env.input then
|
||||||
|
Cache[own_number].env.input[rmt_number] = val
|
||||||
|
-- only two events per second
|
||||||
|
local t = minetest.get_us_time()
|
||||||
|
if not Cache[own_number].last_event or Cache[own_number].last_event < t then
|
||||||
|
minetest.after(0.01, on_timer, pos, -1)
|
||||||
|
Cache[own_number].last_event = t + 500000 -- add 500 ms
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
tubelib.register_node("smartline:controller2", {}, {
|
||||||
|
on_recv_message = function(pos, topic, payload)
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
local number = meta:get_string("number")
|
||||||
|
|
||||||
|
if topic == "on" then
|
||||||
|
set_input(pos, number, payload, topic)
|
||||||
|
elseif topic == "off" then
|
||||||
|
set_input(pos, number, payload, topic)
|
||||||
|
elseif topic == "state" then
|
||||||
|
local state = meta:get_int("state")
|
||||||
|
return tubelib.statestring(state)
|
||||||
|
else
|
||||||
|
return "unsupported"
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
40
smartline/icta/edit.lua
Normal file
40
smartline/icta/edit.lua
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
ICTA Controller
|
||||||
|
===============
|
||||||
|
|
||||||
|
Copyright (C) 2018 Joachim Stolberg
|
||||||
|
|
||||||
|
LGPLv2.1+
|
||||||
|
See LICENSE.txt for more information
|
||||||
|
|
||||||
|
edit.lua
|
||||||
|
|
||||||
|
]]--
|
||||||
|
|
||||||
|
function smartline.edit_command(fs_data, text)
|
||||||
|
local cmnd, pos1, pos2 = text:match('^(%S)%s(%d+)%s(%d+)$')
|
||||||
|
if pos2 == nil then
|
||||||
|
cmnd, pos1 = text:match('^(%S)%s(%d+)$')
|
||||||
|
end
|
||||||
|
if cmnd and pos1 and pos2 then
|
||||||
|
pos1 = math.max(1, math.min(pos1, smartline.NUM_RULES))
|
||||||
|
pos2 = math.max(1, math.min(pos2, smartline.NUM_RULES))
|
||||||
|
|
||||||
|
if cmnd == "x" then
|
||||||
|
local temp = fs_data[pos1]
|
||||||
|
fs_data[pos1] = fs_data[pos2]
|
||||||
|
fs_data[pos2] = temp
|
||||||
|
return "rows "..pos1.." and "..pos2.." exchanged"
|
||||||
|
end
|
||||||
|
if cmnd == "c" then
|
||||||
|
fs_data[pos2] = table.copy(fs_data[pos1])
|
||||||
|
return "row "..pos1.." copied to "..pos2
|
||||||
|
end
|
||||||
|
elseif cmnd == "d" and pos1 then
|
||||||
|
pos1 = math.max(1, math.min(pos1, smartline.NUM_RULES))
|
||||||
|
fs_data[pos1] = {}
|
||||||
|
return "row "..pos1.." deleted"
|
||||||
|
end
|
||||||
|
return "Invalid command '"..text.."'"
|
||||||
|
end
|
360
smartline/icta/formspec.lua
Normal file
360
smartline/icta/formspec.lua
Normal file
@ -0,0 +1,360 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
SmartLine
|
||||||
|
=========
|
||||||
|
|
||||||
|
Part of the SmartLine mod
|
||||||
|
|
||||||
|
Copyright (C) 2018 Joachim Stolberg
|
||||||
|
|
||||||
|
LGPLv2.1+
|
||||||
|
See LICENSE.txt for more information
|
||||||
|
|
||||||
|
formspec.lua:
|
||||||
|
|
||||||
|
controller formspecs
|
||||||
|
]]--
|
||||||
|
|
||||||
|
smartline.NUM_RULES = 8
|
||||||
|
|
||||||
|
local SIZE = "size[13,8]"
|
||||||
|
|
||||||
|
local sHELP = [[SmartLine Controller Help
|
||||||
|
|
||||||
|
Control other nodes by means of rules like:
|
||||||
|
IF <condition> THEN <action>
|
||||||
|
|
||||||
|
These rules allow to execute actions based on conditions.
|
||||||
|
Examples for conditions are:
|
||||||
|
- the Player Detector detects a player
|
||||||
|
- a button is pressed
|
||||||
|
- a node state is fault, blocked, standby,...
|
||||||
|
|
||||||
|
Actions are:
|
||||||
|
- switch on/off tubelib nodes, like lamps, machines
|
||||||
|
- send chat messages to the owner
|
||||||
|
- output a text message to the display
|
||||||
|
|
||||||
|
The controller executes all rules cyclically.
|
||||||
|
The cycle time for each rule is configurable
|
||||||
|
(1..1000 sec).
|
||||||
|
0 means, the rule will only be called, when
|
||||||
|
the controller received a command from
|
||||||
|
another node, like buttons.
|
||||||
|
|
||||||
|
Actions can be deleyed. Therefore, the
|
||||||
|
after value can be set (0..1000 sec).
|
||||||
|
|
||||||
|
Edit command examples:
|
||||||
|
- 'x 1 8' exchange rows 1 with row 8
|
||||||
|
- 'c 1 2' copy row 1 to 2
|
||||||
|
- 'd 3' delete row 3
|
||||||
|
|
||||||
|
The 'outp' tab is for debugging outputs via 'print'
|
||||||
|
The 'notes' tab for your notes.
|
||||||
|
|
||||||
|
The controller needs battery power to work.
|
||||||
|
The battery pack has to be placed near the
|
||||||
|
controller (1 node distance).
|
||||||
|
The needed battery power is directly dependent
|
||||||
|
on the CPU time the controller consumes.
|
||||||
|
|
||||||
|
For more information, see: goo.gl/fF5ap6
|
||||||
|
]]
|
||||||
|
|
||||||
|
-- to simplify the search for a pressed main form button (condition/action)
|
||||||
|
local lButtonKeys = {}
|
||||||
|
|
||||||
|
for idx = 1,smartline.NUM_RULES do
|
||||||
|
lButtonKeys[#lButtonKeys+1] = "cond"..idx
|
||||||
|
lButtonKeys[#lButtonKeys+1] = "actn"..idx
|
||||||
|
end
|
||||||
|
|
||||||
|
local function buttons(s)
|
||||||
|
return "button_exit[7.4,7.5;1.8,1;cancel;Cancel]"..
|
||||||
|
"button[9.3,7.5;1.8,1;save;Save]"..
|
||||||
|
"button[11.2,7.5;1.8,1;"..s.."]"
|
||||||
|
end
|
||||||
|
|
||||||
|
function smartline.formspecError(meta)
|
||||||
|
local running = meta:get_int("state") == tubelib.RUNNING
|
||||||
|
local cmnd = running and "stop;Stop" or "start;Start"
|
||||||
|
local init = meta:get_string("init")
|
||||||
|
init = minetest.formspec_escape(init)
|
||||||
|
return "size[4,3]"..
|
||||||
|
default.gui_bg..
|
||||||
|
default.gui_bg_img..
|
||||||
|
default.gui_slots..
|
||||||
|
"label[0,0;No Battery?]"..
|
||||||
|
"button[1,2;1.8,1;start;Start]"
|
||||||
|
end
|
||||||
|
|
||||||
|
local function button(data)
|
||||||
|
if data then
|
||||||
|
return data.button
|
||||||
|
else
|
||||||
|
return "..."
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function formspec_rules(fs_data)
|
||||||
|
local tbl = {"field[0,0;0,0;_type_;;main]"..
|
||||||
|
"label[0.8,0;Cycle/s:]label[2.8,0;IF cond:]label[7,0;THEN action:]label[11.4,0;after/s:]"}
|
||||||
|
|
||||||
|
for idx = 1,smartline.NUM_RULES do
|
||||||
|
local ypos = idx * 0.75 - 0.4
|
||||||
|
tbl[#tbl+1] = "label[0,"..(0.2+ypos)..";"..idx.."]"
|
||||||
|
tbl[#tbl+1] = "field[0.9,"..(0.3+ypos)..";1.8,1;cycle"..idx..";;"..(fs_data[idx].cycle or "").."]"
|
||||||
|
tbl[#tbl+1] = "button[2.5,"..ypos..";4.3,1;cond"..idx..";"..button(fs_data[idx].cond).."]"
|
||||||
|
tbl[#tbl+1] = "button[6.8,"..ypos..";4.3,1;actn"..idx..";"..button(fs_data[idx].actn).."]"
|
||||||
|
tbl[#tbl+1] = "field[11.4,"..(0.3+ypos)..";1.8,1;after"..idx..";;"..(fs_data[idx].after or "").."]"
|
||||||
|
end
|
||||||
|
return table.concat(tbl)
|
||||||
|
end
|
||||||
|
|
||||||
|
function smartline.store_main_form_data(meta, fields)
|
||||||
|
local fs_data = minetest.deserialize(meta:get_string("fs_data"))
|
||||||
|
for idx = 1,smartline.NUM_RULES do
|
||||||
|
fs_data[idx].cycle = fields["cycle"..idx] or ""
|
||||||
|
fs_data[idx].after = fields["after"..idx] or "0"
|
||||||
|
end
|
||||||
|
meta:set_string("fs_data", minetest.serialize(fs_data))
|
||||||
|
end
|
||||||
|
|
||||||
|
function smartline.main_form_button_pressed(fields)
|
||||||
|
for _,key in ipairs(lButtonKeys) do
|
||||||
|
if fields[key] then
|
||||||
|
return key
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function smartline.formspecSubMenu(meta, key)
|
||||||
|
local fs_data = minetest.deserialize(meta:get_string("fs_data"))
|
||||||
|
if key:sub(1,4) == "cond" then
|
||||||
|
local row = tonumber(key:sub(5,5))
|
||||||
|
return smartline.cond_formspec(row, fs_data[row].cond)
|
||||||
|
else
|
||||||
|
local row = tonumber(key:sub(5,5))
|
||||||
|
return smartline.actn_formspec(row, fs_data[row].actn)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function smartline.formspec_button_update(meta, fields)
|
||||||
|
local fs_data = minetest.deserialize(meta:get_string("fs_data"))
|
||||||
|
local row = tonumber(fields._row_ or 1)
|
||||||
|
print("row", row)
|
||||||
|
if fields._col_ == "cond" then
|
||||||
|
fs_data[row].cond = smartline.cond_eval_input(fs_data[row].cond, fields)
|
||||||
|
elseif fields._col_ == "actn" then
|
||||||
|
fs_data[row].actn = smartline.actn_eval_input(fs_data[row].actn, fields)
|
||||||
|
end
|
||||||
|
meta:set_string("fs_data", minetest.serialize(fs_data))
|
||||||
|
end
|
||||||
|
|
||||||
|
function smartline.cond_formspec_update(meta, fields)
|
||||||
|
local fs_data = minetest.deserialize(meta:get_string("fs_data"))
|
||||||
|
local row = tonumber(fields._row_ or 1)
|
||||||
|
fs_data[row].cond = smartline.cond_eval_input(fs_data[row].cond, fields)
|
||||||
|
meta:set_string("formspec", smartline.cond_formspec(row, fs_data[row].cond))
|
||||||
|
meta:set_string("fs_data", minetest.serialize(fs_data))
|
||||||
|
end
|
||||||
|
|
||||||
|
function smartline.actn_formspec_update(meta, fields)
|
||||||
|
local fs_data = minetest.deserialize(meta:get_string("fs_data"))
|
||||||
|
local row = tonumber(fields._row_ or 1)
|
||||||
|
fs_data[row].actn = smartline.actn_eval_input(fs_data[row].actn, fields)
|
||||||
|
meta:set_string("formspec", smartline.actn_formspec(row, fs_data[row].actn))
|
||||||
|
meta:set_string("fs_data", minetest.serialize(fs_data))
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function smartline.formspecRules(meta, fs_data, output)
|
||||||
|
local running = meta:get_int("state") == tubelib.RUNNING
|
||||||
|
local cmnd = running and "stop;Stop" or "start;Start"
|
||||||
|
local init = meta:get_string("init")
|
||||||
|
init = minetest.formspec_escape(init)
|
||||||
|
return SIZE..
|
||||||
|
default.gui_bg..
|
||||||
|
default.gui_bg_img..
|
||||||
|
default.gui_slots..
|
||||||
|
"tabheader[0,0;tab;rules,outp,notes,help;1;;true]"..
|
||||||
|
formspec_rules(fs_data)..
|
||||||
|
"label[0.2,7.0;"..output.."]"..
|
||||||
|
"field[0.3,7.8;4,1;cmnd;;<cmnd>]"..
|
||||||
|
"button[4.0,7.5;1.5,1;go;GO]"..
|
||||||
|
buttons(cmnd)
|
||||||
|
end
|
||||||
|
|
||||||
|
function smartline.formspecOutput(meta)
|
||||||
|
local running = meta:get_int("state") == tubelib.RUNNING
|
||||||
|
local cmnd = running and "stop;Stop" or "start;Start"
|
||||||
|
local output = meta:get_string("output")
|
||||||
|
output = minetest.formspec_escape(output)
|
||||||
|
return SIZE..
|
||||||
|
default.gui_bg..
|
||||||
|
default.gui_bg_img..
|
||||||
|
default.gui_slots..
|
||||||
|
"tabheader[0,0;tab;rules,outp,notes,help;2;;true]"..
|
||||||
|
"textarea[0.3,0.2;13,8.3;output;Output:;"..output.."]"..
|
||||||
|
"button[7.4,7.5;1.8,1;clear;Clear]"..
|
||||||
|
"button[9.3,7.5;1.8,1;update;Update]"..
|
||||||
|
"button[11.2,7.5;1.8,1;"..cmnd.."]"
|
||||||
|
end
|
||||||
|
|
||||||
|
function smartline.formspecNotes(meta)
|
||||||
|
local running = meta:get_int("state") == tubelib.RUNNING
|
||||||
|
local cmnd = running and "stop;Stop" or "start;Start"
|
||||||
|
local notes = meta:get_string("notes")
|
||||||
|
if notes == "" then notes = "<space for your notes>" end
|
||||||
|
notes = minetest.formspec_escape(notes)
|
||||||
|
return SIZE..
|
||||||
|
default.gui_bg..
|
||||||
|
default.gui_bg_img..
|
||||||
|
default.gui_slots..
|
||||||
|
"tabheader[0,0;tab;rules,outp,notes,help;3;;true]"..
|
||||||
|
"textarea[0.3,0.2;13,8.3;notes;Notepad:;"..notes.."]"..
|
||||||
|
buttons(cmnd)
|
||||||
|
end
|
||||||
|
|
||||||
|
function smartline.formspecHelp(offs)
|
||||||
|
return SIZE..
|
||||||
|
default.gui_bg..
|
||||||
|
default.gui_bg_img..
|
||||||
|
default.gui_slots..
|
||||||
|
"tabheader[0,0;tab;rules,outp,notes,help;4;;true]"..
|
||||||
|
"field[0,0;0,0;_type_;;help]"..
|
||||||
|
"label[0,"..(-offs/50)..";"..sHELP.."]"..
|
||||||
|
--"label[0.2,0;test]"..
|
||||||
|
"scrollbar[12,1;0.5,7;vertical;sb_help;"..offs.."]"
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--local function my_on_receive_fields(pos, formname, fields, player)
|
||||||
|
-- local meta = minetest.get_meta(pos)
|
||||||
|
-- local owner = meta:get_string("owner")
|
||||||
|
-- local state = meta:get_int("state")
|
||||||
|
-- if not player or not player:is_player() then
|
||||||
|
-- return
|
||||||
|
-- end
|
||||||
|
-- local fs_data = minetest.deserialize(meta:get_string("fs_data")) or {}
|
||||||
|
-- local output = ""
|
||||||
|
-- local readonly = player:get_player_name() ~= owner
|
||||||
|
|
||||||
|
-- print("fields", dump(fields))
|
||||||
|
|
||||||
|
-- -- FIRST: test if command entered?
|
||||||
|
-- if fields.ok then
|
||||||
|
-- if not readonly then
|
||||||
|
-- output = edit_command(fs_data, fields.cmnd)
|
||||||
|
-- smartline.stop_controller(pos, fs_data)
|
||||||
|
-- meta:set_string("formspec", formspec_main(tubelib.STOPPED, fs_data, output))
|
||||||
|
-- meta:set_string("fs_data", minetest.serialize(fs_data))
|
||||||
|
-- end
|
||||||
|
-- -- SECOND: eval none edit events (events based in __type__)?
|
||||||
|
-- elseif fields.help then
|
||||||
|
-- meta:set_string("formspec", formspec_help(1))
|
||||||
|
---- elseif fields.state then
|
||||||
|
---- meta:set_string("formspec", formspec_state(meta, fs_data))
|
||||||
|
---- elseif fields.update then
|
||||||
|
---- meta:set_string("formspec", formspec_state(meta, fs_data))
|
||||||
|
-- elseif fields._cancel_ then
|
||||||
|
-- fs_data = minetest.deserialize(meta:get_string("fs_old"))
|
||||||
|
-- meta:set_string("formspec", formspec_main(state, fs_data, sOUTPUT))
|
||||||
|
-- elseif fields.close then
|
||||||
|
-- meta:set_string("formspec", formspec_main(state, fs_data, sOUTPUT))
|
||||||
|
---- elseif fields.sb_help then
|
||||||
|
---- local evt = minetest.explode_scrollbar_event(fields.sb_help)
|
||||||
|
---- if evt.type == "CHG" then
|
||||||
|
---- meta:set_string("formspec", formspec_help(evt.value))
|
||||||
|
---- end
|
||||||
|
---- elseif fields.button then
|
||||||
|
---- if not readonly then
|
||||||
|
---- local number = meta:get_string("number")
|
||||||
|
---- local state = meta:get_int("state")
|
||||||
|
---- if state == tubelib.RUNNING then
|
||||||
|
---- smartline.stop_controller(pos, fs_data)
|
||||||
|
---- meta:set_string("formspec", formspec_main(tubelib.STOPPED, fs_data, sOUTPUT))
|
||||||
|
---- else
|
||||||
|
---- formspec2runtime_rule(number, owner, fs_data)
|
||||||
|
---- start_controller(pos, number, fs_data)
|
||||||
|
---- meta:set_string("formspec", formspec_main(tubelib.RUNNING, fs_data, sOUTPUT))
|
||||||
|
---- end
|
||||||
|
---- end
|
||||||
|
---- -- THIRD: evaluate edit events from sub-menus
|
||||||
|
-- elseif fields._col_ == "cond" then
|
||||||
|
-- local row = tonumber(fields._row_ or 1)
|
||||||
|
-- fs_data["cond"..row] = smartline.cond_eval_input(fs_data["cond"..row], fields)
|
||||||
|
-- meta:set_string("formspec", smartline.cond_formspec(row, fs_data["cond"..row]))
|
||||||
|
-- meta:set_string("fs_data", minetest.serialize(fs_data))
|
||||||
|
-- elseif fields._type_ == "main" then
|
||||||
|
-- fs_data = eval_formspec_main(meta, fs_data, fields, readonly)
|
||||||
|
-- meta:set_string("fs_data", minetest.serialize(fs_data))
|
||||||
|
---- elseif fields._type_ == "label" then
|
||||||
|
---- fs_data = eval_formspec_label(meta, fs_data, fields, readonly)
|
||||||
|
---- meta:set_string("fs_data", minetest.serialize(fs_data))
|
||||||
|
---- elseif fields._type_ == "cond" then
|
||||||
|
---- fs_data = eval_formspec_cond(meta, fs_data, fields, readonly)
|
||||||
|
---- meta:set_string("fs_data", minetest.serialize(fs_data))
|
||||||
|
---- elseif fields._type_ == "oprnd" then
|
||||||
|
---- fs_data = eval_formspec_oprnd(meta, fs_data, fields, readonly)
|
||||||
|
---- meta:set_string("fs_data", minetest.serialize(fs_data))
|
||||||
|
---- elseif fields._type_ == "actn" then
|
||||||
|
---- fs_data = eval_formspec_actn(meta, fs_data, fields, readonly)
|
||||||
|
---- meta:set_string("fs_data", minetest.serialize(fs_data))
|
||||||
|
---- elseif fields._type_ == "help" then
|
||||||
|
---- meta:set_string("formspec", formspec_main(state, fs_data, sOUTPUT))
|
||||||
|
---- elseif fields._type_ == "state" then
|
||||||
|
---- meta:set_string("formspec", formspec_main(state, fs_data, sOUTPUT))
|
||||||
|
-- end
|
||||||
|
-- -- FOURTH: back to main menu
|
||||||
|
-- if fields._exit_ then
|
||||||
|
-- meta:set_string("formspec", formspec_main(state, fs_data, sOUTPUT))
|
||||||
|
-- end
|
||||||
|
--end
|
||||||
|
|
||||||
|
--function smartline.on_receive_fields(pos, formname, fields, player)
|
||||||
|
-- local meta = minetest.get_meta(pos)
|
||||||
|
-- local owner = meta:get_string("owner")
|
||||||
|
-- if not player or not player:is_player() then
|
||||||
|
-- return
|
||||||
|
-- end
|
||||||
|
-- local readonly = player:get_player_name() ~= owner
|
||||||
|
|
||||||
|
-- print("fields", dump(fields))
|
||||||
|
|
||||||
|
-- if fields.cancel == nil then
|
||||||
|
-- if fields.rules then
|
||||||
|
-- --meta:set_string("rules", fields.rules)
|
||||||
|
-- meta:set_string("formspec", smartline.formspecRules(meta))
|
||||||
|
-- elseif fields.notes then
|
||||||
|
-- meta:set_string("notes", fields.notes)
|
||||||
|
-- meta:set_string("formspec", formspecNotes(meta))
|
||||||
|
-- end
|
||||||
|
-- end
|
||||||
|
|
||||||
|
-- if fields.update then
|
||||||
|
-- meta:set_string("formspec", formspecOutput(meta))
|
||||||
|
-- elseif fields.clear then
|
||||||
|
-- meta:set_string("output", "<press update>")
|
||||||
|
-- meta:set_string("formspec", formspecOutput(meta))
|
||||||
|
-- elseif fields.tab == "1" then
|
||||||
|
-- meta:set_string("formspec", smartline.formspecRules(meta))
|
||||||
|
-- elseif fields.tab == "2" then
|
||||||
|
-- meta:set_string("formspec", formspecOutput(meta))
|
||||||
|
-- elseif fields.tab == "3" then
|
||||||
|
-- meta:set_string("formspec", formspecNotes(meta))
|
||||||
|
-- elseif fields.tab == "4" then
|
||||||
|
-- meta:set_string("formspec", formspecHelp(1))
|
||||||
|
-- elseif fields.start == "Start" then
|
||||||
|
-- start_controller(pos)
|
||||||
|
-- minetest.log("action", player:get_player_name() ..
|
||||||
|
-- " starts the sl_controller at ".. minetest.pos_to_string(pos))
|
||||||
|
-- elseif fields.stop == "Stop" then
|
||||||
|
-- stop_controller(pos)
|
||||||
|
-- end
|
||||||
|
--end
|
||||||
|
|
||||||
|
|
197
smartline/icta/submenu.lua
Normal file
197
smartline/icta/submenu.lua
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
ICTA Controller
|
||||||
|
===============
|
||||||
|
|
||||||
|
Part of the SmartLine mod
|
||||||
|
|
||||||
|
Copyright (C) 2018 Joachim Stolberg
|
||||||
|
|
||||||
|
LGPLv2.1+
|
||||||
|
See LICENSE.txt for more information
|
||||||
|
|
||||||
|
submenu.lua
|
||||||
|
|
||||||
|
A sub-menu control to generate a formspec sting for conditions and actions
|
||||||
|
]]--
|
||||||
|
|
||||||
|
local sl = smartline
|
||||||
|
|
||||||
|
local function index(list, x)
|
||||||
|
for idx, v in ipairs(list) do
|
||||||
|
if v == x then return idx end
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- generate the choice dependent part of the form
|
||||||
|
local function add_controls_to_table(tbl, kvDefinition, kvSelect)
|
||||||
|
local val = ""
|
||||||
|
local offs = 1.4
|
||||||
|
if kvDefinition[kvSelect.choice] then
|
||||||
|
local lControls = kvDefinition[kvSelect.choice].formspec
|
||||||
|
for idx,elem in ipairs(lControls) do
|
||||||
|
if elem.label and elem.label ~= "" then
|
||||||
|
tbl[#tbl+1] = "label[0,"..offs..";"..elem.label.."]"
|
||||||
|
offs = offs + 0.4
|
||||||
|
end
|
||||||
|
if elem.type == "numbers" or elem.type == "digits" or elem.type == "letters"
|
||||||
|
or elem.type == "ascii" then
|
||||||
|
val = kvSelect[elem.name] or elem.default
|
||||||
|
tbl[#tbl+1] = "field[0.3,"..(offs+0.2)..";8,1;"..elem.name..";;"..val.."]"
|
||||||
|
offs = offs + 1
|
||||||
|
elseif elem.type == "textlist" then
|
||||||
|
local l = elem.choices:split(",")
|
||||||
|
val = index(l, kvSelect[elem.name]) or elem.default
|
||||||
|
tbl[#tbl+1] = "dropdown[0.0,"..(offs)..";8.5,1.4;"..elem.name..";"..elem.choices..";"..val.."]"
|
||||||
|
offs = offs + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return tbl
|
||||||
|
end
|
||||||
|
|
||||||
|
local function default_data(kvDefinition, kvSelect)
|
||||||
|
local lControls = kvDefinition[kvSelect.choice].formspec
|
||||||
|
for idx,elem in ipairs(lControls) do
|
||||||
|
kvSelect[elem.name] = elem.default
|
||||||
|
end
|
||||||
|
kvSelect.button = kvDefinition[kvSelect.choice].button(kvSelect)
|
||||||
|
return kvSelect
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Copy field/formspec data to the table kvSelect
|
||||||
|
-- kvDefinition: submenu formspec definition
|
||||||
|
-- kvSelect: form data
|
||||||
|
-- fields: formspec input
|
||||||
|
local function field_to_kvSelect(kvDefinition, kvSelect, fields)
|
||||||
|
local error = false
|
||||||
|
local lControls = kvDefinition[kvSelect.choice].formspec
|
||||||
|
for idx,elem in ipairs(lControls) do
|
||||||
|
if elem.type == "numbers" then
|
||||||
|
if fields[elem.name] then
|
||||||
|
if fields[elem.name]:find("^[%d ]+$") then
|
||||||
|
kvSelect[elem.name] = fields[elem.name]
|
||||||
|
else
|
||||||
|
kvSelect[elem.name] = elem.default
|
||||||
|
error = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif elem.type == "digits" then -- including positions
|
||||||
|
if fields[elem.name] then
|
||||||
|
if fields[elem.name]:find("^[+%%-,%d]+$") then
|
||||||
|
kvSelect[elem.name] = fields[elem.name]
|
||||||
|
else
|
||||||
|
kvSelect[elem.name] = elem.default
|
||||||
|
error = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif elem.type == "letters" then
|
||||||
|
if fields[elem.name] then
|
||||||
|
if fields[elem.name]:find("^[+-]?%a+$") then
|
||||||
|
kvSelect[elem.name] = fields[elem.name]
|
||||||
|
else
|
||||||
|
kvSelect[elem.name] = elem.default
|
||||||
|
error = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif elem.type == "ascii" then
|
||||||
|
if fields[elem.name] then
|
||||||
|
kvSelect[elem.name] = fields[elem.name]
|
||||||
|
end
|
||||||
|
elseif elem.type == "textlist" then
|
||||||
|
if fields[elem.name] ~= nil then
|
||||||
|
kvSelect[elem.name] = fields[elem.name]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- store user input of button text
|
||||||
|
if fields._button_ then
|
||||||
|
kvSelect._button_ = fields._button_
|
||||||
|
end
|
||||||
|
-- select button text
|
||||||
|
if error then
|
||||||
|
kvSelect.button = "invalid"
|
||||||
|
elseif kvSelect._button_ and kvSelect._button_ ~= "" then
|
||||||
|
kvSelect.button = kvSelect._button_
|
||||||
|
else
|
||||||
|
kvSelect.button = kvDefinition[kvSelect.choice].button(kvSelect)
|
||||||
|
end
|
||||||
|
return kvSelect
|
||||||
|
end
|
||||||
|
|
||||||
|
function smartline.submenu_verify(kvDefinition, kvSelect)
|
||||||
|
local error = false
|
||||||
|
local lControls = kvDefinition[kvSelect.choice].formspec
|
||||||
|
for idx,elem in ipairs(lControls) do
|
||||||
|
if elem.type == "numbers" then
|
||||||
|
if not kvSelect[elem.name]:find("^[%d ]+$") then
|
||||||
|
error = true
|
||||||
|
end
|
||||||
|
elseif elem.type == "digits" then -- including positions
|
||||||
|
if not kvSelect[elem.name]:find("^[+%%-,%d]+$") then
|
||||||
|
error = true
|
||||||
|
end
|
||||||
|
elseif elem.type == "letters" then
|
||||||
|
if not kvSelect[elem.name]:find("^[+-]?%a+$") then
|
||||||
|
error = true
|
||||||
|
end
|
||||||
|
elseif elem.type == "ascii" then
|
||||||
|
if kvSelect[elem.name] == "" or kvSelect[elem.name] == nil then
|
||||||
|
error = true
|
||||||
|
end
|
||||||
|
elseif elem.type == "textlist" then
|
||||||
|
if kvSelect[elem.name] == "" or kvSelect[elem.name] == nil then
|
||||||
|
error = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return (error == false)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- generate a formspec string from the given control definition
|
||||||
|
-- row, col: numbers to identify the control
|
||||||
|
-- title: Title text for the control
|
||||||
|
-- lKeys: list of keywords of selected choices according to fields
|
||||||
|
-- lChoice: list of possible choices for the control
|
||||||
|
-- kvDefinition: definitions of the choice dependent controls
|
||||||
|
-- kvSelect: data of the last selected item {choice, number, value, ...}
|
||||||
|
function smartline.submenu_generate_formspec(row, col, title, lKeys, lChoice, kvDefinition, kvSelect)
|
||||||
|
if kvSelect == nil or next(kvSelect) == nil then
|
||||||
|
kvSelect = {choice = "default"}
|
||||||
|
end
|
||||||
|
local tbl = {"size[8.2,9]"..
|
||||||
|
--default.gui_bg.. TODO
|
||||||
|
--default.gui_bg_img..
|
||||||
|
--default.gui_slots..
|
||||||
|
"field[0,0;0,0;_row_;;"..row.."]"..
|
||||||
|
"field[0,0;0,0;_col_;;"..col.."]"}
|
||||||
|
|
||||||
|
local sChoice = table.concat(lChoice, ",")
|
||||||
|
local idx = index(lKeys, kvSelect.choice) or 1
|
||||||
|
tbl[#tbl+1] = "label[0,0;"..title..":]"
|
||||||
|
tbl[#tbl+1] = "dropdown[0,0.5;8.5,1;choice;"..sChoice..";"..idx.."]"
|
||||||
|
tbl = add_controls_to_table(tbl, kvDefinition, kvSelect)
|
||||||
|
tbl[#tbl+1] = "field[0.2,8.7;4,1;_button_;Button text;"..(kvSelect._button_ or "").."]"
|
||||||
|
tbl[#tbl+1] = "button[4,8.4;2,1;_cancel_;cancel]"
|
||||||
|
tbl[#tbl+1] = "button[6,8.4;2,1;_exit_;ok]"
|
||||||
|
return table.concat(tbl)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- return the selected and configured menu item based on user inputs (fields)
|
||||||
|
function smartline.submenu_eval_input(kvDefinition, lKeys, lChoice, kvSelect, fields)
|
||||||
|
-- determine selected choice
|
||||||
|
if fields.choice then
|
||||||
|
-- load with default values
|
||||||
|
local idx = index(lChoice, fields.choice) or 1
|
||||||
|
kvSelect = {choice = lKeys[idx]}
|
||||||
|
kvSelect = default_data(kvDefinition, kvSelect)
|
||||||
|
kvSelect = field_to_kvSelect(kvDefinition, kvSelect, fields)
|
||||||
|
else
|
||||||
|
-- add real data
|
||||||
|
kvSelect = field_to_kvSelect(kvDefinition, kvSelect, fields)
|
||||||
|
end
|
||||||
|
return kvSelect
|
||||||
|
end
|
||||||
|
|
@ -10,15 +10,29 @@
|
|||||||
|
|
||||||
]]--
|
]]--
|
||||||
|
|
||||||
|
smartline = {}
|
||||||
|
|
||||||
|
local MP = minetest.get_modpath("smartline")
|
||||||
|
|
||||||
if minetest.get_modpath("display_lib") and display_lib ~= nil and
|
if minetest.get_modpath("display_lib") and display_lib ~= nil and
|
||||||
minetest.get_modpath("font_lib") and font_lib ~= nil then
|
minetest.get_modpath("font_lib") and font_lib ~= nil then
|
||||||
dofile(minetest.get_modpath("smartline") .. "/display.lua")
|
dofile(MP.."/display.lua")
|
||||||
end
|
end
|
||||||
dofile(minetest.get_modpath("smartline") .. "/button.lua")
|
dofile(MP.."/button.lua")
|
||||||
dofile(minetest.get_modpath("smartline") .. "/signaltower.lua")
|
dofile(MP.."/signaltower.lua")
|
||||||
dofile(minetest.get_modpath("smartline") .. "/playerdetector.lua")
|
dofile(MP.."/playerdetector.lua")
|
||||||
dofile(minetest.get_modpath("smartline") .. "/sequencer.lua")
|
dofile(MP.."/sequencer.lua")
|
||||||
dofile(minetest.get_modpath("smartline") .. "/timer.lua")
|
dofile(MP.."/timer.lua")
|
||||||
dofile(minetest.get_modpath("smartline") .. "/repeater.lua")
|
dofile(MP.."/repeater.lua")
|
||||||
dofile(minetest.get_modpath("smartline") .. "/controller.lua")
|
dofile(MP.."/controller.lua")
|
||||||
dofile(minetest.get_modpath("smartline") .. "/commands.lua")
|
dofile(MP.."/commands.lua")
|
||||||
|
-- ICTA Controller
|
||||||
|
dofile(MP.."/icta/submenu.lua")
|
||||||
|
dofile(MP.."/icta/condition.lua")
|
||||||
|
dofile(MP.."/icta/action.lua")
|
||||||
|
dofile(MP.."/icta/formspec.lua")
|
||||||
|
dofile(MP.."/icta/controller.lua")
|
||||||
|
dofile(MP.."/icta/commands.lua")
|
||||||
|
dofile(MP.."/icta/edit.lua")
|
||||||
|
dofile(MP.."/icta/battery.lua")
|
||||||
|
dofile(MP.."/icta/balancer.lua")
|
||||||
|
BIN
smartline/textures/smartline_battery_green.png
Normal file
BIN
smartline/textures/smartline_battery_green.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 322 B |
BIN
smartline/textures/smartline_battery_inventory.png
Normal file
BIN
smartline/textures/smartline_battery_inventory.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 260 B |
BIN
smartline/textures/smartline_battery_red.png
Normal file
BIN
smartline/textures/smartline_battery_red.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 322 B |
@ -1,5 +1,6 @@
|
|||||||
tubelib
|
tubelib
|
||||||
default
|
default
|
||||||
|
bucket
|
||||||
stairs?
|
stairs?
|
||||||
moreores?
|
moreores?
|
||||||
farming?
|
farming?
|
||||||
|
@ -20,4 +20,5 @@ dofile(minetest.get_modpath("tubelib_addons1") .. '/reformer.lua')
|
|||||||
dofile(minetest.get_modpath("tubelib_addons1") .. '/funnel.lua')
|
dofile(minetest.get_modpath("tubelib_addons1") .. '/funnel.lua')
|
||||||
dofile(minetest.get_modpath("tubelib_addons1") .. "/pusher_fast.lua")
|
dofile(minetest.get_modpath("tubelib_addons1") .. "/pusher_fast.lua")
|
||||||
dofile(minetest.get_modpath("tubelib_addons1") .. "/detector.lua")
|
dofile(minetest.get_modpath("tubelib_addons1") .. "/detector.lua")
|
||||||
dofile(minetest.get_modpath("tubelib_addons1") .. '/chest.lua')
|
dofile(minetest.get_modpath("tubelib_addons1") .. '/chest.lua')
|
||||||
|
dofile(minetest.get_modpath("tubelib_addons1") .. '/liquidsampler.lua')
|
308
tubelib_addons1/liquidsampler.lua
Normal file
308
tubelib_addons1/liquidsampler.lua
Normal file
@ -0,0 +1,308 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
Tubelib Addons 1
|
||||||
|
================
|
||||||
|
|
||||||
|
Copyright (C) 2017,2018 Joachim Stolberg
|
||||||
|
|
||||||
|
LGPLv2.1+
|
||||||
|
See LICENSE.txt for more information
|
||||||
|
|
||||||
|
liquidsampler.lua
|
||||||
|
|
||||||
|
]]--
|
||||||
|
|
||||||
|
local CYCLE_TIME = 8
|
||||||
|
|
||||||
|
local function get_pos(pos, facedir, side)
|
||||||
|
local offs = {F=0, R=1, B=2, L=3, D=4, U=5}
|
||||||
|
local dst_pos = table.copy(pos)
|
||||||
|
facedir = (facedir + offs[side]) % 4
|
||||||
|
local dir = minetest.facedir_to_dir(facedir)
|
||||||
|
return vector.add(dst_pos, dir)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function test_liquid(node)
|
||||||
|
local liquiddef = bucket.liquids[node.name]
|
||||||
|
if liquiddef ~= nil and liquiddef.itemname ~= nil and
|
||||||
|
node.name == liquiddef.source then
|
||||||
|
return liquiddef.itemname
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function sample_liquid(pos, meta)
|
||||||
|
local giving_back = test_liquid(minetest.get_node(pos))
|
||||||
|
if giving_back then
|
||||||
|
local inv = meta:get_inventory()
|
||||||
|
if inv:room_for_item("dst", ItemStack(giving_back)) and
|
||||||
|
inv:contains_item("src", ItemStack("bucket:bucket_empty")) then
|
||||||
|
minetest.remove_node(pos)
|
||||||
|
inv:remove_item("src", ItemStack("bucket:bucket_empty"))
|
||||||
|
inv:add_item("dst", ItemStack(giving_back))
|
||||||
|
return true -- success
|
||||||
|
else
|
||||||
|
return nil -- standby
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return false -- fault
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function formspec(meta, state)
|
||||||
|
return "size[9,8.5]"..
|
||||||
|
default.gui_bg..
|
||||||
|
default.gui_bg_img..
|
||||||
|
default.gui_slots..
|
||||||
|
"list[context;src;0,0;1,4;]"..
|
||||||
|
"image[0,0;1,1;bucket.png]"..
|
||||||
|
"image[1,1;1,1;tubelib_gui_arrow.png]"..
|
||||||
|
"image_button[1,3;1,1;".. tubelib.state_button(state) ..";button;]"..
|
||||||
|
"list[context;dst;2,0;7,4;]"..
|
||||||
|
"list[current_player;main;0.5,4.5;8,4;]"..
|
||||||
|
"listring[current_player;main]"..
|
||||||
|
"listring[context;src]" ..
|
||||||
|
"listring[current_player;main]"..
|
||||||
|
"listring[context;dst]" ..
|
||||||
|
"listring[current_player;main]"
|
||||||
|
end
|
||||||
|
|
||||||
|
local function switch_on(pos, node)
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
local number = meta:get_string("number")
|
||||||
|
meta:set_int("running", tubelib.STATE_RUNNING)
|
||||||
|
meta:set_string("infotext", "Liquid Sampler "..number..": running")
|
||||||
|
meta:set_string("formspec", formspec(meta, tubelib.RUNNING))
|
||||||
|
node.name = "tubelib_addons1:liquidsampler_active"
|
||||||
|
minetest.swap_node(pos, node)
|
||||||
|
minetest.get_node_timer(pos):start(CYCLE_TIME)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local function switch_off(pos, node)
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
local number = meta:get_string("number")
|
||||||
|
meta:set_int("running", tubelib.STATE_STOPPED)
|
||||||
|
meta:set_string("infotext", "Liquid Sampler "..number..": stopped")
|
||||||
|
meta:set_string("formspec", formspec(meta, tubelib.STOPPED))
|
||||||
|
node.name = "tubelib_addons1:liquidsampler"
|
||||||
|
minetest.swap_node(pos, node)
|
||||||
|
minetest.get_node_timer(pos):stop()
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local function goto_fault(pos, node)
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
local number = meta:get_string("number")
|
||||||
|
meta:set_int("running", tubelib.STATE_FAULT)
|
||||||
|
meta:set_string("infotext", "Liquid Sampler "..number..": fault")
|
||||||
|
meta:set_string("formspec", formspec(meta, tubelib.FAULT))
|
||||||
|
node.name = "tubelib_addons1:liquidsampler"
|
||||||
|
minetest.swap_node(pos, node)
|
||||||
|
minetest.get_node_timer(pos):start(20)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local function goto_standby(pos, node)
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
local number = meta:get_string("number")
|
||||||
|
meta:set_int("running", tubelib.STATE_STANDBY)
|
||||||
|
meta:set_string("infotext", "Liquid Sampler "..number..": standby")
|
||||||
|
meta:set_string("formspec", formspec(meta, tubelib.STANDBY))
|
||||||
|
node.name = "tubelib_addons1:liquidsampler"
|
||||||
|
minetest.swap_node(pos, node)
|
||||||
|
minetest.get_node_timer(pos):start(20)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local function allow_metadata_inventory_put(pos, listname, index, stack, player)
|
||||||
|
if minetest.is_protected(pos, player:get_player_name()) then
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
return stack:get_count()
|
||||||
|
end
|
||||||
|
|
||||||
|
local function allow_metadata_inventory_take(pos, listname, index, stack, player)
|
||||||
|
if minetest.is_protected(pos, player:get_player_name()) then
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
return stack:get_count()
|
||||||
|
end
|
||||||
|
|
||||||
|
local function allow_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player)
|
||||||
|
if minetest.is_protected(pos, player:get_player_name()) then
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
return count
|
||||||
|
end
|
||||||
|
|
||||||
|
local function on_receive_fields(pos, formname, fields, sender)
|
||||||
|
if minetest.is_protected(pos, sender:get_player_name()) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
local node = minetest.get_node(pos)
|
||||||
|
local running = meta:get_int("running")
|
||||||
|
if fields.button ~= nil then
|
||||||
|
if running == tubelib.STATE_RUNNING then
|
||||||
|
switch_off(pos, node)
|
||||||
|
meta:set_int("running", tubelib.STATE_STOPPED)
|
||||||
|
else
|
||||||
|
meta:set_int("running", tubelib.STATE_RUNNING)
|
||||||
|
switch_on(pos, node)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function keep_running(pos, elapsed)
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
local running = meta:get_int("running")
|
||||||
|
local water_pos = minetest.string_to_pos(meta:get_string("water_pos"))
|
||||||
|
local res = sample_liquid(water_pos, meta)
|
||||||
|
|
||||||
|
if res == nil then
|
||||||
|
local node = minetest.get_node(pos)
|
||||||
|
return goto_standby(pos, node)
|
||||||
|
elseif res == true then
|
||||||
|
if running <= 0 then
|
||||||
|
local node = minetest.get_node(pos)
|
||||||
|
return switch_on(pos, node)
|
||||||
|
end
|
||||||
|
elseif res == false then
|
||||||
|
if running > 0 then
|
||||||
|
local node = minetest.get_node(pos)
|
||||||
|
return goto_fault(pos, node)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
meta:set_int("running", running)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_node("tubelib_addons1:liquidsampler", {
|
||||||
|
description = "Liquid Sampler",
|
||||||
|
tiles = {
|
||||||
|
-- up, down, right, left, back, front
|
||||||
|
'tubelib_front.png',
|
||||||
|
'tubelib_front.png',
|
||||||
|
'tubelib_addons1_liquidsampler.png',
|
||||||
|
'tubelib_addons1_liquidsampler_passive.png',
|
||||||
|
'tubelib_addons1_liquidsampler.png',
|
||||||
|
'tubelib_addons1_liquidsampler.png',
|
||||||
|
},
|
||||||
|
|
||||||
|
on_construct = function(pos)
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
local inv = meta:get_inventory()
|
||||||
|
inv:set_size("src", 4)
|
||||||
|
inv:set_size("dst", 28)
|
||||||
|
end,
|
||||||
|
|
||||||
|
after_place_node = function(pos, placer)
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
meta:set_string("player_name", placer:get_player_name())
|
||||||
|
local number = tubelib.add_node(pos, "tubelib_addons1:liquidsampler")
|
||||||
|
meta:set_string("number", number)
|
||||||
|
local node = minetest.get_node(pos)
|
||||||
|
local water_pos = get_pos(pos, node.param2, "L")
|
||||||
|
meta:set_string("water_pos", minetest.pos_to_string(water_pos))
|
||||||
|
switch_off(pos, node)
|
||||||
|
end,
|
||||||
|
|
||||||
|
on_receive_fields = on_receive_fields,
|
||||||
|
|
||||||
|
after_dig_node = function(pos)
|
||||||
|
tubelib.remove_node(pos)
|
||||||
|
end,
|
||||||
|
|
||||||
|
on_timer = keep_running,
|
||||||
|
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("tubelib_addons1:liquidsampler_active", {
|
||||||
|
description = "Liquid Sampler",
|
||||||
|
tiles = {
|
||||||
|
-- up, down, right, left, back, front
|
||||||
|
'tubelib_front.png',
|
||||||
|
'tubelib_front.png',
|
||||||
|
'tubelib_addons1_liquidsampler.png',
|
||||||
|
{
|
||||||
|
image = "tubelib_addons1_liquidsampler_active.png",
|
||||||
|
backface_culling = false,
|
||||||
|
animation = {
|
||||||
|
type = "vertical_frames",
|
||||||
|
aspect_w = 32,
|
||||||
|
aspect_h = 32,
|
||||||
|
length = 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'tubelib_addons1_liquidsampler.png',
|
||||||
|
'tubelib_addons1_liquidsampler.png',
|
||||||
|
},
|
||||||
|
|
||||||
|
on_receive_fields = on_receive_fields,
|
||||||
|
|
||||||
|
on_timer = keep_running,
|
||||||
|
on_rotate = screwdriver.disallow,
|
||||||
|
|
||||||
|
after_dig_node = function(pos)
|
||||||
|
tubelib.remove_node(pos)
|
||||||
|
end,
|
||||||
|
|
||||||
|
paramtype = "light",
|
||||||
|
sunlight_propagates = true,
|
||||||
|
paramtype2 = "facedir",
|
||||||
|
groups = {crumbly=0, not_in_creative_inventory=1},
|
||||||
|
is_ground_content = false,
|
||||||
|
drop = "tubelib_addons1:liquidsampler",
|
||||||
|
sounds = default.node_sound_wood_defaults(),
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
output = "tubelib_addons1:liquidsampler",
|
||||||
|
recipe = {
|
||||||
|
{"group:wood", "default:steel_ingot", "group:wood"},
|
||||||
|
{"default:mese_crystal", "bucket:bucket_empty", "tubelib:tube1"},
|
||||||
|
{"group:wood", "default:steel_ingot", "group:wood"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
--------------------------------------------------------------- tubelib
|
||||||
|
tubelib.register_node("tubelib_addons1:liquidsampler", {"tubelib_addons1:liquidsampler_active"}, {
|
||||||
|
on_pull_item = function(pos, side)
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
return tubelib.get_item(meta, "dst")
|
||||||
|
end,
|
||||||
|
on_push_item = function(pos, side, item)
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
minetest.get_node_timer(pos):start(CYCLE_TIME)
|
||||||
|
return tubelib.put_item(meta, "src", item)
|
||||||
|
end,
|
||||||
|
on_unpull_item = function(pos, side, item)
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
return tubelib.put_item(meta, "dst", item)
|
||||||
|
end,
|
||||||
|
|
||||||
|
on_recv_message = function(pos, topic, payload)
|
||||||
|
local node = minetest.get_node(pos)
|
||||||
|
if topic == "on" then
|
||||||
|
return switch_on(pos, node)
|
||||||
|
elseif topic == "off" then
|
||||||
|
return switch_off(pos, node)
|
||||||
|
elseif topic == "state" then
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
local running = meta:get_int("running") or tubelib.STATE_STOPPED
|
||||||
|
return tubelib.statestring(running)
|
||||||
|
else
|
||||||
|
return "not supported"
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
--------------------------------------------------------------- tubelib
|
@ -275,7 +275,7 @@ local function on_receive_fields(pos, formname, fields, player)
|
|||||||
|
|
||||||
local running = meta:get_int("running") or STOP_STATE
|
local running = meta:get_int("running") or STOP_STATE
|
||||||
if fields.button ~= nil then
|
if fields.button ~= nil then
|
||||||
if running > STOP_STATE or running == FAULT_STATE then
|
if running > STOP_STATE then
|
||||||
stop_the_machine(pos)
|
stop_the_machine(pos)
|
||||||
else
|
else
|
||||||
start_the_machine(pos)
|
start_the_machine(pos)
|
||||||
|
BIN
tubelib_addons1/textures/tubelib_addons1_liquidsampler.png
Normal file
BIN
tubelib_addons1/textures/tubelib_addons1_liquidsampler.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 496 B |
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
After Width: | Height: | Size: 654 B |
Loading…
Reference in New Issue
Block a user