770 lines
23 KiB
Lua
770 lines
23 KiB
Lua
--[[
|
|
|
|
TechAge
|
|
=======
|
|
|
|
Copyright (C) 2019-2025 Joachim Stolberg
|
|
|
|
AGPL v3
|
|
See LICENSE.txt for more information
|
|
|
|
TA5 Item Digitizer
|
|
]]--
|
|
|
|
-- for lazy programmers
|
|
local M = minetest.get_meta
|
|
local S = techage.S
|
|
local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end
|
|
|
|
-- Consumer Related Data
|
|
local Tube = techage.Tube
|
|
local Cable = techage.ElectricCable
|
|
local power = networks.power
|
|
local MP = minetest.get_modpath(minetest.get_current_modname())
|
|
local mConf = dofile(MP .. "/basis/conf_inv.lua")
|
|
local CYCLE_TIME = 2
|
|
local STANDBY_TICKS = 8
|
|
local COUNTDOWN_TICKS = 2
|
|
local NUM_ITEMS = 50
|
|
local STORAGE_SLOTS = 8
|
|
local STORAGE_SIZE = 100000
|
|
local PWR_NEEDED = 24
|
|
local EX_POINTS = techage.ta5_digitizer_expoints
|
|
local DESC = S("TA5 Digitizer")
|
|
local LOG_INTERVAL = 150 -- ticks (~5 min at CYCLE_TIME=2)
|
|
|
|
-- items:
|
|
-- {
|
|
-- [1] = {name = "default:stone", count = 10},
|
|
-- [2] = {name = "default:gold_ingot", count = 5},
|
|
-- ....
|
|
-- [STORAGE_SLOTS] = {name = "default:diamond", count = 1},
|
|
-- }
|
|
|
|
-- Returns true if the item can be stored (stackable, no metadata, no wear)
|
|
local function is_valid_item(stack)
|
|
if not stack or stack:is_empty() then return false end
|
|
local ndef = minetest.registered_items[stack:get_name()]
|
|
if not ndef then return false end
|
|
if (ndef.stack_max or 1) <= 1 then return false end
|
|
if stack:get_wear() > 0 then return false end
|
|
if next(stack:get_meta():to_table().fields) ~= nil then return false end
|
|
return true
|
|
end
|
|
|
|
local function store_items(pos, mem, force)
|
|
if force and mem.items ~= nil then -- nil guard: never overwrite valid meta with nil
|
|
M(pos):set_string("items", minetest.serialize(mem.items))
|
|
end
|
|
end
|
|
|
|
-- Short summary for item tooltip (e.g. "3/16 slots, 150234 items")
|
|
local function items_summary_short(items_tbl)
|
|
if not items_tbl then return "empty" end
|
|
local slots_used, total = 0, 0
|
|
for i = 1, STORAGE_SLOTS do
|
|
local slot = items_tbl[i]
|
|
if slot and slot.name ~= "" and slot.count > 0 then
|
|
slots_used = slots_used + 1
|
|
total = total + slot.count
|
|
end
|
|
end
|
|
if slots_used == 0 then return "empty" end
|
|
return slots_used .. "/" .. STORAGE_SLOTS .. " slots, " .. total .. " items"
|
|
end
|
|
|
|
-- Full summary for server log (one entry per used slot)
|
|
local function items_summary_full(items_tbl)
|
|
if not items_tbl then return "empty" end
|
|
local parts = {}
|
|
for i = 1, STORAGE_SLOTS do
|
|
local slot = items_tbl[i]
|
|
if slot and slot.name ~= "" and slot.count > 0 then
|
|
parts[#parts + 1] = slot.name .. " x" .. slot.count
|
|
end
|
|
end
|
|
if #parts == 0 then return "empty" end
|
|
return table.concat(parts, ", ")
|
|
end
|
|
|
|
local function get_total_count(items_tbl)
|
|
if not items_tbl then return 0 end
|
|
local total = 0
|
|
for i = 1, STORAGE_SLOTS do
|
|
local slot = items_tbl[i]
|
|
if slot and slot.name ~= "" and slot.count > 0 then
|
|
total = total + slot.count
|
|
end
|
|
end
|
|
return total
|
|
end
|
|
|
|
local function restore_items(pos, mem)
|
|
if mem.items == nil then
|
|
local meta = M(pos)
|
|
if meta:contains("items") then
|
|
mem.items = minetest.deserialize(meta:get_string("items")) or {}
|
|
else
|
|
mem.items = {}
|
|
end
|
|
for idx = 1, STORAGE_SLOTS do
|
|
mem.items[idx] = mem.items[idx] or {name = "", count = 0}
|
|
end
|
|
end
|
|
end
|
|
|
|
local function find_storage_slot_with_space(pos, mem, max_num_items, item_name)
|
|
local function match(i, force)
|
|
if (mem.items[i].name == item_name and mem.items[i].count < STORAGE_SIZE)
|
|
or (force and mem.items[i].name == "") then
|
|
mem.items[i].name = item_name
|
|
return i
|
|
end
|
|
return nil -- full
|
|
end
|
|
local function num_items(idx, max_num_items)
|
|
return math.min(STORAGE_SIZE - mem.items[idx].count, max_num_items)
|
|
end
|
|
|
|
restore_items(pos, mem)
|
|
|
|
-- Try last used slot
|
|
if mem.last_idx and match(mem.last_idx) then
|
|
return mem.last_idx, num_items(mem.last_idx, max_num_items)
|
|
end
|
|
|
|
-- Try all slots with items
|
|
for i = 1, STORAGE_SLOTS do
|
|
if match(i) then
|
|
mem.last_idx = i
|
|
return i, num_items(i, max_num_items)
|
|
end
|
|
end
|
|
|
|
-- Try all empty slots also
|
|
for i = 1, STORAGE_SLOTS do
|
|
if match(i, true) then
|
|
mem.last_idx = i
|
|
return i, num_items(i, max_num_items)
|
|
end
|
|
end
|
|
|
|
mem.last_idx = nil
|
|
return nil, 0 -- full
|
|
end
|
|
|
|
local function find_storage_slot_with_items(pos, mem, item_name)
|
|
restore_items(pos, mem)
|
|
for i = STORAGE_SLOTS, 1, -1 do
|
|
if mem.items[i].name == item_name then
|
|
if mem.items[i].count > 0 then
|
|
return i
|
|
else
|
|
mem.items[i].name = ""
|
|
end
|
|
end
|
|
end
|
|
return nil -- empty
|
|
end
|
|
|
|
local function is_empty(pos, mem)
|
|
restore_items(pos, mem)
|
|
for i = 1, STORAGE_SLOTS do
|
|
if mem.items[i].count > 0 then
|
|
return false
|
|
end
|
|
end
|
|
return true -- empty
|
|
end
|
|
|
|
local function delete_empty_slot(pos, mem, idx)
|
|
if mem.items[idx].name ~= "" and mem.items[idx].count == 0 then
|
|
mem.items[idx].name = ""
|
|
end
|
|
end
|
|
|
|
local function item_image(x, y, item_name, item_count)
|
|
local box = "box[" .. (x + 1.2) .. "," .. (y + 0.2) .. ";2,0.6;#808080]"
|
|
local label = "label[" .. (x + 1.2) .. "," .. (y + 0.5) .. ";" .. string.format("%8d", item_count or 0) .. "]"
|
|
local text = ""
|
|
local tooltip = ""
|
|
|
|
if item_name ~= "" and item_count > 0 then
|
|
text = minetest.formspec_escape(ItemStack(item_name):get_description())
|
|
tooltip = "tooltip["..x..","..y..";1,1;"..text..";#0C3D32;#FFFFFF]"
|
|
end
|
|
|
|
return "box[" .. x .. "," .. y .. ";1,1;#808080]" ..
|
|
"style_type[label;font=mono]" ..
|
|
"item_image[" .. x .. "," .. y .. ";1,1;" .. item_name .. "]" ..
|
|
tooltip .. box .. label
|
|
end
|
|
|
|
local function fs_container(rows, text)
|
|
local size = 130
|
|
return "scrollbaroptions[max=" .. size .. "]" ..
|
|
"scrollbar[9.6,1.2;0.4,8.2;vertical;wrenchmenu;]" ..
|
|
"scroll_container[0.2,1;9.4,8;wrenchmenu;vertical;]" ..
|
|
text ..
|
|
"scroll_container_end[]"
|
|
end
|
|
|
|
local function formspec1(self, pos, nvm)
|
|
local opmode = nvm.opmode or 1
|
|
return "formspec_version[8]" ..
|
|
"size[10.2,9.6]" ..
|
|
"tabheader[0,0;tab;" .. S("Control,Storage") .. ";1;;true]" ..
|
|
"box[0.2,0.2;9.8,0.5;#c6e8ff]" ..
|
|
"label[0.5,0.45;" .. minetest.colorize( "#000000", DESC) .. "]" ..
|
|
"label[5.7,1.5;" .. S("Configured\nItem") .. "]" ..
|
|
"list[context;main;4.5,1.2;1,1;]" ..
|
|
"image[2.5,1;1,1;"..techage.get_power_image(pos, nvm) .. "]" ..
|
|
"tooltip[2.5,1;1,1;" .. S("Needs @1 ku power", PWR_NEEDED) .. "]" ..
|
|
"image_button[2.5,2.5;1,1;" .. self:get_state_button_image(nvm) .. ";state_button;]" ..
|
|
"tooltip[2.5,2.5;1,1;" .. self:get_state_tooltip(nvm) .. "]" ..
|
|
"dropdown[4.5,3;4,0.6;opmode;" .. S("pull") .. "," .. S("push") .. ";" .. opmode .. ";true]" ..
|
|
"list[current_player;main;0.2,4.4;8,4;]" ..
|
|
"listring[context;main]" ..
|
|
"listring[current_player;main]"
|
|
end
|
|
|
|
local function formspec2(self, pos, nvm)
|
|
local mem = techage.get_mem(pos)
|
|
restore_items(pos, mem)
|
|
local tbl = {}
|
|
local idx = 1
|
|
for idx = 1, STORAGE_SLOTS do
|
|
local name, count = mem.items[idx].name, mem.items[idx].count
|
|
if idx % 2 == 1 then
|
|
tbl[#tbl + 1] = item_image(0.5, (idx + 0) * 0.6, name, count)
|
|
else
|
|
tbl[#tbl + 1] = item_image(5.5, (idx - 1) * 0.6, name, count)
|
|
end
|
|
end
|
|
return "formspec_version[8]" ..
|
|
"size[10.2,9.6]" ..
|
|
"tabheader[0,0;tab;" .. S("Control,Storage") .. ";2;;true]" ..
|
|
"box[0.2,0.2;9.8,0.5;#c6e8ff]" ..
|
|
"label[0.5,0.45;" .. minetest.colorize( "#000000", DESC) .. "]" ..
|
|
fs_container(#tbl, table.concat(tbl, ""))
|
|
end
|
|
|
|
local function formspec(self, pos, nvm)
|
|
if nvm.fs_tab2 then
|
|
return formspec2(self, pos, nvm)
|
|
else
|
|
return formspec1(self, pos, nvm)
|
|
end
|
|
end
|
|
|
|
local function configured_item(pos)
|
|
local inv = M(pos):get_inventory()
|
|
local stack = inv:get_stack('main', 1)
|
|
if stack and stack:get_count() > 0 then
|
|
return stack:get_name()
|
|
end
|
|
return nil
|
|
end
|
|
|
|
local function config_item(pos, payload)
|
|
local inv = M(pos):get_inventory()
|
|
local stack = ItemStack(payload)
|
|
inv:set_stack("main", 1, stack)
|
|
end
|
|
|
|
local function stop_node(pos, nvm, state)
|
|
end
|
|
|
|
local function can_start(pos, nvm, state)
|
|
if configured_item(pos) then
|
|
local mem = techage.get_mem(pos)
|
|
mem.last_idx = nil
|
|
return true
|
|
end
|
|
return S("no configured item")
|
|
end
|
|
|
|
local State = techage.NodeStates:new({
|
|
node_name_passive = "techage:ta5_digitizer_pas",
|
|
node_name_active = "techage:ta5_digitizer_act",
|
|
cycle_time = CYCLE_TIME,
|
|
infotext_name = DESC,
|
|
standby_ticks = STANDBY_TICKS,
|
|
formspec_func = formspec,
|
|
stop_node = stop_node,
|
|
can_start = can_start,
|
|
})
|
|
|
|
local function consume_power(pos, nvm)
|
|
if techage.needs_power(nvm) then
|
|
local taken = power.consume_power(pos, Cable, nil, PWR_NEEDED)
|
|
if techage.is_running(nvm) then
|
|
if taken < PWR_NEEDED then
|
|
State:nopower(pos, nvm)
|
|
return false
|
|
else
|
|
return true
|
|
end
|
|
elseif taken == PWR_NEEDED then
|
|
State:start(pos, nvm)
|
|
return false
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
return true
|
|
end
|
|
|
|
local function on_receive_fields(pos, formname, fields, player)
|
|
if minetest.is_protected(pos, player:get_player_name()) then
|
|
return
|
|
end
|
|
local meta = M(pos)
|
|
local nvm = techage.get_nvm(pos)
|
|
if fields.tab == "1" then
|
|
nvm.fs_tab2 = false
|
|
meta:set_string("formspec", formspec(State, pos, nvm))
|
|
return
|
|
elseif fields.tab == "2" then
|
|
nvm.fs_tab2 = true
|
|
techage.set_activeformspec(pos, player)
|
|
meta:set_string("formspec", formspec(State, pos, nvm))
|
|
return
|
|
else
|
|
if fields.opmode then
|
|
nvm.opmode = tonumber(fields.opmode)
|
|
end
|
|
if EX_POINTS == 0 or techage.get_expoints(player) >= EX_POINTS then
|
|
State:state_button_event(pos, nvm, fields)
|
|
end
|
|
end
|
|
end
|
|
|
|
local function digitize(pos, nvm, mem)
|
|
local item_name = configured_item(pos)
|
|
if item_name == nil then
|
|
State:fault(pos, nvm, S("No configured item"))
|
|
return false
|
|
end
|
|
|
|
local tube_dir = M(pos):get_int("tube_dir")
|
|
local idx, num_items = find_storage_slot_with_space(pos, mem, NUM_ITEMS, item_name)
|
|
if idx then
|
|
local taken = techage.pull_items(pos, tube_dir, num_items, item_name)
|
|
if taken and taken:get_count() > 0 then
|
|
if not is_valid_item(taken) then
|
|
techage.push_items(pos, tube_dir, taken)
|
|
State:fault(pos, nvm, S("Invalid item type"))
|
|
return false
|
|
end
|
|
local is_new_slot = mem.items[idx].count == 0
|
|
mem.items[idx].count = mem.items[idx].count + taken:get_count()
|
|
if is_new_slot then
|
|
minetest.log("action", "[techage] TA5 Digitizer #" .. M(pos):get_string("node_number") ..
|
|
" | new slot: " .. item_name .. " at " .. P2S(pos))
|
|
end
|
|
State:keep_running(pos, nvm, COUNTDOWN_TICKS)
|
|
return true
|
|
end
|
|
delete_empty_slot(pos, mem, idx)
|
|
-- Pulled nothing, try again later
|
|
State:idle(pos, nvm)
|
|
return false
|
|
end
|
|
-- No space in storage, stop execution
|
|
State:blocked(pos, nvm, S("Storage full"))
|
|
return false
|
|
end
|
|
|
|
local function reassemble(pos, nvm, mem)
|
|
local item_name = configured_item(pos)
|
|
if item_name == nil then
|
|
State:fault(pos, nvm, S("No configured item"))
|
|
return false
|
|
end
|
|
|
|
local tube_dir = M(pos):get_int("tube_dir")
|
|
local idx = find_storage_slot_with_items(pos, mem, item_name)
|
|
if idx then
|
|
local count = math.min(mem.items[idx].count, NUM_ITEMS)
|
|
local stack = ItemStack({name = item_name, count = count})
|
|
local leftover = techage.push_items(pos, tube_dir, stack)
|
|
local pushed = not leftover and 0 or leftover ~= true and count - leftover:get_count() or count
|
|
local prev_name = mem.items[idx].name
|
|
mem.items[idx].count = mem.items[idx].count - pushed
|
|
delete_empty_slot(pos, mem, idx)
|
|
if mem.items[idx].name == "" then
|
|
minetest.log("action", "[techage] TA5 Digitizer #" .. M(pos):get_string("node_number") ..
|
|
" | slot cleared: " .. prev_name .. " at " .. P2S(pos))
|
|
end
|
|
if pushed > 0 then
|
|
State:keep_running(pos, nvm, COUNTDOWN_TICKS)
|
|
return true
|
|
else
|
|
-- Can't push items, try again later
|
|
State:blocked(pos, nvm, "Can't push, no space")
|
|
end
|
|
return false
|
|
end
|
|
-- No items in storage, stop execution
|
|
State:stop(pos, nvm)
|
|
return false
|
|
end
|
|
|
|
local function on_timer(pos, elapsed)
|
|
local nvm = techage.get_nvm(pos)
|
|
if consume_power(pos, nvm) then
|
|
local mem = techage.get_mem(pos)
|
|
local changed = false
|
|
if nvm.opmode == 1 then
|
|
changed = digitize(pos, nvm, mem)
|
|
else
|
|
changed = reassemble(pos, nvm, mem)
|
|
end
|
|
store_items(pos, mem, changed)
|
|
-- Periodic status log (~every 5 min)
|
|
nvm.log_tick = (nvm.log_tick or 0) + 1
|
|
if nvm.log_tick >= LOG_INTERVAL then
|
|
nvm.log_tick = 0
|
|
local full = items_summary_full(mem.items)
|
|
if full ~= "empty" then
|
|
minetest.log("action", "[techage] TA5 Digitizer #" .. M(pos):get_string("node_number") ..
|
|
" | status: " .. full .. " at " .. P2S(pos))
|
|
end
|
|
end
|
|
if techage.is_activeformspec(pos) then
|
|
M(pos):set_string("formspec", formspec(State, pos, nvm))
|
|
end
|
|
end
|
|
return true -- keep running
|
|
end
|
|
|
|
minetest.register_node("techage:ta5_digitizer_pas", {
|
|
description = DESC,
|
|
tiles = {
|
|
-- up, down, right, left, back, front
|
|
"techage_filling_ta4.png^techage_frame_ta5_top.png^techage_appl_arrow.png",
|
|
"techage_filling_ta4.png^techage_frame_ta5.png",
|
|
"techage_filling_ta4.png^techage_frame_ta5.png^techage_appl_in_out.png",
|
|
"techage_filling_ta4.png^techage_frame_ta5.png",
|
|
"techage_filling_ta4.png^techage_appl_digitizer_off.png^techage_frame_ta5.png",
|
|
"techage_filling_ta4.png^techage_appl_digitizer_off.png^techage_frame_ta5.png",
|
|
},
|
|
|
|
after_place_node = function(pos, placer, itemstack, pointed_thing)
|
|
-- Don't allow placing if itemstack has metadata
|
|
if techage.cordless_screwdriver_only(pos, placer, itemstack) then
|
|
return true
|
|
end
|
|
|
|
local meta = M(pos)
|
|
local nvm = techage.get_nvm(pos)
|
|
local node = minetest.get_node(pos)
|
|
local tube_dir = techage.side_to_outdir("R", node.param2)
|
|
local number = techage.add_node(pos, "techage:ta5_digitizer_pas")
|
|
State:node_init(pos, nvm, number)
|
|
meta:set_int("tube_dir", tube_dir)
|
|
meta:set_string("owner", placer:get_player_name())
|
|
Tube:after_place_node(pos, {tube_dir})
|
|
Cable:after_place_node(pos)
|
|
local inv = meta:get_inventory()
|
|
inv:set_size('main', 1)
|
|
end,
|
|
|
|
ta_rotate_node = function(pos, node, new_param2)
|
|
local meta = M(pos)
|
|
Cable:after_dig_node(pos)
|
|
Tube:after_dig_node(pos)
|
|
minetest.swap_node(pos, {name = node.name, param2 = new_param2})
|
|
local tube_dir = techage.side_to_outdir("R", new_param2)
|
|
meta:set_int("tube_dir", tube_dir)
|
|
Tube:after_place_node(pos, {tube_dir})
|
|
Cable:after_place_node(pos)
|
|
end,
|
|
|
|
on_timer = on_timer,
|
|
on_receive_fields = on_receive_fields,
|
|
ta_preserve_nodedata = function(pos, node, digger)
|
|
-- Load items from meta into mem first (handles cold mem after server restart),
|
|
-- then flush to meta so pack_meta captures the current state reliably.
|
|
local mem = techage.get_mem(pos)
|
|
restore_items(pos, mem)
|
|
store_items(pos, mem, true)
|
|
local number = M(pos):get_string("node_number")
|
|
local player_name = digger and digger:get_player_name() or "unknown"
|
|
local short = items_summary_short(mem.items)
|
|
local full = items_summary_full(mem.items)
|
|
minetest.log("action", "[techage] TA5 Digitizer #" .. number ..
|
|
" packed by " .. player_name ..
|
|
" at " .. P2S(pos) .. " | " .. full)
|
|
return techage.preserve_nodedata(pos), short
|
|
end,
|
|
ta_restore_nodedata = function(pos, s, placer)
|
|
techage.restore_nodedata(pos, s)
|
|
-- Re-register the existing node number in the backend (required after
|
|
-- placement via cordless screwdriver, where add_node is never called)
|
|
techage.repair_number(pos)
|
|
-- Log restored contents directly from freshly-restored meta
|
|
local items_tbl = minetest.deserialize(M(pos):get_string("items"))
|
|
local number = M(pos):get_string("node_number")
|
|
local player_name = placer and placer:get_player_name() or "unknown"
|
|
local full = items_summary_full(items_tbl)
|
|
minetest.log("action", "[techage] TA5 Digitizer #" .. number ..
|
|
" unpacked by " .. player_name ..
|
|
" at " .. P2S(pos) .. " | " .. full)
|
|
local node = minetest.get_node(pos)
|
|
local tube_dir = techage.side_to_outdir("R", node.param2)
|
|
local meta = M(pos)
|
|
meta:set_int("tube_dir", tube_dir)
|
|
Tube:after_place_node(pos, {tube_dir})
|
|
Cable:after_place_node(pos)
|
|
end,
|
|
|
|
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
|
|
if minetest.is_protected(pos, player:get_player_name()) then
|
|
return 0
|
|
end
|
|
if not is_valid_item(stack) then
|
|
minetest.chat_send_player(player:get_player_name(),
|
|
S("Item not storable (not stackable, has metadata, or is worn)"))
|
|
return 0
|
|
end
|
|
return mConf.allow_conf_inv_put(pos, listname, index, stack, player)
|
|
end,
|
|
|
|
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
|
|
if minetest.is_protected(pos, player:get_player_name()) then
|
|
return 0
|
|
end
|
|
return mConf.allow_conf_inv_take(pos, listname, index, stack, player)
|
|
end,
|
|
|
|
ta_can_remove = function(pos, digger)
|
|
if minetest.is_protected(pos, digger:get_player_name()) then
|
|
return false
|
|
end
|
|
local nvm = techage.get_nvm(pos)
|
|
if (nvm.techage_state or techage.STOPPED) ~= techage.STOPPED then
|
|
minetest.chat_send_player(digger:get_player_name(),
|
|
S("[Digitizer] Stop the Digitizer first!"))
|
|
return false
|
|
end
|
|
return true -- only removable when stopped; data preserved via ta_preserve_nodedata
|
|
end,
|
|
|
|
can_dig = function(pos, player)
|
|
if minetest.is_protected(pos, player:get_player_name()) then
|
|
return false
|
|
end
|
|
local mem = techage.get_mem(pos)
|
|
if is_empty(pos, mem) then
|
|
return true
|
|
else
|
|
minetest.chat_send_player(player:get_player_name(),
|
|
S("[Digitizer] Storage not empty! Empty the storage first."))
|
|
return false
|
|
end
|
|
end,
|
|
|
|
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
|
techage.remove_node(pos, oldnode, oldmetadata)
|
|
Tube:after_dig_node(pos)
|
|
Cable:after_dig_node(pos)
|
|
techage.del_mem(pos)
|
|
end,
|
|
|
|
paramtype2 = "facedir", -- important!
|
|
on_rotate = screwdriver.disallow, -- important!
|
|
is_ground_content = false,
|
|
groups = {crumbly = 3, cracky = 3, snappy = 3},
|
|
sounds = default.node_sound_glass_defaults(),
|
|
})
|
|
|
|
minetest.register_node("techage:ta5_digitizer_act", {
|
|
description = DESC,
|
|
tiles = {
|
|
-- up, down, right, left, back, front
|
|
"techage_filling_ta4.png^techage_frame_ta5_top.png^techage_appl_arrow.png",
|
|
"techage_filling_ta4.png^techage_frame_ta5.png",
|
|
"techage_filling_ta4.png^techage_frame_ta5.png^techage_appl_in_out.png",
|
|
"techage_filling_ta4.png^techage_frame_ta5.png",
|
|
{
|
|
name = "techage_appl_digitizer_on4.png^[transformR180]^techage_frame4_ta5.png",
|
|
backface_culling = false,
|
|
animation = {
|
|
type = "vertical_frames",
|
|
aspect_w = 32,
|
|
aspect_h = 32,
|
|
length = 1.2,
|
|
},
|
|
},
|
|
{
|
|
name = "techage_appl_digitizer_on4.png^techage_frame4_ta5.png",
|
|
backface_culling = false,
|
|
animation = {
|
|
type = "vertical_frames",
|
|
aspect_w = 32,
|
|
aspect_h = 32,
|
|
length = 1.2,
|
|
},
|
|
},
|
|
},
|
|
|
|
on_timer = on_timer,
|
|
on_receive_fields = on_receive_fields,
|
|
|
|
on_rightclick = function(pos, node, clicker)
|
|
local nvm = techage.get_nvm(pos)
|
|
techage.set_activeformspec(pos, clicker)
|
|
M(pos):set_string("formspec", formspec(State, pos, nvm))
|
|
end,
|
|
|
|
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
|
|
return 0
|
|
end,
|
|
|
|
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
|
|
return 0
|
|
end,
|
|
|
|
ta_can_remove = function(pos, digger)
|
|
if minetest.is_protected(pos, digger:get_player_name()) then
|
|
return false
|
|
end
|
|
minetest.chat_send_player(digger:get_player_name(),
|
|
S("[Digitizer] Stop the Digitizer first!"))
|
|
return false
|
|
end,
|
|
|
|
paramtype2 = "facedir", -- important!
|
|
on_rotate = screwdriver.disallow, -- important!
|
|
is_ground_content = false,
|
|
drop = "",
|
|
diggable = false,
|
|
groups = {crumbly = 3, cracky = 3, snappy = 3, not_in_creative_inventory = 1},
|
|
sounds = default.node_sound_glass_defaults(),
|
|
})
|
|
|
|
techage.register_node({"techage:ta5_digitizer_pas", "techage:ta5_digitizer_act"}, {
|
|
on_recv_message = function(pos, src, topic, payload)
|
|
if topic == "pull" then
|
|
local nvm = techage.get_nvm(pos)
|
|
if not techage.is_running(nvm) and configured_item(pos) then
|
|
nvm.opmode = 1
|
|
State:start(pos, nvm)
|
|
return true
|
|
end
|
|
return false
|
|
elseif topic == "push" then
|
|
local nvm = techage.get_nvm(pos)
|
|
if not techage.is_running(nvm) and configured_item(pos) then
|
|
nvm.opmode = 2
|
|
State:start(pos, nvm)
|
|
return true
|
|
end
|
|
return false
|
|
elseif topic == "config" then
|
|
local nvm = techage.get_nvm(pos)
|
|
if techage.is_running(nvm) then
|
|
State:stop(pos, nvm)
|
|
end
|
|
if payload and type(payload) == "string" then
|
|
config_item(pos, payload)
|
|
return true
|
|
end
|
|
return false
|
|
elseif topic == "stop" then
|
|
local nvm = techage.get_nvm(pos)
|
|
State:stop(pos, nvm)
|
|
return true
|
|
elseif topic == "count" then
|
|
local nvm = techage.get_nvm(pos)
|
|
restore_items(pos, nvm)
|
|
return get_total_count(nvm.items)
|
|
elseif topic == "itemstring" then
|
|
return configured_item(pos) or ""
|
|
elseif topic == "mode" then
|
|
local nvm = techage.get_nvm(pos)
|
|
if payload then
|
|
nvm.opmode = tonumber(payload) == 2 and 2 or 1
|
|
return true
|
|
end
|
|
return nvm.opmode or 1
|
|
else
|
|
return State:on_receive_message(pos, topic, payload)
|
|
end
|
|
end,
|
|
on_beduino_receive_cmnd = function(pos, src, topic, payload)
|
|
if topic == 65 then -- Set config item (itemstring)
|
|
local nvm = techage.get_nvm(pos)
|
|
if techage.is_running(nvm) then
|
|
State:stop(pos, nvm)
|
|
end
|
|
config_item(pos, payload)
|
|
return 0
|
|
elseif topic == 67 then -- Set mode (1=pull, 2=push), string payload
|
|
local nvm = techage.get_nvm(pos)
|
|
nvm.opmode = (tonumber(payload) == 2) and 2 or 1
|
|
return 0
|
|
else
|
|
return State:on_beduino_receive_cmnd(pos, topic, payload)
|
|
end
|
|
end,
|
|
on_beduino_request_data = function(pos, src, topic, payload)
|
|
if topic == 154 then -- Get total stored item count
|
|
local nvm = techage.get_nvm(pos)
|
|
restore_items(pos, nvm)
|
|
return 0, {get_total_count(nvm.items)}
|
|
elseif topic == 155 then -- Get configured item name
|
|
return 0, configured_item(pos) or ""
|
|
else
|
|
return State:on_beduino_request_data(pos, topic, payload)
|
|
end
|
|
end,
|
|
on_node_load = function(pos, node)
|
|
local nvm = techage.get_nvm(pos)
|
|
if techage.is_operational(nvm) then
|
|
State:on_node_load(pos)
|
|
end
|
|
end,
|
|
})
|
|
|
|
power.register_nodes({"techage:ta5_digitizer_pas", "techage:ta5_digitizer_act"}, Cable, "con", {"B", "L", "F", "D", "U"})
|
|
Tube:set_valid_sides({"techage:ta5_digitizer_pas", "techage:ta5_digitizer_act"}, {"R"})
|
|
|
|
techage.recipes.add("ta4_electronic_fab", {
|
|
output = "techage:ta5_controlunit 1",
|
|
waste = "basic_materials:empty_spool 1",
|
|
input = {
|
|
"techage:aluminum 1", "basic_materials:gold_wire 1", "techage:ta5_aichip2 1", "techage:ta4_wlanchip 2",
|
|
},
|
|
ex_points = EX_POINTS,
|
|
})
|
|
|
|
minetest.register_craftitem("techage:ta5_controlunit", {
|
|
description = S("TA5 Control Unit"),
|
|
inventory_image = "techage_controlunit.png",
|
|
})
|
|
|
|
minetest.register_craftitem("techage:ta5_ssd", {
|
|
description = S("TA5 SSD"),
|
|
inventory_image = "techage_ta5_ssd.png",
|
|
})
|
|
|
|
techage.recipes.add("ta4_electronic_fab", {
|
|
output = "techage:ta5_ssd 1",
|
|
input = {
|
|
"techage:ta4_ramchip 16", "techage:ta4_silicon_wafer 1",
|
|
"basic_materials:plastic_sheet 1", "basic_materials:steel_strip 1",
|
|
},
|
|
})
|
|
|
|
minetest.register_craft({
|
|
output = "techage:ta5_digitizer_pas",
|
|
recipe = {
|
|
{"techage:aluminum", "dye:red", "techage:ta4_carbon_fiber"},
|
|
{"techage:electric_cableS", "techage:ta4_pusher_pas", "techage:ta4_tubeS"},
|
|
{"techage:ta5_ssd", "basic_materials:gear_steel", "techage:ta5_controlunit"},
|
|
},
|
|
})
|