signs_bot/basis.lua

531 lines
14 KiB
Lua
Raw Normal View History

2019-03-23 13:15:13 -07:00
--[[
Signs Bot
=========
Copyright (C) 2019-2021 Joachim Stolberg
2019-03-23 13:15:13 -07:00
2019-08-22 11:51:29 -07:00
GPL v3
2019-03-23 13:15:13 -07:00
See LICENSE.txt for more information
Signs Bot: Robot basis block
]]--
-- for lazy programmers
local M = minetest.get_meta
-- Load support for I18n.
local S = signs_bot.S
2019-03-23 13:15:13 -07:00
local lib = signs_bot.lib
2020-02-25 10:44:15 -08:00
signs_bot.MAX_CAPA = 600
2020-02-24 12:05:26 -08:00
2019-03-23 13:15:13 -07:00
local CYCLE_TIME = 1
2021-08-01 01:31:31 -07:00
local CYCLE_TIME2 = 2 -- for charging phase
2019-03-23 13:15:13 -07:00
2019-10-11 11:12:07 -07:00
local function in_range(val, min, max)
if val < min then return min end
if val > max then return max end
return val
end
-- determine item name from the given Bot inventory slot
function signs_bot.bot_inv_item_name(pos, slot)
if slot == 0 then return nil end -- invalid num
local inv = M(pos):get_inventory()
local name = inv:get_stack("filter", slot):get_name()
if name ~= "" then return name end
end
-- put items into the bot inventory and return leftover
function signs_bot.bot_inv_put_item(pos, slot, items)
2019-10-18 12:00:06 -07:00
if not items then return end
2019-10-11 11:12:07 -07:00
local inv = M(pos):get_inventory()
if slot and slot > 0 then
local name = inv:get_stack("filter", slot):get_name()
if name == "" or name == items:get_name() then
local stack = inv:get_stack("main", slot)
2019-10-18 12:00:06 -07:00
items = stack:add_item(items)
2019-10-11 11:12:07 -07:00
inv:set_stack("main", slot, stack)
end
else
for idx = 1,8 do
local name = inv:get_stack("filter", idx):get_name()
if name == "" or name == items:get_name() then
local stack = inv:get_stack("main", idx)
2019-10-18 12:00:06 -07:00
items = stack:add_item(items)
2019-10-11 11:12:07 -07:00
inv:set_stack("main", idx, stack)
2019-10-18 12:00:06 -07:00
if items:get_count() == 0 then return items end
2019-10-11 11:12:07 -07:00
end
end
end
return items
end
local function take_items(inv, slot, num)
local stack = inv:get_stack("main", slot)
if stack:get_count() >= num then
local taken = stack:take_item(num)
inv:set_stack("main", slot, stack)
return taken
else
inv:set_stack("main", slot, nil)
local rest = num - stack:get_count()
local taken = inv:remove_item("main", ItemStack(stack:get_name().." "..rest))
stack:set_count(stack:get_count() + taken:get_count())
return stack
end
end
2019-10-11 11:12:07 -07:00
-- take items from the bot inventory
function signs_bot.bot_inv_take_item(pos, slot, num)
local inv = M(pos):get_inventory()
if slot and slot > 0 then
return take_items(inv, slot, num)
2019-10-11 11:12:07 -07:00
else
for idx = 1,8 do
if not inv:get_stack("main", idx):is_empty() then
return take_items(inv, idx, num)
2019-10-11 11:12:07 -07:00
end
end
end
end
local bot_inv_item_name = signs_bot.bot_inv_item_name
local function preassigned_slots(pos)
local inv = M(pos):get_inventory()
local tbl = {}
for idx = 1,8 do
local item_name = inv:get_stack("filter", idx):get_name()
if item_name ~= "" then
local x = ((idx - 1) % 4) + 5
local y = idx < 5 and 1 or 2
tbl[#tbl+1] = "item_image["..x..","..y..";1,1;"..item_name.."]"
end
end
return table.concat(tbl, "")
end
local function status(mem)
if mem.error then
if type(mem.error) == "string" then
return mem.error
else
return dump(mem.error)
end
end
if mem.running then
return S("running")
end
if mem.charging then
return S("charging")
end
return S("stopped")
end
local function formspec(pos, mem)
2019-03-23 13:15:13 -07:00
mem.running = mem.running or false
local cmnd = mem.running and "stop;"..S("Off") or "start;"..S("On")
2019-10-11 11:12:07 -07:00
local bot = not mem.running and "image[0.6,0;1,1;signs_bot_bot_inv.png]" or ""
2019-06-20 07:22:01 -07:00
local current_capa = mem.capa or (signs_bot.MAX_CAPA * 0.9)
return "size[9,8.2]"..
2019-03-23 13:15:13 -07:00
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"label[2.1,0;"..S("Signs").."]label[5.3,0;"..S("Other items").."]"..
2019-10-11 11:12:07 -07:00
"image[0.6,0;1,1;signs_bot_form_mask.png]"..
2019-04-09 12:09:33 -07:00
bot..
2019-10-11 11:12:07 -07:00
preassigned_slots(pos)..
2019-06-20 07:22:01 -07:00
signs_bot.formspec_battery_capa(signs_bot.MAX_CAPA, current_capa)..
2019-04-12 13:32:40 -07:00
"label[2.1,0.5;1]label[3.1,0.5;2]label[4.1,0.5;3]"..
"list[context;sign;1.8,1;3,2;]"..
"label[2.1,3;4]label[3.1,3;5]label[4.1,3;6]"..
"label[5.3,0.5;1]label[6.3,0.5;2]label[7.3,0.5;3]label[8.3,0.5;4]"..
"list[context;main;5,1;4,2;]"..
"label[5.3,3;5]label[6.3,3;6]label[7.3,3;7]label[8.3,3;8]"..
"button[0.2,1;1.5,1;config;"..S("Config").."]"..
2019-04-12 13:32:40 -07:00
"button[0.2,2;1.5,1;"..cmnd.."]"..
"label[1,3.6;"..status(mem).."]"..
"list[current_player;main;0.5,4.4;8,4;]"..
2019-03-23 13:15:13 -07:00
"listring[context;main]"..
"listring[current_player;main]"
end
local function formspec_cfg()
return "size[9,8.2]"..
2019-10-11 11:12:07 -07:00
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"label[5.3,0;"..S("Preassign slots items").."]"..
2019-10-11 11:12:07 -07:00
"label[5.3,0.5;1]label[6.3,0.5;2]label[7.3,0.5;3]label[8.3,0.5;4]"..
"list[context;filter;5,1;4,2;]"..
"label[5.3,3;5]label[6.3,3;6]label[7.3,3;7]label[8.3,3;8]"..
"button[0.2,1;1.5,1;back;"..S("Back").."]"..
"list[current_player;main;0.5,4.4;8,4;]"..
"listring[context;filter]"..
"listring[current_player;main]"
2019-10-11 11:12:07 -07:00
end
local function get_capa(itemstack)
local meta = itemstack:get_meta()
if meta then
return in_range(meta:get_int("capa") * (signs_bot.MAX_CAPA/100), 0, 3000)
end
return 0
end
local function set_capa(pos, oldnode, digger, capa)
local node = ItemStack(oldnode.name)
local meta = node:get_meta()
capa = techage.power.percent(signs_bot.MAX_CAPA, capa)
capa = (math.floor((capa or 0) / 5)) * 5
meta:set_int("capa", capa)
local text = S("Robot Box").." ("..capa.." %)"
2019-10-11 11:12:07 -07:00
meta:set_string("description", text)
local inv = minetest.get_inventory({type="player", name=digger:get_player_name()})
local left_over = inv:add_item("main", node)
if left_over:get_count() > 0 then
minetest.add_item(pos, node)
end
end
function signs_bot.infotext(pos, state)
2019-04-14 10:38:25 -07:00
local meta = M(pos)
local number = meta:get_string("number")
state = state or "<unknown>"
meta:set_string("infotext", S("Robot Box").." "..number..": "..state)
2019-03-23 13:15:13 -07:00
end
2021-11-03 12:34:31 -07:00
local function free_start_pos(pos, mem)
local param2 = (minetest.get_node(pos).param2 + 1) % 4
local robot_pos = lib.next_pos(pos, param2, 1)
return signs_bot.lib.is_air_like(robot_pos)
end
2019-03-23 13:15:13 -07:00
local function reset_robot(pos, mem)
mem.robot_param2 = (minetest.get_node(pos).param2 + 1) % 4
mem.robot_pos = lib.next_pos(pos, mem.robot_param2, 1)
local pos_below = {x=mem.robot_pos.x, y=mem.robot_pos.y-1, z=mem.robot_pos.z}
signs_bot.place_robot(mem.robot_pos, pos_below, mem.robot_param2)
end
function signs_bot.start_robot(base_pos)
local mem = tubelib2.get_mem(base_pos)
2021-11-03 12:34:31 -07:00
if free_start_pos(base_pos, mem) then
mem.steps = nil
mem.script = "cond_move"
local meta = M(base_pos)
signs_bot.reset(base_pos, mem)
mem.running = true
mem.charging = false
mem.error = false
mem.stored_node = nil
if minetest.global_exists("techage") then
mem.capa = mem.capa or 0 -- enable power consumption
else
mem.capa = nil
end
meta:set_string("formspec", formspec(base_pos, mem))
signs_bot.infotext(base_pos, S("running"))
reset_robot(base_pos, mem)
minetest.get_node_timer(base_pos):start(CYCLE_TIME)
return true
2019-06-20 07:22:01 -07:00
end
2019-03-23 13:15:13 -07:00
end
2019-03-24 11:03:12 -07:00
function signs_bot.stop_robot(base_pos, mem)
2019-04-14 10:38:25 -07:00
local meta = M(base_pos)
if mem.signal_request ~= true then
mem.running = false
2019-08-18 09:07:34 -07:00
if minetest.global_exists("techage") then
2021-08-01 01:31:31 -07:00
minetest.get_node_timer(base_pos):start(CYCLE_TIME2)
2019-08-18 09:07:34 -07:00
mem.charging = true
2020-03-27 10:29:40 -07:00
mem.power_available = false
2019-08-18 09:07:34 -07:00
else
minetest.get_node_timer(base_pos):stop()
mem.charging = false
end
2021-08-01 01:31:31 -07:00
if mem.charging then
signs_bot.infotext(base_pos, S("charging"))
else
signs_bot.infotext(base_pos, S("stopped"))
end
meta:set_string("formspec", formspec(base_pos, mem))
signs_bot.remove_robot(mem)
else
mem.signal_request = false
signs_bot.start_robot(base_pos)
end
2019-03-23 13:15:13 -07:00
end
-- Used by the pairing tool
local function signs_bot_get_signal(pos, node)
local mem = tubelib2.get_mem(pos)
if mem.running then
return "on"
else
return "off"
end
end
-- To be called from sensors
local function signs_bot_on_signal(pos, node, signal)
local mem = tubelib2.get_mem(pos)
if signal == "on" and not mem.running then
signs_bot.start_robot(pos)
elseif signal == "off" and mem.running then
signs_bot.stop_robot(pos, mem)
2019-05-25 11:16:11 -07:00
-- else
-- mem.signal_request = (signal == "on")
end
end
2019-03-23 13:15:13 -07:00
local function node_timer(pos, elapsed)
local mem = tubelib2.get_mem(pos)
2019-08-18 09:07:34 -07:00
if mem.charging and signs_bot.while_charging then
return signs_bot.while_charging(pos, mem)
else
local res = false
--local t = minetest.get_us_time()
if mem.running then
res = signs_bot.run_next_command(pos, mem)
end
--t = minetest.get_us_time() - t
--print("node_timer", t)
return res and mem.running
end
2019-03-23 13:15:13 -07:00
end
local function on_receive_fields(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
local mem = tubelib2.get_mem(pos)
local meta = minetest.get_meta(pos)
if fields.update then
meta:set_string("formspec", formspec(pos, mem))
2019-10-11 11:12:07 -07:00
elseif fields.config then
meta:set_string("formspec", formspec_cfg())
2019-10-11 11:12:07 -07:00
elseif fields.back then
meta:set_string("formspec", formspec(pos, mem))
elseif fields.start then
signs_bot.start_robot(pos)
elseif fields.stop then
2019-03-24 11:03:12 -07:00
signs_bot.stop_robot(pos, mem)
2019-03-23 13:15:13 -07:00
end
end
2019-06-20 07:22:01 -07:00
local function on_rightclick(pos)
local mem = tubelib2.get_mem(pos)
M(pos):set_string("formspec", formspec(pos, mem))
end
2019-03-29 12:20:51 -07:00
local function allow_metadata_inventory_put(pos, listname, index, stack, player)
2019-03-23 13:15:13 -07:00
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
2019-03-29 12:20:51 -07:00
local mem = tubelib2.get_mem(pos)
if mem.running then
return 0
end
local name = stack:get_name()
if listname == "sign" and minetest.get_item_group(name, "sign_bot_sign") ~= 1 then
2019-03-29 12:20:51 -07:00
return 0
end
2019-10-11 11:12:07 -07:00
if listname == "main" and bot_inv_item_name(pos, index) and
name ~= bot_inv_item_name(pos, index) then
return 0
end
if listname == "filter" then
local inv = M(pos):get_inventory()
local list = inv:get_list(listname)
if list[index]:get_count() == 0 or stack:get_name() ~= list[index]:get_name() then
return 1
end
return 0
end
2019-03-23 13:15:13 -07:00
return stack:get_count()
end
2019-03-29 12:20:51 -07:00
local function allow_metadata_inventory_take(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
local mem = tubelib2.get_mem(pos)
if mem.running 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
local mem = tubelib2.get_mem(pos)
if mem.running then
return 0
end
if from_list ~= to_list then
return 0
end
2019-10-11 11:12:07 -07:00
local inv = M(pos):get_inventory()
local name = inv:get_stack(from_list, from_index):get_name()
if to_list == "main" and bot_inv_item_name(pos, to_index) and
name ~= bot_inv_item_name(pos, to_index) then
return 0
end
if to_list == "filter" then
local list = inv:get_list(to_list)
if list[to_index]:get_count() == 0 or name ~= list[to_index]:get_name() then
return 1
end
return 0
end
2019-03-29 12:20:51 -07:00
return count
end
2019-10-11 11:12:07 -07:00
local drop = "signs_bot:box"
if minetest.global_exists("techage") then
drop = ""
end
2019-03-23 13:15:13 -07:00
minetest.register_node("signs_bot:box", {
description = S("Signs Bot Box"),
2019-03-23 13:15:13 -07:00
stack_max = 1,
tiles = {
-- up, down, right, left, back, front
'signs_bot_base_top.png',
'signs_bot_base_top.png',
'signs_bot_base_right.png',
'signs_bot_base_left.png',
'signs_bot_base_front.png',
'signs_bot_base_front.png',
},
on_construct = function(pos)
2019-04-14 10:38:25 -07:00
local meta = M(pos)
2019-03-23 13:15:13 -07:00
local inv = meta:get_inventory()
inv:set_size('main', 8)
inv:set_size('sign', 6)
2019-10-11 11:12:07 -07:00
inv:set_size('filter', 8)
2019-03-23 13:15:13 -07:00
end,
2019-10-11 11:12:07 -07:00
after_place_node = function(pos, placer, itemstack)
if not placer or not placer:is_player() then
minetest.remove_node(pos)
minetest.add_item(pos, itemstack)
end
2019-03-23 13:15:13 -07:00
local mem = tubelib2.init_mem(pos)
mem.running = false
2019-06-28 14:49:01 -07:00
mem.error = false
2019-04-14 10:38:25 -07:00
local meta = M(pos)
2019-06-28 14:49:01 -07:00
local number = ""
if minetest.global_exists("techage") then
number = techage.add_node(pos, "signs_bot:box")
end
2019-03-23 13:15:13 -07:00
meta:set_string("owner", placer:get_player_name())
meta:set_string("number", number)
meta:set_string("formspec", formspec(pos, mem))
2019-03-23 13:15:13 -07:00
meta:set_string("signs_bot_cmnd", "turn_off")
meta:set_int("err_code", 0)
signs_bot.infotext(pos, S("stopped"))
2019-10-11 11:12:07 -07:00
if minetest.global_exists("techage") then
2020-02-24 12:05:26 -08:00
techage.ElectricCable:after_place_node(pos)
2019-10-11 11:12:07 -07:00
mem.capa = get_capa(itemstack)
end
2019-03-23 13:15:13 -07:00
end,
signs_bot_get_signal = signs_bot_get_signal,
signs_bot_on_signal = signs_bot_on_signal,
2019-03-23 13:15:13 -07:00
on_receive_fields = on_receive_fields,
2019-06-20 07:22:01 -07:00
on_rightclick = on_rightclick,
2019-03-29 12:20:51 -07:00
allow_metadata_inventory_put = allow_metadata_inventory_put,
allow_metadata_inventory_take = allow_metadata_inventory_take,
allow_metadata_inventory_move = allow_metadata_inventory_move,
2019-03-23 13:15:13 -07:00
can_dig = function(pos, player)
if minetest.is_protected(pos, player:get_player_name()) then
2019-03-23 13:15:13 -07:00
return
end
2019-06-28 14:49:01 -07:00
local mem = tubelib2.get_mem(pos)
2019-03-23 13:15:13 -07:00
if mem.running then
return
end
local inv = M(pos):get_inventory()
return inv:is_empty("main") and inv:is_empty("sign")
end,
on_dig = function(pos, node, puncher, pointed_thing)
2019-03-23 13:15:13 -07:00
minetest.node_dig(pos, node, puncher, pointed_thing)
end,
2019-10-11 11:12:07 -07:00
after_dig_node = function(pos, oldnode, oldmetadata, digger)
if minetest.global_exists("techage") then
2020-02-24 12:05:26 -08:00
techage.ElectricCable:after_dig_node(pos)
2019-10-11 11:12:07 -07:00
local mem = tubelib2.get_mem(pos)
set_capa(pos, oldnode, digger, mem.capa)
end
tubelib2.del_mem(pos)
end,
on_timer = node_timer,
on_rotate = screwdriver.disallow,
2019-10-11 11:12:07 -07:00
drop = drop,
2019-03-23 13:15:13 -07:00
paramtype2 = "facedir",
is_ground_content = false,
groups = {cracky = 1},
sounds = default.node_sound_metal_defaults(),
})
if minetest.global_exists("techage") then
minetest.register_craft({
output = "signs_bot:box",
recipe = {
{"default:steel_ingot", "group:wood", "default:steel_ingot"},
{"basic_materials:motor", "techage:ta4_wlanchip", "basic_materials:gear_steel"},
{"default:tin_ingot", "", "default:tin_ingot"}
}
})
else
minetest.register_craft({
output = "signs_bot:box",
recipe = {
{"default:steel_ingot", "group:wood", "default:steel_ingot"},
{"basic_materials:motor", "default:mese_crystal", "basic_materials:gear_steel"},
{"default:tin_ingot", "", "default:tin_ingot"}
}
})
end
2019-03-23 13:15:13 -07:00
if minetest.get_modpath("doc") then
doc.add_entry("signs_bot", "box", {
name = S("Signs Bot Box"),
data = {
item = "signs_bot:box",
text = table.concat({
S("The Box is the housing of the bot."),
S("Place the box and start the bot by means of the 'On' button."),
S("If the mod techage is installed, the bot needs electrical power."),
"",
S("The bot leaves the box on the right side."),
S("It will not start, if this position is blocked."),
"",
S("To stop and remove the bot, press the 'Off' button."),
"",
S("The box inventory simulates the inventory of the bot."),
S("You will not be able to access the inventory, if the bot is running."),
S("The bot can carry up to 8 stacks and 6 signs with it."),
}, "\n")
},
})
end