pipeworks/wielder.lua

355 lines
12 KiB
Lua
Raw Permalink Normal View History

local S = minetest.get_translator("pipeworks")
local has_digilines = minetest.get_modpath("digilines")
local function set_wielder_formspec(def, meta)
local width, height = def.wield_inv.width, def.wield_inv.height
local offset = 5.22 - width * 0.625
local size = "10.2,"..(6.5 + height * 1.25 + (has_digilines and 1.25 or 0))
local list_bg = ""
if minetest.get_modpath("i3") or minetest.get_modpath("mcl_formspec") then
list_bg = "style_type[box;colors=#666]"
for i=0, height-1 do
for j=0, width-1 do
list_bg = list_bg.."box["..offset+(i*1.25)..","..1.25+(j*1.25)..";1,1;]"
end
end
end
local inv_offset = 1.5 + height * 1.25
local fs = "formspec_version[2]size["..size.."]"..
pipeworks.fs_helpers.get_prepends(size)..list_bg..
"item_image[0.5,0.3;1,1;"..def.name.."_off]"..
"label[1.75,0.8;"..minetest.formspec_escape(def.description).."]"..
"list[context;"..def.wield_inv.name..";"..offset..",1.25;"..width..","..height..";]"
if has_digilines then
fs = fs.."field[1.5,"..inv_offset..";5,0.8;channel;"..S("Channel")..";${channel}]"..
"button_exit[6.5,"..inv_offset..";2,0.8;save;"..S("Save").."]"..
pipeworks.fs_helpers.get_inv(inv_offset + 1.25).."listring[]"
else
fs = fs..pipeworks.fs_helpers.get_inv(inv_offset).."listring[]"
end
meta:set_string("formspec", fs)
meta:set_string("infotext", def.description)
end
local function wielder_action(def, pos, node, index)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local list = inv:get_list(def.wield_inv.name)
local wield_index
if index then
if list[index] and (def.wield_hand or not list[index]:is_empty()) then
wield_index = index
end
else
for i, stack in ipairs(list) do
if not stack:is_empty() then
wield_index = i
break
end
end
end
if not wield_index and not def.wield_hand then
return
end
local dir = minetest.facedir_to_dir(node.param2)
local fakeplayer = fakelib.create_player({
name = meta:get_string("owner"),
direction = vector.multiply(dir, -1),
position = pos,
inventory = inv,
wield_index = wield_index or 1,
wield_list = def.wield_inv.name,
})
-- Under and above positions are intentionally switched.
local pointed = {
type = "node",
under = vector.subtract(pos, dir),
above = vector.subtract(pos, vector.multiply(dir, 2)),
}
def.action(fakeplayer, pointed)
if def.eject_drops then
for i, stack in ipairs(inv:get_list("main")) do
if not stack:is_empty() then
pipeworks.tube_inject_item(pos, pos, dir, stack)
inv:set_stack("main", i, ItemStack(""))
end
end
end
end
local function wielder_on(def, pos, node)
if node.name ~= def.name.."_off" then
return
end
node.name = def.name.."_on"
minetest.swap_node(pos, node)
wielder_action(def, pos, node)
end
local function wielder_off(def, pos, node)
if node.name == def.name.."_on" then
node.name = def.name.."_off"
minetest.swap_node(pos, node)
end
end
local function wielder_digiline_action(def, pos, channel, msg)
local meta = minetest.get_meta(pos)
local set_channel = meta:get_string("channel")
if channel ~= set_channel then
return
end
if type(msg) ~= "table" then
if type(msg) == "string" then
if msg:sub(1, 8) == "activate" then
msg = {command = "activate", slot = tonumber(msg:sub(9))}
end
else
return
end
end
if msg.command == "activate" then
local node = minetest.get_node(pos)
local index = type(msg.slot) == "number" and msg.slot or nil
wielder_action(def, pos, node, index)
end
end
function pipeworks.register_wielder(def)
for _,state in ipairs({"off", "on"}) do
local groups = {
snappy = 2, choppy = 2, oddly_breakable_by_hand = 2,
mesecon = 2, tubedevice = 1, tubedevice_receiver = 1,
axey = 1, handy = 1, pickaxey = 1,
not_in_creative_inventory = state == "on" and 1 or nil
}
minetest.register_node(def.name.."_"..state, {
description = def.description,
tiles = def.tiles[state],
paramtype2 = "facedir",
groups = groups,
is_ground_content = false,
_mcl_hardness = 0.6,
_sound_def = {
key = "node_sound_stone_defaults",
},
drop = def.name.."_off",
mesecons = {
effector = {
rules = pipeworks.rules_all,
action_on = function(pos, node)
wielder_on(def, pos, node)
end,
action_off = function(pos, node)
wielder_off(def, pos, node)
end,
},
},
digilines = {
receptor = {},
effector = {
action = function(pos, _, channel, msg)
wielder_digiline_action(def, pos, channel, msg)
end,
},
},
tube = {
can_insert = function(pos, node, stack, direction)
if def.eject_drops then
-- Prevent ejected items from being inserted
local dir = vector.multiply(minetest.facedir_to_dir(node.param2), -1)
if vector.equals(direction, dir) then
return false
end
end
local inv = minetest.get_meta(pos):get_inventory()
return inv:room_for_item(def.wield_inv.name, stack)
end,
insert_object = function(pos, node, stack)
local inv = minetest.get_meta(pos):get_inventory()
return inv:add_item(def.wield_inv.name, stack)
end,
input_inventory = def.wield_inv.name,
connect_sides = def.connect_sides,
can_remove = function(pos, node, stack)
return stack:get_count()
end,
},
on_construct = function(pos)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
inv:set_size(def.wield_inv.name, def.wield_inv.width * def.wield_inv.height)
if def.eject_drops then
inv:set_size("main", 32)
end
set_wielder_formspec(def, meta)
end,
after_place_node = function(pos, placer)
pipeworks.scan_for_tube_objects(pos)
if not placer then
return
end
local node = minetest.get_node(pos)
node.param2 = minetest.dir_to_facedir(placer:get_look_dir(), true)
minetest.set_node(pos, node)
minetest.get_meta(pos):set_string("owner", placer:get_player_name())
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
for _,stack in ipairs(oldmetadata.inventory[def.wield_inv.name] or {}) do
if not stack:is_empty() then
minetest.add_item(pos, stack)
end
end
pipeworks.scan_for_tube_objects(pos)
end,
on_rotate = pipeworks.on_rotate,
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
if not pipeworks.may_configure(pos, player) then return 0 end
return stack:get_count()
end,
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
if not pipeworks.may_configure(pos, player) then return 0 end
return stack:get_count()
end,
allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
if not pipeworks.may_configure(pos, player) then return 0 end
return count
end,
on_receive_fields = function(pos, _, fields, sender)
if not fields.channel or not pipeworks.may_configure(pos, sender) then
return
end
minetest.get_meta(pos):set_string("channel", fields.channel)
end,
})
end
table.insert(pipeworks.ui_cat_tube_list, def.name.."_off")
end
local function get_tiles(name, stateful)
local tiles = {on = {}, off = {}}
for _,state in ipairs({"off", "on"}) do
for _,side in ipairs({"top", "bottom", "side2", "side1", "back", "front"}) do
local suffix = stateful[side] and "_"..state or ""
table.insert(tiles[state], "pipeworks_"..name.."_"..side..suffix..".png")
end
end
return tiles
end
if pipeworks.enable_node_breaker then
pipeworks.register_wielder({
name = "pipeworks:nodebreaker",
description = S("Node Breaker"),
tiles = get_tiles("nodebreaker", {top = 1, bottom = 1, side2 = 1, side1 = 1, front = 1}),
connect_sides = {top = 1, bottom = 1, left = 1, right = 1, back = 1},
wield_inv = {name = "pick", width = 1, height = 1},
wield_hand = true,
eject_drops = true,
action = function(fakeplayer, pointed)
local stack = fakeplayer:get_wielded_item()
local old_stack = ItemStack(stack)
local item_def = minetest.registered_items[stack:get_name()]
if item_def.on_use then
stack = item_def.on_use(stack, fakeplayer, pointed) or stack
fakeplayer:set_wielded_item(stack)
else
local node = minetest.get_node(pointed.under)
local node_def = minetest.registered_nodes[node.name]
if not node_def or not node_def.on_dig then
return
end
-- Check if the tool can dig the node
local tool = stack:get_tool_capabilities()
if not minetest.get_dig_params(node_def.groups, tool).diggable then
-- Try using hand if tool can't dig the node
local hand = ItemStack():get_tool_capabilities()
if not minetest.get_dig_params(node_def.groups, hand).diggable then
return
end
end
-- This must only check for false, because `on_dig` returning nil is the same as returning true.
if node_def.on_dig(pointed.under, node, fakeplayer) == false then
return
end
local sound = node_def.sounds and node_def.sounds.dug
if sound then
minetest.sound_play(sound, {pos = pointed.under}, true)
end
stack = fakeplayer:get_wielded_item()
end
if stack:get_name() == old_stack:get_name() then
-- Don't mechanically wear out tool
if stack:get_wear() ~= old_stack:get_wear() and stack:get_count() == old_stack:get_count()
and (item_def.wear_represents == nil or item_def.wear_represents == "mechanical_wear") then
fakeplayer:set_wielded_item(old_stack)
end
elseif not stack:is_empty() then
-- Tool got replaced by something else, treat it as a drop.
fakeplayer:get_inventory():add_item("main", stack)
fakeplayer:set_wielded_item("")
end
end,
})
minetest.register_alias("technic:nodebreaker_off", "pipeworks:nodebreaker_off")
minetest.register_alias("technic:nodebreaker_on", "pipeworks:nodebreaker_on")
minetest.register_alias("technic:node_breaker_off", "pipeworks:nodebreaker_off")
minetest.register_alias("technic:node_breaker_on", "pipeworks:nodebreaker_on")
minetest.register_alias("auto_tree_tap:off", "pipeworks:nodebreaker_off")
minetest.register_alias("auto_tree_tap:on", "pipeworks:nodebreaker_on")
end
if pipeworks.enable_deployer then
pipeworks.register_wielder({
name = "pipeworks:deployer",
description = S("Deployer"),
tiles = get_tiles("deployer", {front = 1}),
connect_sides = {back = 1},
wield_inv = {name = "main", width = 3, height = 3},
action = function(fakeplayer, pointed)
local stack = fakeplayer:get_wielded_item()
local def = minetest.registered_items[stack:get_name()]
if def and def.on_place then
local new_stack, placed_pos = def.on_place(stack, fakeplayer, pointed)
fakeplayer:set_wielded_item(new_stack or stack)
-- minetest.item_place_node doesn't play sound to the placer
local sound = placed_pos and def.sounds and def.sounds.place
local name = fakeplayer:get_player_name()
if sound and name ~= "" then
minetest.sound_play(sound, {pos = placed_pos, to_player = name}, true)
end
end
end,
})
minetest.register_alias("technic:deployer_off", "pipeworks:deployer_off")
minetest.register_alias("technic:deployer_on", "pipeworks:deployer_on")
end
if pipeworks.enable_dispenser then
-- Override minetest.item_drop to negate its hardcoded offset
-- when the dropper is a fake player.
local item_drop = minetest.item_drop
-- luacheck: ignore 122
function minetest.item_drop(stack, dropper, pos)
if dropper and dropper.is_fake_player then
pos = vector.new(pos.x, pos.y - 1.2, pos.z)
end
return item_drop(stack, dropper, pos)
end
pipeworks.register_wielder({
name = "pipeworks:dispenser",
description = S("Dispenser"),
tiles = get_tiles("dispenser", {front = 1}),
connect_sides = {back = 1},
wield_inv = {name = "main", width = 3, height = 3},
action = function(fakeplayer)
local stack = fakeplayer:get_wielded_item()
local def = minetest.registered_items[stack:get_name()]
if def and def.on_drop then
local pos = fakeplayer:get_pos()
fakeplayer:set_wielded_item(def.on_drop(stack, fakeplayer, pos) or stack)
end
end,
})
end