Upload files to "lwcomponents"

This commit is contained in:
Mavori 2025-06-27 17:50:53 +02:00
commit b20501ef6a
5 changed files with 2049 additions and 0 deletions

View file

@ -0,0 +1 @@
Various components for mesecons and digilines.

164
lwcomponents/destroyer.lua Normal file
View file

@ -0,0 +1,164 @@
local utils = ...
local S = utils.S
local function trash (pos)
local meta = minetest.get_meta (pos)
local inv = (meta and meta:get_inventory ()) or nil
if inv then
local stack = inv:get_stack ("trash", 1)
if stack and not stack:is_empty () then
utils.on_destroy (stack)
inv:set_stack ("trash", 1, nil)
end
end
end
local function trash_delayed (pos)
minetest.after (0.1, trash, pos)
end
local function after_place_node (pos, placer, itemstack, pointed_thing)
local meta = minetest.get_meta (pos)
if meta then
local inv = meta:get_inventory ()
if inv then
meta:set_string ("inventory", "{ trash = { [1] = '' } }")
meta:set_string ("formspec",
"formspec_version[3]"..
"size[11.75,8.5,false]"..
"label[5.15,1.0;Destroy]"..
"list[context;trash;5.3,1.25;1,1;]"..
"list[current_player;main;1.0,2.75;8,4;]"..
"listring[]")
inv:set_size ("trash", 1)
inv:set_width ("trash", 1)
end
end
utils.pipeworks_after_place (pos)
-- If return true no item is taken from itemstack
return false
end
local function on_metadata_inventory_put (pos, listname, index, stack, player)
if listname == "trash" then
trash_delayed (pos)
end
end
local function on_metadata_inventory_move (pos, from_list, from_index,
to_list, to_index, count, player)
if to_list == "trash" then
trash_delayed (pos)
end
end
local function pipeworks_support ()
if utils.pipeworks_supported then
return
{
priority = 100,
input_inventory = "trash",
connect_sides = { left = 1, right = 1, front = 1, back = 1, bottom = 1, top = 1 },
insert_object = function (pos, node, stack, direction)
local meta = minetest.get_meta (pos)
local inv = (meta and meta:get_inventory ()) or nil
if inv then
trash_delayed (pos)
return inv:add_item ("trash", stack)
end
return stack
end,
can_insert = function (pos, node, stack, direction)
local meta = minetest.get_meta (pos)
local inv = (meta and meta:get_inventory ()) or nil
if inv then
return inv:room_for_item ("trash", stack)
end
return false
end,
can_remove = function (pos, node, stack, dir)
-- returns the maximum number of items of that stack that can be removed
return 0
end,
remove_items = function (pos, node, stack, dir, count)
-- removes count items and returns them
return stack
end
}
end
return nil
end
local destroyer_groups = { cracky = 3 }
if utils.pipeworks_supported then
destroyer_groups.tubedevice = 1
destroyer_groups.tubedevice_receiver = 1
end
minetest.register_node("lwcomponents:destroyer", {
description = S("Destroyer"),
drawtype = "normal",
tiles = { "lwcomponents_destroyer_top.png", "lwcomponents_destroyer_top.png",
"lwcomponents_destroyer_side.png", "lwcomponents_destroyer_side.png",
"lwcomponents_destroyer_side.png", "lwcomponents_destroyer_side.png" },
is_ground_content = false,
groups = table.copy (destroyer_groups),
--sounds = default.node_sound_stone_defaults (),
paramtype = "none",
param1 = 0,
paramtype2 = "none",
param2 = 0,
floodable = false,
tube = pipeworks_support (),
after_place_node = after_place_node,
after_dig_node = utils.pipeworks_after_dig,
on_metadata_inventory_put = on_metadata_inventory_put,
on_metadata_inventory_move = on_metadata_inventory_move,
})
utils.hopper_add_container({
{"bottom", "lwcomponents:destroyer", "trash"}, -- insert items below from hopper above
{"side", "lwcomponents:destroyer", "trash"}, -- insert items from hopper at side
})
--

906
lwcomponents/detector.lua Normal file
View file

@ -0,0 +1,906 @@
local utils = ...
local S = utils.S
if utils.digilines_supported or utils.mesecon_supported then
local detect_interval = 0.5
local function mesecons_on (pos)
local meta = minetest.get_meta (pos)
if meta then
if meta:get_int ("power_on") == 0 then
utils.mesecon_receptor_on (pos, utils.mesecon_default_rules)
meta:set_int ("power_on", 1)
local node = utils.get_far_node (pos)
if node then
if node.name == "lwcomponents:detector_locked_on" then
node.name = "lwcomponents:detector_locked_on_on"
elseif node.name == "lwcomponents:detector_on" then
node.name = "lwcomponents:detector_on_on"
end
minetest.swap_node (pos, node)
end
end
end
end
local function mesecons_off (pos)
local meta = minetest.get_meta (pos)
if meta then
if meta:get_int ("power_on") ~= 0 then
utils.mesecon_receptor_off (pos, utils.mesecon_default_rules)
meta:set_int ("power_on", 0)
local node = utils.get_far_node (pos)
if node then
if node.name == "lwcomponents:detector_locked_on_on" then
node.name = "lwcomponents:detector_locked_on"
elseif node.name == "lwcomponents:detector_on_on" then
node.name = "lwcomponents:detector_on"
end
minetest.swap_node (pos, node)
end
end
end
end
local function to_relative_coords (pos, testpos)
local base = { x = testpos.x - pos.x,
y = testpos.y - pos.y,
z = testpos.z - pos.z }
local node = minetest.get_node (pos)
if node then
if node.param2 == 3 then -- +x
return { x = (base.z * -1), y = base.y, z = base.x }
elseif node.param2 == 0 then -- -z
return { x = (base.x * -1), y = base.y, z = (base.z * -1) }
elseif node.param2 == 1 then -- -x
return { x = base.z, y = base.y, z = (base.x * -1) }
elseif node.param2 == 2 then -- +z
return { x = base.x, y = base.y, z = base.z }
end
end
return { x = 0, y = 0, z = 0 }
end
local function send_detect_message (pos, detected_list)
if utils.digilines_supported then
local meta = minetest.get_meta (pos)
if meta then
local channel = meta:get_string ("channel")
if channel:len () > 0 then
utils.digilines_receptor_send (pos,
utils.digilines_default_rules,
channel,
{ action = "detect",
detected = detected_list })
end
end
end
end
local function filter_item (pos, mode, testpos)
local base = { x = math.floor (testpos.x - pos.x + 0.5),
y = math.floor (testpos.y - pos.y + 0.5),
z = math.floor (testpos.z - pos.z + 0.5) }
if base.x == 0 and base.y == 0 and base.z == 0 then
return false
end
if mode == 1 then
-- all
return true
elseif mode == 2 then
-- forward
local node = minetest.get_node (pos)
if node then
if node.param2 == 0 then
-- -z
return (base.x == 0 and base.y == 0 and base.z < 0)
elseif node.param2 == 1 then
-- -x
return (base.x < 0 and base.y == 0 and base.z == 0)
elseif node.param2 == 2 then
-- +z
return (base.x == 0 and base.y == 0 and base.z > 0)
elseif node.param2 == 3 then
-- +x
return (base.x > 0 and base.y == 0 and base.z == 0)
end
end
elseif mode == 3 then
-- up
return (base.x == 0 and base.z == 0 and base.y > 0)
elseif mode == 4 then
-- down
return (base.x == 0 and base.z == 0 and base.y < 0)
end
return false
end
local function get_entity_height (objref)
if objref.get_luaentity then
local entity = objref:get_luaentity ()
if entity and entity.name then
local def = minetest.registered_entities[entity.name]
if def and type (def.collisionbox) == "table" and
type (def.collisionbox[5]) == "number" then
return def.collisionbox[5]
end
end
end
local props = objref:get_properties ()
if props and props.collisionbox and type (props.collisionbox) == "table" and
type (props.collisionbox[5]) == "number" then
return props.collisionbox[5]
end
return 0
end
local function detect (pos)
local meta = minetest.get_meta (pos)
local detected = false
if meta then
local radius = meta:get_int ("radius")
local mode = meta:get_int ("mode")
local object = minetest.get_objects_inside_radius (pos, radius + 0.5)
local detected_list = { }
for i = 1, #object, 1 do
if object[i]:is_player () then
-- player
if meta:get_string ("players") == "true" and
filter_item (pos, mode, object[i]:get_pos ()) then
detected_list[#detected_list + 1] =
{
type = "player",
name = object[i]:get_player_name (),
label = object[i]:get_player_name (),
pos = to_relative_coords (pos, object[i]:get_pos ()),
count = 1,
hp = object[i]:get_hp (),
height = get_entity_height (object[i])
}
detected = true
end
elseif object[i].get_luaentity and object[i]:get_luaentity () and
object[i]:get_luaentity ().name and
object[i]:get_luaentity ().name == "__builtin:item" then
-- drop
if meta:get_string ("drops") == "true" and
filter_item (pos, mode, object[i]:get_pos ()) then
local stack = ItemStack (object[i]:get_luaentity ().itemstring or "")
if stack and not stack:is_empty () then
detected_list[#detected_list + 1] =
{
type = "drop",
name = stack:get_name (),
label = stack:get_name (),
pos = to_relative_coords (pos, object[i]:get_pos ()),
count = stack:get_count (),
hp = 0,
height = 0
}
detected = true
end
end
elseif object[i].get_pos and object[i]:get_pos () then
-- entity
if meta:get_string ("entities") == "true" and
filter_item (pos, mode, object[i]:get_pos ()) then
local name = object[i]:get_nametag_attributes ()
local label = ""
if type (name) == "table" then
label = tostring (name.text or "")
end
name = (object[i].get_luaentity and
object[i]:get_luaentity () and
object[i]:get_luaentity ().name) or ""
detected_list[#detected_list + 1] =
{
type = "entity",
name = name,
label = label,
pos = to_relative_coords (pos, object[i]:get_pos ()),
count = 1,
hp = object[i]:get_hp (),
height = get_entity_height (object[i])
}
detected = true
end
end
end
if meta:get_string ("nodes") == "true" then
for y = (pos.y - radius), (pos.y + radius) do
for x = (pos.x - radius), (pos.x + radius) do
for z = (pos.z - radius), (pos.z + radius) do
local testpos = { x = x, y = y, z = z }
local node = minetest.get_node (testpos)
if node and node.name ~= "air" and node.name ~= "ignore" and
filter_item (pos, mode, testpos) then
detected_list[#detected_list + 1] =
{
type = "node",
name = node.name,
label = node.name,
pos = testpos,
count = 1,
hp = 0,
height = 0
}
detected = true
end
end
end
end
end
if detected then
mesecons_on (pos)
send_detect_message (pos, detected_list)
else
mesecons_off (pos)
end
end
end
local function get_form_spec (is_off, radius, entities, players, drops, nodes, mode)
return
"formspec_version[3]\n"..
"size[11.75,9.0;true]\n"..
"field[1.0,1.0;4.0,0.8;channel;Channel;${channel}]\n"..
"button[5.5,1.0;2.0,0.8;setchannel;Set]\n"..
"button[8.25,1.0;2.5,0.8;"..((is_off and "start;Start") or "stop;Stop").."]\n"..
"field[1.0,2.5;4.0,0.8;radius;Radius;"..tostring (radius).."]\n"..
"button[5.5,2.5;2.0,0.8;setradius;Set]\n"..
"checkbox[1.0,4.4;entities;Entities;"..entities.."]\n"..
"checkbox[1.0,5.4;players;Players;"..players.."]\n"..
"checkbox[1.0,6.4;drops;Drops;"..drops.."]\n"..
"checkbox[1.0,7.4;nodes;Nodes;"..nodes.."]\n"..
"textlist[4.875,4.0;5.875,4.0;mode;All,Forward,Up,Down;"..tostring (mode)..";false]"
end
local function update_form_spec (pos)
local node = minetest.get_node (pos)
local meta = minetest.get_meta (pos)
if node and meta then
local is_off = node.name == "lwcomponents:detector" or
node.name == "lwcomponents:detector_locked"
meta:set_string ("formspec",
get_form_spec (is_off,
meta:get_int ("radius"),
meta:get_string ("entities"),
meta:get_string ("players"),
meta:get_string ("drops"),
meta:get_string ("nodes"),
meta:get_int ("mode")))
end
end
local function start_detector (pos)
local node = minetest.get_node (pos)
if node then
if node.name == "lwcomponents:detector" then
node.name = "lwcomponents:detector_on"
minetest.swap_node (pos, node)
minetest.get_node_timer (pos):start (detect_interval)
update_form_spec (pos)
elseif node.name == "lwcomponents:detector_locked" then
node.name = "lwcomponents:detector_locked_on"
minetest.swap_node (pos, node)
minetest.get_node_timer (pos):start (detect_interval)
update_form_spec (pos)
end
end
end
local function stop_detector (pos)
local node = minetest.get_node (pos)
if node then
if node.name == "lwcomponents:detector_on" or
node.name == "lwcomponents:detector_on_on" then
node.name = "lwcomponents:detector"
minetest.swap_node (pos, node)
minetest.get_node_timer (pos):stop ()
mesecons_off (pos)
update_form_spec (pos)
elseif node.name == "lwcomponents:detector_locked_on" or
node.name == "lwcomponents:detector_locked_on_on" then
node.name = "lwcomponents:detector_locked"
minetest.swap_node (pos, node)
minetest.get_node_timer (pos):stop ()
mesecons_off (pos)
update_form_spec (pos)
end
end
end
local function on_destruct (pos)
minetest.get_node_timer (pos):stop ()
mesecons_off (pos)
end
local function after_place_node (pos, placer, itemstack, pointed_thing)
local meta = minetest.get_meta (pos)
local is_off = itemstack and (itemstack:get_name () == "lwcomponents:detector" or
itemstack:get_name () == "lwcomponents:detector_locked")
meta:set_string ("formspec", get_form_spec (is_off, 1, 0, 0, 0, 0, 1))
meta:set_string ("entities", "false")
meta:set_string ("players", "false")
meta:set_string ("drops", "false")
meta:set_string ("nodes", "false")
meta:set_int ("mode", 1)
meta:set_int ("radius", 1)
meta:set_int ("power_on", 0)
-- If return true no item is taken from itemstack
return false
end
local function after_place_node_locked (pos, placer, itemstack, pointed_thing)
after_place_node (pos, placer, itemstack, pointed_thing)
if placer and placer:is_player () then
local meta = minetest.get_meta (pos)
meta:set_string ("owner", placer:get_player_name ())
meta:set_string ("infotext", "Detector (owned by "..placer:get_player_name ()..")")
end
-- If return true no item is taken from itemstack
return false
end
local function on_receive_fields (pos, formname, fields, sender)
if not utils.can_interact_with_node (pos, sender) then
return
end
if fields.setchannel then
local meta = minetest.get_meta (pos)
if meta then
meta:set_string ("channel", fields.channel)
end
end
if fields.setradius then
local meta = minetest.get_meta (pos)
if meta then
local radius = math.min (math.max (tonumber (fields.radius) or 1, 1), 5)
meta:set_int ("radius", radius)
update_form_spec (pos)
end
end
if fields.start then
start_detector (pos)
end
if fields.stop then
stop_detector (pos)
end
if fields.entities ~= nil then
local meta = minetest.get_meta (pos)
if meta then
meta:set_string ("entities", fields.entities)
update_form_spec (pos)
end
end
if fields.players ~= nil then
local meta = minetest.get_meta (pos)
if meta then
meta:set_string ("players", fields.players)
update_form_spec (pos)
end
end
if fields.drops ~= nil then
local meta = minetest.get_meta (pos)
if meta then
meta:set_string ("drops", fields.drops)
update_form_spec (pos)
end
end
if fields.nodes ~= nil then
local meta = minetest.get_meta (pos)
if meta then
meta:set_string ("nodes", fields.nodes)
update_form_spec (pos)
end
end
if fields.mode then
local event = minetest.explode_textlist_event (fields.mode)
if event.type == "CHG" then
local meta = minetest.get_meta (pos)
if meta then
meta:set_int ("mode", event.index)
update_form_spec (pos)
end
end
end
end
local function can_dig (pos, player)
if not utils.can_interact_with_node (pos, player) then
return false
end
return true
end
local function on_blast (pos, intensity)
local meta = minetest.get_meta (pos)
if meta then
if intensity >= 1.0 then
on_destruct (pos)
minetest.remove_node (pos)
else -- intensity < 1.0
local node = minetest.get_node_or_nil (pos)
if node then
local items = minetest.get_node_drops (node, nil)
if items and #items > 0 then
local stack = ItemStack (items[1])
if stack then
utils.item_drop (stack, nil, pos)
on_destruct (pos)
minetest.remove_node (pos)
end
end
end
end
end
end
local function on_timer (pos, elapsed)
detect (pos)
return true
end
local function on_rightclick (pos, node, clicker, itemstack, pointed_thing)
if not utils.can_interact_with_node (pos, clicker) then
if clicker and clicker:is_player () then
local owner = "<unknown>"
local meta = minetest.get_meta (pos)
if meta then
owner = meta:get_string ("owner")
end
local spec =
"formspec_version[3]"..
"size[8.0,4.0,false]"..
"label[1.0,1.0;Owned by "..minetest.formspec_escape (owner).."]"..
"button_exit[3.0,2.0;2.0,1.0;close;Close]"
minetest.show_formspec (clicker:get_player_name (),
"lwcomponents:component_privately_owned",
spec)
end
end
return itemstack
end
local function digilines_support ()
if utils.digilines_supported then
return
{
wire =
{
rules = utils.digilines_default_rules,
},
effector =
{
action = function (pos, node, channel, msg)
local meta = minetest.get_meta(pos)
if meta then
local this_channel = meta:get_string ("channel")
if this_channel ~= "" and this_channel == channel and
type (msg) == "string" then
local m = { }
for w in string.gmatch(msg, "[^%s]+") do
m[#m + 1] = w
end
if m[1] == "start" then
start_detector (pos)
elseif m[1] == "stop" then
stop_detector (pos)
elseif m[1] == "radius" then
local radius = math.min (math.max (tonumber (m[2] or 1) or 1, 1), 5)
meta:set_int ("radius", radius)
update_form_spec (pos)
elseif m[1] == "entities" then
meta:set_string ("entities", ((m[2] == "true") and "true") or "false")
update_form_spec (pos)
elseif m[1] == "players" then
meta:set_string ("players", ((m[2] == "true") and "true") or "false")
update_form_spec (pos)
elseif m[1] == "drops" then
meta:set_string ("drops", ((m[2] == "true") and "true") or "false")
update_form_spec (pos)
elseif m[1] == "nodes" then
meta:set_string ("nodes", ((m[2] == "true") and "true") or "false")
update_form_spec (pos)
elseif m[1] == "mode" then
if m[2] == "all" then
meta:set_int ("mode", 1)
update_form_spec (pos)
elseif m[2] == "forward" then
meta:set_int ("mode", 2)
update_form_spec (pos)
elseif m[2] == "up" then
meta:set_int ("mode", 3)
update_form_spec (pos)
elseif m[2] == "down" then
meta:set_int ("mode", 4)
update_form_spec (pos)
end
end
end
end
end,
}
}
end
return nil
end
local function mesecon_support_on ()
if utils.mesecon_supported then
return
{
receptor =
{
state = utils.mesecon_state_on,
rules = utils.mesecon_default_rules
}
}
end
return nil
end
local function mesecon_support_off ()
if utils.mesecon_supported then
return
{
receptor =
{
state = utils.mesecon_state_off,
rules = utils.mesecon_default_rules
}
}
end
return nil
end
minetest.register_node("lwcomponents:detector", {
description = S("Detector"),
tiles = { "lwdetector_face.png", "lwdetector_face.png", "lwdetector.png",
"lwdetector.png", "lwdetector.png", "lwdetector_face.png"},
is_ground_content = false,
groups = { cracky = 3, wires_connect = 1 },
--sounds = default.node_sound_stone_defaults (),
paramtype = "none",
param1 = 0,
paramtype2 = "facedir",
param2 = 1,
floodable = false,
drop = "lwcomponents:detector",
_digistuff_channelcopier_fieldname = "channel",
mesecons = mesecon_support_off (),
digiline = digilines_support (),
on_destruct = on_destruct,
on_receive_fields = on_receive_fields,
can_dig = can_dig,
after_place_node = after_place_node,
on_blast = on_blast,
on_timer = on_timer,
on_rightclick = on_rightclick
})
minetest.register_node("lwcomponents:detector_locked", {
description = S("Detector (locked)"),
tiles = { "lwdetector_face.png", "lwdetector_face.png", "lwdetector.png",
"lwdetector.png", "lwdetector.png", "lwdetector_face.png"},
is_ground_content = false,
groups = { cracky = 3, wires_connect = 1 },
--sounds = default.node_sound_stone_defaults (),
paramtype = "none",
param1 = 0,
paramtype2 = "facedir",
param2 = 1,
floodable = false,
drop = "lwcomponents:detector_locked",
_digistuff_channelcopier_fieldname = "channel",
mesecons = mesecon_support_off (),
digiline = digilines_support (),
on_destruct = on_destruct,
on_receive_fields = on_receive_fields,
can_dig = can_dig,
after_place_node = after_place_node_locked,
on_blast = on_blast,
on_timer = on_timer,
on_rightclick = on_rightclick
})
minetest.register_node("lwcomponents:detector_on", {
description = S("Detector"),
tiles = { "lwdetector_face_on.png", "lwdetector_face_on.png", "lwdetector.png",
"lwdetector.png", "lwdetector.png", "lwdetector_face_on.png"},
is_ground_content = false,
groups = { cracky = 3, not_in_creative_inventory = 1, wires_connect = 1 },
--sounds = default.node_sound_stone_defaults (),
paramtype = "none",
param1 = 0,
paramtype2 = "facedir",
param2 = 1,
floodable = false,
drop = "lwcomponents:detector",
_digistuff_channelcopier_fieldname = "channel",
mesecons = mesecon_support_off (),
digiline = digilines_support (),
on_destruct = on_destruct,
on_receive_fields = on_receive_fields,
can_dig = can_dig,
after_place_node = after_place_node,
on_blast = on_blast,
on_timer = on_timer,
on_rightclick = on_rightclick
})
minetest.register_node("lwcomponents:detector_locked_on", {
description = S("Detector (locked)"),
tiles = { "lwdetector_face_on.png", "lwdetector_face_on.png", "lwdetector.png",
"lwdetector.png", "lwdetector.png", "lwdetector_face_on.png"},
is_ground_content = false,
groups = { cracky = 3, not_in_creative_inventory = 1, wires_connect = 1 },
--sounds = default.node_sound_stone_defaults (),
paramtype = "none",
param1 = 0,
paramtype2 = "facedir",
param2 = 1,
floodable = false,
drop = "lwcomponents:detector_locked",
_digistuff_channelcopier_fieldname = "channel",
mesecons = mesecon_support_off (),
digiline = digilines_support (),
on_destruct = on_destruct,
on_receive_fields = on_receive_fields,
can_dig = can_dig,
after_place_node = after_place_node_locked,
on_blast = on_blast,
on_timer = on_timer,
on_rightclick = on_rightclick
})
minetest.register_node("lwcomponents:detector_on_on", {
description = S("Detector"),
tiles = { "lwdetector_face_on.png", "lwdetector_face_on.png", "lwdetector.png",
"lwdetector.png", "lwdetector.png", "lwdetector_face_on.png"},
is_ground_content = false,
groups = { cracky = 3, not_in_creative_inventory = 1, wires_connect = 1 },
--sounds = default.node_sound_stone_defaults (),
paramtype = "none",
param1 = 0,
paramtype2 = "facedir",
param2 = 1,
floodable = false,
drop = "lwcomponents:detector",
_digistuff_channelcopier_fieldname = "channel",
mesecons = mesecon_support_on (),
digiline = digilines_support (),
on_destruct = on_destruct,
on_receive_fields = on_receive_fields,
can_dig = can_dig,
after_place_node = after_place_node,
on_blast = on_blast,
on_timer = on_timer,
on_rightclick = on_rightclick
})
minetest.register_node("lwcomponents:detector_locked_on_on", {
description = S("Detector (locked)"),
tiles = { "lwdetector_face_on.png", "lwdetector_face_on.png", "lwdetector.png",
"lwdetector.png", "lwdetector.png", "lwdetector_face_on.png"},
is_ground_content = false,
groups = { cracky = 3, not_in_creative_inventory = 1, wires_connect = 1 },
--sounds = default.node_sound_stone_defaults (),
paramtype = "none",
param1 = 0,
paramtype2 = "facedir",
param2 = 1,
floodable = false,
drop = "lwcomponents:detector_locked",
_digistuff_channelcopier_fieldname = "channel",
mesecons = mesecon_support_on (),
digiline = digilines_support (),
on_destruct = on_destruct,
on_receive_fields = on_receive_fields,
can_dig = can_dig,
after_place_node = after_place_node_locked,
on_blast = on_blast,
on_timer = on_timer,
on_rightclick = on_rightclick
})
end -- utils.digilines_supported or utils.mesecon_supported
--

378
lwcomponents/digiswitch.lua Normal file
View file

@ -0,0 +1,378 @@
local utils = ...
local S = utils.S
if utils.digilines_supported and utils.mesecon_supported then
local function get_mesecon_rule_for_side (side)
if side == "white" then
return { { x = 0, y = 1, z = 0 } }
elseif side == "black" then
return { { x = 0, y = -1, z = 0 } }
elseif side == "red" then
return { { x = -1, y = 0, z = 0 } }
elseif side == "green" then
return { { x = 1, y = 0, z = 0 } }
elseif side == "blue" then
return { { x = 0, y = 0, z = -1 } }
elseif side == "yellow" then
return { { x = 0, y = 0, z = 1 } }
elseif side == "switch" then
return nil
else
return
{
{ x = 1, y = 0, z = 0 },
{ x = -1, y = 0, z = 0 },
{ x = 0, y = 0, z = 1 },
{ x = 0, y = 0, z = -1 },
{ x = 0, y = 1, z = 0 },
{ x = 0, y = -1, z = 0 },
}
end
end
local side_bits =
{
["white"] = 0,
["black"] = 1,
["red"] = 2,
["green"] = 3,
["blue"] = 4,
["yellow"] = 5
}
local function get_side_bit (side)
if side then
if side == "switch" then
return 64
end
local bit = side_bits[side]
if bit then
return math.pow (2, bit)
end
end
return 63
end
local function is_side_on (bits, side)
local bit = get_side_bit (side)
for i = 0, 6, 1 do
if (bit % 2) == 1 and (bits % 2) ~= 1 then
return false
end
bit = math.floor (bit / 2)
bits = math.floor (bits / 2)
end
return true
end
local function set_side_bit (bits, side, on)
local bit = get_side_bit (side)
local result = 0
for i = 0, 6, 1 do
if (bit % 2) == 1 then
if on then
result = result + math.pow (2, i)
end
elseif (bits % 2) == 1 then
result = result + math.pow (2, i)
end
bit = math.floor (bit / 2)
bits = math.floor (bits / 2)
end
return result
end
local function get_powered_rules (node)
local rules = { }
if is_side_on (node.param1, "switch") then
rules = table.copy (utils.mesecon_default_rules)
if is_side_on (node.param1, "white") then
rules[#rules + 1] = get_mesecon_rule_for_side ("white")[1]
end
if is_side_on (node.param1, "black") then
rules[#rules + 1] = get_mesecon_rule_for_side ("black")[1]
end
else
local sides =
{
"white",
"black",
"red",
"green",
"blue",
"yellow",
}
for _, side in ipairs (sides) do
if is_side_on (node.param1, side) then
rules[#rules + 1] = get_mesecon_rule_for_side (side)[1]
end
end
end
return rules
end
local function get_node_name (node)
if node.param1 ~= 0 then
return "lwcomponents:digiswitch_on"
end
return "lwcomponents:digiswitch"
end
local function switch_on (pos, side)
utils.mesecon_receptor_on (pos, get_mesecon_rule_for_side (side))
local node = utils.get_far_node (pos)
if node then
node.param1 = set_side_bit (node.param1, side, true)
node.name = get_node_name (node)
minetest.swap_node (pos, node)
end
end
local function switch_off (pos, side)
utils.mesecon_receptor_off (pos, get_mesecon_rule_for_side (side))
local node = utils.get_far_node (pos)
if node then
node.param1 = set_side_bit (node.param1, side, false)
node.name = get_node_name (node)
minetest.swap_node (pos, node)
end
end
local function digilines_support ()
return
{
wire =
{
rules =
{
{ x = 0, y = 0, z = -1 },
{ x = 1, y = 0, z = 0 },
{ x = -1, y = 0, z = 0 },
{ x = 0, y = 0, z = 1 },
{ x = 1, y = 1, z = 0 },
{ x = 1, y = -1, z = 0 },
{ x = -1, y = 1, z = 0 },
{ x = -1, y = -1, z = 0 },
{ x = 0, y = 1, z = 1 },
{ x = 0, y = -1, z = 1 },
{ x = 0, y = 1, z = -1 },
{ x = 0, y = -1, z = -1 },
{ x = 0, y = 1, z = 0 },
{ x = 0, y = -1, z = 0 }
}
},
effector =
{
action = function (pos, node, channel, msg)
local meta = minetest.get_meta(pos)
if meta then
local mychannel = meta:get_string ("channel")
if mychannel ~= "" and mychannel == channel then
if type (msg) == "string" then
local words = { }
for word in string.gmatch (msg, "%S+") do
words[#words + 1] = word
end
if words[1] == "on" then
switch_on (pos, words[2])
elseif words[1] == "off" then
switch_off (pos, words[2])
end
end
end
end
end,
}
}
end
local function mesecon_support ()
return
{
receptor =
{
state = mesecon.state.off,
rules =
{
{ x = 0, y = 0, z = -1 },
{ x = 1, y = 0, z = 0 },
{ x = -1, y = 0, z = 0 },
{ x = 0, y = 0, z = 1 },
{ x = 1, y = 1, z = 0 },
{ x = 1, y = -1, z = 0 },
{ x = -1, y = 1, z = 0 },
{ x = -1, y = -1, z = 0 },
{ x = 0, y = 1, z = 1 },
{ x = 0, y = -1, z = 1 },
{ x = 0, y = 1, z = -1 },
{ x = 0, y = -1, z = -1 },
{ x = 0, y = 1, z = 0 },
{ x = 0, y = -1, z = 0 }
}
},
}
end
local function mesecon_support_on ()
return
{
receptor =
{
state = mesecon.state.on,
rules = get_powered_rules
},
}
end
local function on_construct (pos)
local meta = minetest.get_meta (pos)
if meta then
meta:set_string ("channel", "")
local formspec =
"formspec_version[3]\n"..
"size[6.0,4.0]\n"..
"field[1.0,0.8;4.0,1.0;channel;Channel;${channel}]\n"..
"button_exit[2.0,2.5;2.0,1.0;set;Set]\n"
meta:set_string ("formspec", formspec)
end
end
local function on_destruct (pos)
local node = utils.get_far_node (pos)
if node then
local rules = get_powered_rules (node)
if #rules > 0 then
utils.mesecon_receptor_off (pos, rules)
end
end
end
local function on_receive_fields (pos, formname, fields, sender)
if fields.channel then
local meta = minetest.get_meta (pos)
if meta then
meta:set_string ("channel", fields.channel or "")
end
end
end
minetest.register_node ("lwcomponents:digiswitch", {
description = S("Digilines Switch"),
tiles = { "lwdigiswitch_white.png", "lwdigiswitch_black.png",
"lwdigiswitch_green.png", "lwdigiswitch_red.png",
"lwdigiswitch_yellow.png", "lwdigiswitch_blue.png" },
sunlight_propagates = false,
drawtype = "normal",
node_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
}
},
paramtype = "none",
param1 = 0,
groups = { cracky = 2, oddly_breakable_by_hand = 2, wires_connect = 1 },
--sounds = default.node_sound_stone_defaults (),
mesecons = mesecon_support (),
digiline = digilines_support (),
_digistuff_channelcopier_fieldname = "channel",
on_construct = on_construct,
on_destruct = on_destruct,
on_receive_fields = on_receive_fields,
})
minetest.register_node ("lwcomponents:digiswitch_on", {
description = S("Digilines Switch"),
tiles = { "lwdigiswitch_white.png", "lwdigiswitch_black.png",
"lwdigiswitch_green.png", "lwdigiswitch_red.png",
"lwdigiswitch_yellow.png", "lwdigiswitch_blue.png" },
sunlight_propagates = false,
drawtype = "normal",
node_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
}
},
paramtype = "none",
param1 = 0,
groups = { cracky = 2, oddly_breakable_by_hand = 2, not_in_creative_inventory = 1, wires_connect = 1 },
--sounds = default.node_sound_stone_defaults (),
mesecons = mesecon_support_on (),
digiline = digilines_support (),
_digistuff_channelcopier_fieldname = "channel",
on_construct = on_construct,
on_destruct = on_destruct,
on_receive_fields = on_receive_fields,
})
end -- utils.digilines_supported and utils.mesecon_supported

600
lwcomponents/dispenser.lua Normal file
View file

@ -0,0 +1,600 @@
local utils = ...
local S = utils.S
if utils.digilines_supported or utils.mesecon_supported then
local dispenser_force = 25
local function dispense_dir (node)
if node.param2 == 0 then
return { x = 0, y = 0, z = -1 }
elseif node.param2 == 1 then
return { x = -1, y = 0, z = 0 }
elseif node.param2 == 2 then
return { x = 0, y = 0, z = 1 }
elseif node.param2 == 3 then
return { x = 1, y = 0, z = 0 }
else
return { x = 0, y = 0, z = 0 }
end
end
local function dispense_pos (pos, node)
if node.param2 == 0 then
return { x = pos.x, y = pos.y, z = pos.z - 1 }
elseif node.param2 == 1 then
return { x = pos.x - 1, y = pos.y, z = pos.z }
elseif node.param2 == 2 then
return { x = pos.x, y = pos.y, z = pos.z + 1 }
elseif node.param2 == 3 then
return { x = pos.x + 1, y = pos.y, z = pos.z }
else
return { x = pos.x, y = pos.y, z = pos.z }
end
end
local function dispense_velocity (node)
local tilt = (math.random (1 , 2001) - 1001) / 1000
local sway = (math.random (1 , 4001) - 2001) / 1000
if node.param2 == 0 then
return { x = sway, y = tilt, z = -dispenser_force }
elseif node.param2 == 1 then
return { x = -dispenser_force, y = tilt, z = sway }
elseif node.param2 == 2 then
return { x = sway, y = tilt, z = dispenser_force }
elseif node.param2 == 3 then
return { x = dispenser_force, y = tilt, z = sway }
else
return { x = 0, y = 0, z = 0 }
end
end
local function send_dispense_message (pos, slot, name)
if utils.digilines_supported then
local meta = minetest.get_meta (pos)
if meta then
local channel = meta:get_string ("channel")
if channel:len () > 0 then
utils.digilines_receptor_send (pos,
utils.digilines_default_rules,
channel,
{ action = "dispense",
name = name,
slot = slot })
end
end
end
end
-- slot:
-- nil - next item, no dispense if empty
-- number - 1 item from slot, no dispense if empty
-- string - name of item to dispense, no dispense if none
local function dispense_item (pos, node, slot)
local meta = minetest.get_meta (pos)
if meta then
local inv = meta:get_inventory ()
if inv then
if not slot then
local slots = inv:get_size ("main")
for i = 1, slots do
local stack = inv:get_stack ("main", i)
if not stack:is_empty () and stack:get_count () > 0 then
slot = i
break
end
end
elseif type (slot) == "string" then
local name = slot
slot = nil
local slots = inv:get_size ("main")
for i = 1, slots do
local stack = inv:get_stack ("main", i)
if not stack:is_empty () and stack:get_count () > 0 then
if name == stack:get_name () then
slot = i
break
end
end
end
else
slot = tonumber (slot)
end
if slot then
local stack = inv:get_stack ("main", slot)
if not stack:is_empty () and stack:get_count () > 0 then
local name = stack:get_name ()
local item = ItemStack (stack)
if item then
item:set_count (1)
local spawn_pos = dispense_pos (pos, node)
local owner = meta:get_string ("owner")
local obj = nil
local cancel
if utils.settings.spawn_mobs then
obj, cancel = utils.spawn_registered (name,
spawn_pos,
item,
owner,
pos,
dispense_dir (node),
dispenser_force)
if obj == nil and cancel then
return false
end
end
if not obj then
obj = minetest.add_item (spawn_pos, item)
if obj then
obj:set_velocity (dispense_velocity (node))
end
end
if obj then
stack:set_count (stack:get_count () - 1)
inv:set_stack ("main", slot, stack)
send_dispense_message (pos, slot, name)
return true, slot, name
end
end
end
end
end
end
return false
end
local function after_place_base (pos, placer, itemstack, pointed_thing)
local meta = minetest.get_meta (pos)
local spec =
"formspec_version[3]\n"..
"size[11.75,13.75;true]\n"..
"field[1.0,1.0;4.0,0.8;channel;Channel;${channel}]\n"..
"button[5.5,1.0;2.0,0.8;setchannel;Set]\n"..
"list[context;main;3.5,2.5;4,4;]\n"..
"list[current_player;main;1.0,8.0;8,4;]\n"..
"listring[]"
meta:set_string ("inventory", "{ main = { } }")
meta:set_string ("formspec", spec)
local inv = meta:get_inventory ()
inv:set_size ("main", 16)
inv:set_width ("main", 4)
end
local function after_place_node (pos, placer, itemstack, pointed_thing)
after_place_base (pos, placer, itemstack, pointed_thing)
utils.pipeworks_after_place (pos)
-- If return true no item is taken from itemstack
return false
end
local function after_place_node_locked (pos, placer, itemstack, pointed_thing)
after_place_base (pos, placer, itemstack, pointed_thing)
if placer and placer:is_player () then
local meta = minetest.get_meta (pos)
meta:set_string ("owner", placer:get_player_name ())
meta:set_string ("infotext", "Dispenser (owned by "..placer:get_player_name ()..")")
end
utils.pipeworks_after_place (pos)
-- If return true no item is taken from itemstack
return false
end
local function on_receive_fields (pos, formname, fields, sender)
if not utils.can_interact_with_node (pos, sender) then
return
end
if fields.setchannel then
local meta = minetest.get_meta (pos)
if meta then
meta:set_string ("channel", fields.channel)
end
end
end
local function can_dig (pos, player)
if not utils.can_interact_with_node (pos, player) then
return false
end
local meta = minetest.get_meta (pos)
if meta then
local inv = meta:get_inventory ()
if inv then
if not inv:is_empty ("main") then
return false
end
end
end
return true
end
local function on_blast (pos, intensity)
local meta = minetest.get_meta (pos)
if meta then
if intensity >= 1.0 then
local inv = meta:get_inventory ()
if inv then
local slots = inv:get_size ("main")
for slot = 1, slots do
local stack = inv:get_stack ("main", slot)
if stack and not stack:is_empty () then
if math.floor (math.random (0, 5)) == 3 then
utils.item_drop (stack, nil, pos)
else
utils.on_destroy (stack)
end
end
end
end
minetest.remove_node (pos)
else -- intensity < 1.0
local inv = meta:get_inventory ()
if inv then
local slots = inv:get_size ("main")
for slot = 1, slots do
local stack = inv:get_stack ("main", slot)
if stack and not stack:is_empty () then
utils.item_drop (stack, nil, pos)
end
end
end
local node = minetest.get_node_or_nil (pos)
if node then
local items = minetest.get_node_drops (node, nil)
if items and #items > 0 then
local stack = ItemStack (items[1])
if stack then
utils.item_drop (stack, nil, pos)
minetest.remove_node (pos)
end
end
end
end
end
end
local function on_rightclick (pos, node, clicker, itemstack, pointed_thing)
if not utils.can_interact_with_node (pos, clicker) then
if clicker and clicker:is_player () then
local owner = "<unknown>"
local meta = minetest.get_meta (pos)
if meta then
owner = meta:get_string ("owner")
end
local spec =
"formspec_version[3]"..
"size[8.0,4.0,false]"..
"label[1.0,1.0;Owned by "..minetest.formspec_escape (owner).."]"..
"button_exit[3.0,2.0;2.0,1.0;close;Close]"
minetest.show_formspec (clicker:get_player_name (),
"lwcomponents:component_privately_owned",
spec)
end
end
return itemstack
end
local function digilines_support ()
if utils.digilines_supported then
return
{
wire =
{
rules = utils.digilines_default_rules,
},
effector =
{
action = function (pos, node, channel, msg)
local meta = minetest.get_meta(pos)
if meta then
local this_channel = meta:get_string ("channel")
if this_channel ~= "" and this_channel == channel and
type (msg) == "string" then
local m = { }
for w in string.gmatch(msg, "[^%s]+") do
m[#m + 1] = w
end
if m[1] == "dispense" then
if m[2] and tonumber (m[2]) then
m[2] = tonumber (m[2])
end
dispense_item (pos, node, m[2])
end
end
end
end,
}
}
end
return nil
end
local function mesecon_support ()
if utils.mesecon_supported then
return
{
effector =
{
rules = utils.mesecon_flat_rules,
action_on = function (pos, node)
dispense_item (pos, node)
end
}
}
end
return nil
end
local function pipeworks_support ()
if utils.pipeworks_supported then
return
{
priority = 100,
input_inventory = "main",
connect_sides = { left = 1, right = 1, back = 1, bottom = 1, top = 1 },
insert_object = function (pos, node, stack, direction)
local meta = minetest.get_meta (pos)
local inv = (meta and meta:get_inventory ()) or nil
if inv then
return inv:add_item ("main", stack)
end
return stack
end,
can_insert = function (pos, node, stack, direction)
local meta = minetest.get_meta (pos)
local inv = (meta and meta:get_inventory ()) or nil
if inv then
return inv:room_for_item ("main", stack)
end
return false
end,
can_remove = function (pos, node, stack, dir)
-- returns the maximum number of items of that stack that can be removed
local meta = minetest.get_meta (pos)
local inv = (meta and meta:get_inventory ()) or nil
if inv then
local slots = inv:get_size ("main")
for i = 1, slots, 1 do
local s = inv:get_stack ("main", i)
if s and not s:is_empty () and utils.is_same_item (stack, s) then
return s:get_count ()
end
end
end
return 0
end,
remove_items = function (pos, node, stack, dir, count)
-- removes count items and returns them
local meta = minetest.get_meta (pos)
local inv = (meta and meta:get_inventory ()) or nil
local left = count
if inv then
local slots = inv:get_size ("main")
for i = 1, slots, 1 do
local s = inv:get_stack ("main", i)
if s and not s:is_empty () and utils.is_same_item (s, stack) then
if s:get_count () > left then
s:set_count (s:get_count () - left)
inv:set_stack ("main", i, s)
left = 0
else
left = left - s:get_count ()
inv:set_stack ("main", i, nil)
end
end
if left == 0 then
break
end
end
end
local result = ItemStack (stack)
result:set_count (count - left)
return result
end
}
end
return nil
end
local dispenser_groups = { cracky = 3, wires_connect = 1 }
if utils.pipeworks_supported then
dispenser_groups.tubedevice = 1
dispenser_groups.tubedevice_receiver = 1
end
minetest.register_node("lwcomponents:dispenser", {
description = S("Dispenser"),
tiles = { "lwdispenser.png", "lwdispenser.png", "lwdispenser.png",
"lwdispenser.png", "lwdispenser.png", "lwdispenser_face.png"},
is_ground_content = false,
groups = table.copy (dispenser_groups),
--sounds = default.node_sound_stone_defaults (),
paramtype = "none",
param1 = 0,
paramtype2 = "facedir",
param2 = 1,
floodable = false,
_digistuff_channelcopier_fieldname = "channel",
mesecons = mesecon_support (),
digiline = digilines_support (),
tube = pipeworks_support (),
on_receive_fields = on_receive_fields,
after_place_node = after_place_node,
can_dig = can_dig,
after_dig_node = utils.pipeworks_after_dig,
on_blast = on_blast,
on_rightclick = on_rightclick
})
minetest.register_node("lwcomponents:dispenser_locked", {
description = S("Dispenser (locked)"),
tiles = { "lwdispenser.png", "lwdispenser.png", "lwdispenser.png",
"lwdispenser.png", "lwdispenser.png", "lwdispenser_face.png"},
is_ground_content = false,
groups = table.copy (dispenser_groups),
--sounds = default.node_sound_stone_defaults (),
paramtype = "none",
param1 = 0,
paramtype2 = "facedir",
param2 = 1,
floodable = false,
_digistuff_channelcopier_fieldname = "channel",
mesecons = mesecon_support (),
digiline = digilines_support (),
tube = pipeworks_support (),
on_receive_fields = on_receive_fields,
after_place_node = after_place_node_locked,
can_dig = can_dig,
after_dig_node = utils.pipeworks_after_dig,
on_blast = on_blast,
on_rightclick = on_rightclick
})
utils.hopper_add_container({
{"top", "lwcomponents:dispenser", "main"}, -- take items from above into hopper below
{"bottom", "lwcomponents:dispenser", "main"}, -- insert items below from hopper above
{"side", "lwcomponents:dispenser", "main"}, -- insert items from hopper at side
})
utils.hopper_add_container({
{"top", "lwcomponents:dispenser_locked", "main"}, -- take items from above into hopper below
{"bottom", "lwcomponents:dispenser_locked", "main"}, -- insert items below from hopper above
{"side", "lwcomponents:dispenser_locked", "main"}, -- insert items from hopper at side
})
end -- utils.digilines_supported or utils.mesecon_supported
--