mirror of
https://github.com/joe7575/techpack.git
synced 2024-11-22 07:13:48 +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.*
|
||||
*.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.
|
||||
|
||||
@ -77,7 +77,7 @@ Gravelsieve optional: moreores, hopper, pipeworks
|
||||
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-24 V1.01 * Support for Ethereal added
|
||||
- 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-13 V1.11 * Detector 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
|
||||
|
||||
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 stack
|
||||
if percent > 95 then
|
||||
stack = ItemStack("sl_controller:battery")
|
||||
stack = ItemStack("smartline:battery")
|
||||
elseif percent > 75 then
|
||||
stack = ItemStack("sl_controller:battery75")
|
||||
stack = ItemStack("smartline:battery75")
|
||||
elseif percent > 50 then
|
||||
stack = ItemStack("sl_controller:battery50")
|
||||
stack = ItemStack("smartline:battery50")
|
||||
elseif percent > 25 then
|
||||
stack = ItemStack("sl_controller:battery25")
|
||||
stack = ItemStack("smartline:battery25")
|
||||
else
|
||||
return
|
||||
end
|
||||
@ -95,7 +97,7 @@ local function register_battery(ext, percent, nici)
|
||||
})
|
||||
end
|
||||
|
||||
register_battery("", 1.0, 0)
|
||||
register_battery("", 1.0, 1)
|
||||
register_battery("75", 0.75, 1)
|
||||
register_battery("50", 0.5, 1)
|
||||
register_battery("25", 0.25, 1)
|
||||
@ -135,22 +137,22 @@ minetest.register_node("sl_controller:battery_empty", {
|
||||
})
|
||||
|
||||
|
||||
if minetest.global_exists("moreores") then
|
||||
minetest.register_craft({
|
||||
output = "sl_controller:battery 2",
|
||||
recipe = {
|
||||
{"", "moreores:silver_ingot", ""},
|
||||
{"", "default:copper_ingot", ""},
|
||||
{"", "moreores:silver_ingot", ""},
|
||||
}
|
||||
})
|
||||
else
|
||||
minetest.register_craft({
|
||||
output = "sl_controller:battery 2",
|
||||
recipe = {
|
||||
{"", "default:tin_ingot", ""},
|
||||
{"", "default:copper_ingot", ""},
|
||||
{"", "default:tin_ingot", ""},
|
||||
}
|
||||
})
|
||||
end
|
||||
--if minetest.global_exists("moreores") then
|
||||
-- minetest.register_craft({
|
||||
-- output = "sl_controller:battery 2",
|
||||
-- recipe = {
|
||||
-- {"", "moreores:silver_ingot", ""},
|
||||
-- {"", "default:copper_ingot", ""},
|
||||
-- {"", "moreores:silver_ingot", ""},
|
||||
-- }
|
||||
-- })
|
||||
--else
|
||||
-- minetest.register_craft({
|
||||
-- output = "sl_controller:battery 2",
|
||||
-- recipe = {
|
||||
-- {"", "default:tin_ingot", ""},
|
||||
-- {"", "default:copper_ingot", ""},
|
||||
-- {"", "default:tin_ingot", ""},
|
||||
-- }
|
||||
-- })
|
||||
--end
|
||||
|
@ -181,6 +181,7 @@ sl_controller.register_action("door", {
|
||||
if door then
|
||||
local player = {
|
||||
get_player_name = function() return self.meta.owner end,
|
||||
is_player = function() return true end,
|
||||
}
|
||||
if text == "open" then
|
||||
door:open(player)
|
||||
|
@ -230,7 +230,7 @@ local function compile(pos, meta, number)
|
||||
end
|
||||
|
||||
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
|
||||
local meta = minetest.get_meta(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)
|
||||
if input then
|
||||
if Cache[number] and Cache[number].inputs then
|
||||
Cache[number].inputs[input] = val
|
||||
-- only one event per second
|
||||
local t = minetest.get_us_time()
|
||||
if not Cache[number].last_event or Cache[number].last_event < t then
|
||||
Cache[number].inputs[input] = val
|
||||
local meta = minetest.get_meta(pos)
|
||||
minetest.after(0.1, call_loop, pos, meta, -1)
|
||||
Cache[number].last_event = t + 1000000 -- add one second
|
||||
minetest.after(0.01, call_loop, pos, meta, -1)
|
||||
Cache[number].last_event = t + 500000 -- add 500 ms
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -584,6 +584,7 @@ local function door_toggle(pos, owner, state)
|
||||
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)
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
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.
|
||||
It has a 'update' button to update the view.
|
||||
|
||||
For more information, see: goo.gl/fF5ap6
|
||||
]]
|
||||
|
||||
local sOUTPUT = "Press 'help' for edit commands"
|
||||
@ -117,8 +117,6 @@ local function exec_action(data, environ, number)
|
||||
ActnRunTimeHandlers[data.__idx__](data, environ, number)
|
||||
end
|
||||
|
||||
smartline = {}
|
||||
|
||||
--
|
||||
-- API functions for condition/action registrations
|
||||
--
|
||||
@ -845,9 +843,10 @@ minetest.register_node("smartline:controller", {
|
||||
paramtype = "light",
|
||||
sunlight_propagates = true,
|
||||
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,
|
||||
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
|
||||
minetest.get_modpath("font_lib") and font_lib ~= nil then
|
||||
dofile(minetest.get_modpath("smartline") .. "/display.lua")
|
||||
dofile(MP.."/display.lua")
|
||||
end
|
||||
dofile(minetest.get_modpath("smartline") .. "/button.lua")
|
||||
dofile(minetest.get_modpath("smartline") .. "/signaltower.lua")
|
||||
dofile(minetest.get_modpath("smartline") .. "/playerdetector.lua")
|
||||
dofile(minetest.get_modpath("smartline") .. "/sequencer.lua")
|
||||
dofile(minetest.get_modpath("smartline") .. "/timer.lua")
|
||||
dofile(minetest.get_modpath("smartline") .. "/repeater.lua")
|
||||
dofile(minetest.get_modpath("smartline") .. "/controller.lua")
|
||||
dofile(minetest.get_modpath("smartline") .. "/commands.lua")
|
||||
dofile(MP.."/button.lua")
|
||||
dofile(MP.."/signaltower.lua")
|
||||
dofile(MP.."/playerdetector.lua")
|
||||
dofile(MP.."/sequencer.lua")
|
||||
dofile(MP.."/timer.lua")
|
||||
dofile(MP.."/repeater.lua")
|
||||
dofile(MP.."/controller.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
|
||||
default
|
||||
bucket
|
||||
stairs?
|
||||
moreores?
|
||||
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") .. "/pusher_fast.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
|
||||
if fields.button ~= nil then
|
||||
if running > STOP_STATE or running == FAULT_STATE then
|
||||
if running > STOP_STATE then
|
||||
stop_the_machine(pos)
|
||||
else
|
||||
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