Compare commits

...

18 Commits

Author SHA1 Message Date
loosewheel
de9638b85b Add files via upload 2021-11-21 02:12:13 +10:00
loosewheel
f728c4d246 Add files via upload 2021-11-21 02:10:31 +10:00
loosewheel
92138ff625 Add files via upload 2021-11-21 02:09:17 +10:00
loosewheel
09dc9951ab Add files via upload 2021-11-19 10:37:11 +10:00
loosewheel
b3604d044d Add files via upload 2021-11-19 10:36:28 +10:00
loosewheel
d91c820ac9 Add files via upload 2021-11-19 10:34:48 +10:00
loosewheel
69135632d4 Add files via upload 2021-11-16 04:45:47 +10:00
loosewheel
582ac287f8 Add files via upload 2021-11-16 04:44:02 +10:00
loosewheel
0248d0929b Add files via upload 2021-11-16 04:42:28 +10:00
loosewheel
c30e5b6947 Add files via upload 2021-11-14 06:05:23 +10:00
loosewheel
92a065b591 Add files via upload 2021-11-14 06:04:46 +10:00
loosewheel
af812515bb Create api.txt 2021-11-14 06:00:58 +10:00
loosewheel
0d27b384a2 Add files via upload 2021-11-14 01:52:55 +10:00
loosewheel
7b6b0176a7 Add files via upload 2021-11-14 00:17:20 +10:00
loosewheel
f475b498e5 Add files via upload 2021-11-14 00:16:22 +10:00
loosewheel
3adc0fcf70 Add files via upload 2021-11-13 23:12:12 +10:00
loosewheel
7ed06d7e94 Add files via upload 2021-11-13 23:11:13 +10:00
loosewheel
35ec093f88 Add files via upload 2021-11-13 23:09:34 +10:00
74 changed files with 4824 additions and 434 deletions

12
api.lua Normal file
View File

@@ -0,0 +1,12 @@
local utils = ...
-- function (spawn_pos, itemstack, owner, spawner_pos, spawner_dir, force)
function lwcomponents.register_spawner (itemname, spawn_func)
return utils.register_spawner (itemname, spawn_func)
end
--

727
breaker.lua Normal file
View File

@@ -0,0 +1,727 @@
local utils = ...
local S = utils.S
if utils.digilines_supported or utils.mesecon_supported then
local break_interval = 1.0
local function get_breaker_side (pos, param2, side)
local base = nil
if side == "left" then
base = { x = -1, y = pos.y, z = 0 }
elseif side == "right" then
base = { x = 1, y = pos.y, z = 0 }
elseif side == "back" then
base = { x = 0, y = pos.y, z = -1 }
else -- "front"
base = { x = 0, y = pos.y, z = 1 }
end
if param2 == 3 then -- +x
return { x = base.z + pos.x, y = base.y, z = (base.x * -1) + pos.z }
elseif param2 == 0 then -- -z
return { x = (base.x * -1) + pos.x, y = base.y, z = (base.z * -1) + pos.z }
elseif param2 == 1 then -- -x
return { x = (base.z * -1) + pos.x, y = base.y, z = base.x + pos.z }
else -- param2 == 2 +z
return { x = base.x + pos.x, y = base.y, z = base.z + pos.z }
end
end
local function get_break_pos (pos, param2, range)
local breakpos = { x = pos.x, y = pos.y, z = pos.z }
for i = 1, range do
breakpos = get_breaker_side (breakpos, param2, "front")
if i < range then
local node = minetest.get_node_or_nil (breakpos)
if not node or node.name ~= "air" then
return nil
end
end
end
return breakpos
end
local function send_break_message (pos, action, name, range)
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 = action,
name = name,
range = range })
end
end
end
end
local function get_tool (pos)
local meta = minetest.get_meta (pos)
if meta then
local inv = meta:get_inventory ()
if inv then
local stack = inv:get_stack ("tool", 1)
if stack and not stack:is_empty () then
return stack
end
end
end
return nil
end
local function add_wear (pos, wear)
if wear > 0 then
local meta = minetest.get_meta (pos)
if meta then
local inv = meta:get_inventory ()
if inv then
local stack = inv:get_stack ("tool", 1)
if stack and not stack:is_empty () then
local cur_wear = stack:get_wear ()
if (cur_wear + wear) >= 65535 then
inv:set_stack ("tool", 1, nil)
send_break_message (pos, "tool", stack:get_name ())
else
stack:set_wear (cur_wear + wear)
inv:set_stack ("tool", 1, stack)
end
end
end
end
end
end
local function can_break_node (pos, breakpos)
local node = minetest.get_node (pos)
if node then
local dig_node = minetest.get_node_or_nil (breakpos)
if dig_node and dig_node.name ~= "air" then
local node_def = minetest.registered_nodes[dig_node.name]
if node_def then
-- try tool first
local tool = get_tool (pos)
if tool then
local dig_params = nil
local tool_def = minetest.registered_items[tool:get_name ()]
if tool_def then
dig_params =
minetest.get_dig_params (node_def.groups,
tool_def.tool_capabilities)
if dig_params.diggable then
return true, tool:get_name (), dig_params.wear
end
end
end
-- then try hand
dig_params =
minetest.get_dig_params (node_def.groups,
minetest.registered_items[""].tool_capabilities)
if dig_params.diggable then
return true, nil, 0
end
end
end
end
return false
end
local function dig_node (pos, toolname)
local node = minetest.get_node_or_nil (pos)
local dig = false
local drops = nil
if toolname == true then
dig = true
toolname = nil
end
if node and node.name ~= "air" and node.name ~= "ignore" then
local def = utils.find_item_def (node.name)
if not dig then
if def and def.can_dig then
local result, can_dig = pcall (def.can_dig, pos)
dig = ((not result) or (result and (can_dig == nil or can_dig == true)))
else
dig = true
end
end
if dig then
local items = minetest.get_node_drops (node, toolname)
if items then
drops = { }
for i = 1, #items do
drops[i] = ItemStack (items[i])
end
if def and def.preserve_metadata then
def.preserve_metadata (pos, node, minetest.get_meta (pos), drops)
end
end
if def and def.sounds and def.sounds.dug then
pcall (minetest.sound_play, def.sounds.dug, { pos = pos })
end
minetest.remove_node (pos)
end
end
return drops
end
local function break_node (pos, range)
local node = minetest.get_node_or_nil (pos)
if node then
local breakpos = get_break_pos (pos, node.param2, range)
if breakpos then
local diggable, toolname, wear = can_break_node (pos, breakpos)
if diggable then
local breaknode = minetest.get_node_or_nil (breakpos)
if breaknode and breaknode.name ~= "air" then
local drops = dig_node (breakpos, toolname)
if drops then
local break_name = breaknode.name
local eject_pos = get_breaker_side (pos, node.param2, "back")
for i = 1, #drops do
utils.item_drop (drops[i], nil, eject_pos)
end
add_wear (pos, wear)
send_break_message (pos, "break", break_name, range)
end
end
end
end
end
end
local function breaker_off (pos)
local node = minetest.get_node (pos)
if node then
if node.name == "lwcomponents:breaker_on" then
node.name = "lwcomponents:breaker"
minetest.get_node_timer (pos):stop ()
minetest.swap_node (pos, node)
elseif node.name == "lwcomponents:breaker_locked_on" then
node.name = "lwcomponents:breaker_locked"
minetest.get_node_timer (pos):stop ()
minetest.swap_node (pos, node)
end
end
end
local function breaker_on (pos, range)
local node = minetest.get_node (pos)
range = tonumber (range) or 1
if node and range < 6 and range > 0 then
if node.name == "lwcomponents:breaker" then
node.name = "lwcomponents:breaker_on"
minetest.swap_node (pos, node)
break_node (pos, range)
minetest.get_node_timer (pos):start (break_interval)
elseif node.name == "lwcomponents:breaker_locked" then
node.name = "lwcomponents:breaker_locked_on"
minetest.swap_node (pos, node)
break_node (pos, range)
minetest.get_node_timer (pos):start (break_interval)
end
end
end
local function eject_tool (pos, side)
local node = minetest.get_node (pos)
local meta = minetest.get_meta (pos)
if meta and node then
local inv = meta:get_inventory ()
if inv then
local stack = inv:get_stack ("tool", 1)
if stack and not stack:is_empty () then
utils.item_drop (stack, nil, get_breaker_side (pos, node.param2, side))
inv:set_stack ("tool", 1, nil)
end
end
end
end
local function after_place_node (pos, placer, itemstack, pointed_thing)
local meta = minetest.get_meta (pos)
local spec =
"formspec_version[3]\n"..
"size[11.75,10.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;tool;5.0,2.75;1,1;]\n"..
"list[current_player;main;1.0,5.0;8,4;]\n"..
"listring[]"
meta:set_string ("inventory", "{ tool = { } }")
meta:set_string ("formspec", spec)
local inv = meta:get_inventory ()
inv:set_size ("tool", 1)
inv:set_width ("tool", 1)
-- 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", "Dropper (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
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 ("tool") then
return false
end
end
end
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 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 ("tool")
for slot = 1, slots do
local stack = inv:get_stack ("tool", 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 ("tool")
for slot = 1, slots do
local stack = inv:get_stack ("tool", 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
preserve_metadata (pos, node, meta, { stack })
utils.item_drop (stack, nil, pos)
minetest.remove_node (pos)
end
end
end
end
end
end
local function on_timer (pos, elapsed)
breaker_off (pos)
end
local function allow_metadata_inventory_put (pos, listname, index, stack, player)
if listname == "tool" then
if stack and not stack:is_empty () then
local def = utils.find_item_def (stack:get_name ())
if def and def.tool_capabilities then
return 1
end
end
end
return 0
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] == "break" then
breaker_on (pos, m[2])
elseif m[1] == "eject" then
eject_tool (pos, m[2])
end
end
end
end,
}
}
end
return nil
end
local function mesecon_support ()
if utils.mesecon_supported then
return
{
effector =
{
rules = utils.mesecon_default_rules,
action_on = function (pos, node)
-- do something to turn the effector on
breaker_on (pos, 1)
end,
}
}
end
return nil
end
minetest.register_node("lwcomponents:breaker", {
description = S("Breaker"),
tiles = { "lwbreaker.png", "lwbreaker.png", "lwbreaker.png",
"lwbreaker.png", "lwbreaker_rear.png", "lwbreaker_face.png"},
is_ground_content = false,
groups = { cracky = 3 },
sounds = default.node_sound_stone_defaults (),
paramtype = "none",
param1 = 0,
paramtype2 = "facedir",
param2 = 1,
floodable = false,
drop = "lwcomponents:breaker",
_digistuff_channelcopier_fieldname = "channel",
mesecons = mesecon_support (),
digiline = digilines_support (),
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,
allow_metadata_inventory_put = allow_metadata_inventory_put
})
minetest.register_node("lwcomponents:breaker_locked", {
description = S("Breaker (locked)"),
tiles = { "lwbreaker.png", "lwbreaker.png", "lwbreaker.png",
"lwbreaker.png", "lwbreaker_rear.png", "lwbreaker_face.png"},
is_ground_content = false,
groups = { cracky = 3 },
sounds = default.node_sound_stone_defaults (),
paramtype = "none",
param1 = 0,
paramtype2 = "facedir",
param2 = 1,
floodable = false,
drop = "lwcomponents:breaker_locked",
_digistuff_channelcopier_fieldname = "channel",
mesecons = mesecon_support (),
digiline = digilines_support (),
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,
allow_metadata_inventory_put = allow_metadata_inventory_put
})
minetest.register_node("lwcomponents:breaker_on", {
description = S("Breaker"),
tiles = { "lwbreaker.png", "lwbreaker.png", "lwbreaker.png",
"lwbreaker.png", "lwbreaker_rear.png", "lwbreaker_face_on.png"},
is_ground_content = false,
groups = { cracky = 3, not_in_creative_inventory = 1 },
sounds = default.node_sound_stone_defaults (),
paramtype = "none",
param1 = 0,
paramtype2 = "facedir",
param2 = 1,
light_source = 3,
floodable = false,
drop = "lwcomponents:breaker",
_digistuff_channelcopier_fieldname = "channel",
mesecons = mesecon_support (),
digiline = digilines_support (),
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,
allow_metadata_inventory_put = allow_metadata_inventory_put
})
minetest.register_node("lwcomponents:breaker_locked_on", {
description = S("Breaker (locked)"),
tiles = { "lwbreaker.png", "lwbreaker.png", "lwbreaker.png",
"lwbreaker.png", "lwbreaker_rear.png", "lwbreaker_face_on.png"},
is_ground_content = false,
groups = { cracky = 3, not_in_creative_inventory = 1 },
sounds = default.node_sound_stone_defaults (),
paramtype = "none",
param1 = 0,
paramtype2 = "facedir",
param2 = 1,
light_source = 3,
floodable = false,
drop = "lwcomponents:breaker_locked",
_digistuff_channelcopier_fieldname = "channel",
mesecons = mesecon_support (),
digiline = digilines_support (),
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,
allow_metadata_inventory_put = allow_metadata_inventory_put
})
utils.hopper_add_container({
{"bottom", "lwcomponents:breaker", "tool"}, -- insert items below from hopper above
{"side", "lwcomponents:breaker", "tool"}, -- insert items from hopper at side
})
utils.hopper_add_container({
{"bottom", "lwcomponents:breaker_locked", "tool"}, -- insert items below from hopper above
{"side", "lwcomponents:breaker_locked", "tool"}, -- insert items from hopper at side
})
utils.hopper_add_container({
{"bottom", "lwcomponents:breaker_on", "tool"}, -- insert items below from hopper above
{"side", "lwcomponents:breaker_on", "tool"}, -- insert items from hopper at side
})
utils.hopper_add_container({
{"bottom", "lwcomponents:breaker_locked_on", "tool"}, -- insert items below from hopper above
{"side", "lwcomponents:breaker_locked_on", "tool"}, -- insert items from hopper at side
})
end -- utils.digilines_supported or utils.mesecon_supported

View File

@@ -15,3 +15,42 @@ v0.1.2
* Added support for hopper as optional dependency for droppers, dispensers * Added support for hopper as optional dependency for droppers, dispensers
and collectors. and collectors.
* Added digilines message to punchers when something is punched. * Added digilines message to punchers when something is punched.
v0.1.3
* Added hp and height info from detector.
* Added dispensers spawn if spawner with optional dependency on mobs mod.
If mobs:egg is dispensed 10% change a chicken is dispensed instead.
* Added player_button.
v0.1.4
* Bug fix to spawning owned mobs.
v0.1.5
* Added setting Spawn mobs.
* Added lwcomponents.register_spawner api.
v0.1.6
* Added holograms.
* Added breakers.
* Added fans.
v0.1.7
* Fixed fan description.
* Breakers can break nodes up to 5 forward with digilines message.
* Added deployers.
v0.1.8
* Changed detector digilines message to single message with list of
detected items.
* Added conduits.
* Fixed fans not blowing upward.
* Made changes to lwcomponents.register_spawner api - called function
must now set velocity, can use force parameter.
* Removed spawning from this mod. Created lwcomponents_spawners to
register spawers.

View File

@@ -400,7 +400,9 @@ local function digilines_support ()
if meta then if meta then
local this_channel = meta:get_string ("channel") local this_channel = meta:get_string ("channel")
if this_channel ~= "" and this_channel == channel then if this_channel ~= "" and this_channel == channel and
type (msg) == "string" then
local m = { } local m = { }
for w in string.gmatch(msg, "[^%s]+") do for w in string.gmatch(msg, "[^%s]+") do
m[#m + 1] = w m[#m + 1] = w

748
conduit.lua Normal file
View File

@@ -0,0 +1,748 @@
local utils, mod_storage = ...
local S = utils.S
if utils.digilines_supported or utils.mesecon_supported then
local transfer_rate = 0.1
local conduit_interval = 1.0
local conduit_connections = utils.connections:new (mod_storage, "conduit_connections")
local function get_target_list (pos)
local tlist = conduit_connections:get_connected_ids (pos)
local list = { }
for i = 1, #tlist do
if tlist[i].pos.x ~= pos.x or
tlist[i].pos.y ~= pos.y or
tlist[i].pos.y ~= pos.y then
list[#list + 1] = tlist[i].id
end
end
return list
end
local function send_targets_message (pos)
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 = "targets",
targets = get_target_list (pos) })
end
end
end
end
local function deliver_slot (pos, slot)
local meta = minetest.get_meta (pos)
if meta then
local inv = meta:get_inventory ()
local transfer_data = minetest.deserialize (meta:get_string ("transfer_data"))
if inv then
local item = inv:get_stack ("transfer", slot)
if transfer_data[slot] and item and not item:is_empty () then
local tmeta = minetest.get_meta (transfer_data[slot].pos)
if tmeta then
local tinv = tmeta:get_inventory ()
if tinv then
tinv:add_item ("main", item)
--send_conduit_message (pos, target, slot)
end
end
end
transfer_data[slot] = nil
meta:set_string ("transfer_data", minetest.serialize (transfer_data))
inv:set_stack ("transfer", slot, nil)
end
end
end
local function run_deliveries (pos)
local meta = minetest.get_meta (pos)
if meta then
local inv = meta:get_inventory ()
local transfer_data = minetest.deserialize (meta:get_string ("transfer_data")) or { }
if inv then
local slots = inv:get_size ("transfer")
local tm = minetest.get_us_time ()
for i = 1, slots do
if transfer_data[i] and
(transfer_data[i].due <= tm or
tm < (transfer_data[i].due - 1000000000)) then
deliver_slot (pos, i)
end
end
end
return not inv:is_empty ("transfer")
end
return false
end
local function deliver_all (pos)
local meta = minetest.get_meta (pos)
if meta then
local inv = meta:get_inventory ()
if inv then
local slots = inv:get_size ("transfer")
for i = 1, slots do
local item = inv:get_stack ("transfer", i)
if item and not item:is_empty () then
deliver_slot (pos, i)
end
end
end
meta:set_string ("transfer_data", minetest.serialize({ }))
inv:set_list ("transfer", { })
end
end
local function delivered_earliest (pos)
local meta = minetest.get_meta (pos)
if meta then
local inv = meta:get_inventory ()
local transfer_data = minetest.deserialize (meta:get_string ("transfer_data")) or { }
if inv then
local slots = inv:get_size ("transfer")
local slot = 0
local tm = 0
for i = 1, slots do
if transfer_data[i] and transfer_data[i].due < tm then
slot = i
tm = transfer_data[i].due
end
end
if slot > 0 then
deliver_slot (pos, slot)
end
end
end
end
local function get_transfer_free_slot (pos)
local meta = minetest.get_meta (pos)
if meta then
local inv = meta:get_inventory ()
if inv then
local slots = inv:get_size ("transfer")
for i = 1, slots do
local item = inv:get_stack ("transfer", i)
if not item or item:is_empty () then
return i
end
end
end
end
return 0
end
local function add_to_send_list (pos, item, destpos, distance)
local slot = get_transfer_free_slot (pos)
while slot < 1 do
delivered_earliest (pos)
end
local meta = minetest.get_meta (pos)
if meta then
local inv = meta:get_inventory ()
local transfer_data = minetest.deserialize (meta:get_string ("transfer_data")) or { }
if inv then
transfer_data[slot] =
{
pos = destpos,
due = minetest.get_us_time () + (transfer_rate * 1000000 * distance)
}
inv:add_item ("transfer", item)
meta:set_string ("transfer_data", minetest.serialize (transfer_data))
local timer = minetest.get_node_timer (pos)
if not timer:is_started () then
timer:start (conduit_interval)
end
end
end
end
local function send_to_target (pos, target, slot)
local meta = minetest.get_meta (pos)
if meta then
local inv = meta:get_inventory ()
target = (target and tostring (target)) or meta:get_string ("target")
if inv and target:len () > 0 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 tpos, distance = conduit_connections:is_connected (pos, target)
if tpos then
local tmeta = minetest.get_meta (tpos)
if tmeta then
local tinv = tmeta:get_inventory ()
if tinv and tinv:room_for_item ("main", item) then
add_to_send_list (pos, item, tpos, distance)
stack:set_count (stack:get_count () - 1)
inv:set_stack ("main", slot, stack)
--send_conduit_message (pos, target, slot)
return true, target, slot
end
end
end
end
end
end
end
end
return false
end
local function run_conduit (pos)
local meta = minetest.get_meta (pos)
local automatic = false
if meta then
automatic = meta:get_string ("automatic") == "true"
end
if automatic then
send_to_target (pos)
end
return run_deliveries (pos) or automatic
end
local function get_formspec (pos)
local meta = minetest.get_meta (pos)
local automatic = "false"
if meta then
automatic = meta:get_string ("automatic")
end
return
"formspec_version[3]\n"..
"size[11.75,12.25;true]\n"..
"field[1.0,1.5;3.0,0.8;channel;Channel;${channel}]\n"..
"button[4.2,1.5;1.5,0.8;setchannel;Set]\n"..
"field[1.0,3.0;3.0,0.8;target;Target;${target}]\n"..
"button[4.2,3.0;1.5,0.8;settarget;Set]\n"..
"checkbox[1.0,4.5;automatic;Automatic;"..automatic.."]\n"..
"list[context;main;6.0,1.0;4,4;]\n"..
"list[current_player;main;1.0,6.5;8,4;]\n"..
"listring[]"
end
local function on_construct (pos)
conduit_connections:add_node (pos)
end
local function on_destruct (pos)
deliver_all (pos)
conduit_connections:remove_node (pos)
end
local function after_place_node (pos, placer, itemstack, pointed_thing)
local meta = minetest.get_meta (pos)
local spec =
"formspec_version[3]"..
"size[7.0,3.8]"..
"field[0.5,1.0;6.0,0.8;channel;Channel;${channel}]"..
"button[2.0,2.3;3.0,0.8;setchannel;Set]"
meta:set_string ("inventory", "{ main = { }, transfer = { } }")
meta:set_string ("formspec", spec)
meta:set_string ("transfer_data", minetest.serialize({ }))
meta:set_string ("automatic", "false")
local inv = meta:get_inventory ()
inv:set_size ("main", 16)
inv:set_width ("main", 4)
inv:set_size ("transfer", 32)
inv:set_width ("transfer", 8)
-- 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", "Dropper (owned by "..placer:get_player_name ()..")")
end
-- If return true no item is taken from itemstack
return false
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_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
if tostring (fields.channel):len () > 0 then
if meta:get_string ("channel"):len () < 1 then
meta:set_string ("formspec", get_formspec (pos))
end
meta:set_string ("channel", fields.channel)
conduit_connections:set_id (pos, tostring (fields.channel))
elseif meta:get_string ("channel"):len () > 0 then
if can_dig (pos, sender) ~= false then
local spec =
"formspec_version[3]"..
"size[7.0,3.8]"..
"field[0.5,1.0;6.0,0.8;channel;Channel;${channel}]"..
"button[2.0,2.3;3.0,0.8;setchannel;Set]"
meta:set_string ("channel", fields.channel)
meta:set_string ("formspec", spec)
conduit_connections:set_id (pos, nil)
elseif sender and sender:is_player () then
fields.channel = meta:get_string ("channel")
local spec =
"formspec_version[3]"..
"size[8.0,4.0,false]"..
"label[2.5,1.0;Conduit not empty]"..
"button_exit[3.0,2.0;2.0,1.0;close;Close]"
minetest.show_formspec (sender:get_player_name (),
"lwcomponents:conduit_not_empty",
spec)
end
end
end
end
if fields.settarget then
local meta = minetest.get_meta (pos)
if meta then
meta:set_string ("target", fields.target)
end
end
if fields.automatic then
local meta = minetest.get_meta (pos)
if meta then
meta:set_string ("automatic", fields.automatic)
meta:set_string ("formspec", get_formspec (pos))
local timer = minetest.get_node_timer (pos)
if not timer:is_started () then
timer:start (conduit_interval)
end
end
end
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
on_destruct (pos)
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
preserve_metadata (pos, node, meta, { stack })
utils.item_drop (stack, nil, pos)
on_destruct (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 on_timer (pos, elapsed)
return run_conduit (pos)
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 then
if type (msg) == "string" then
local m = { }
for w in string.gmatch(msg, "[^%s]+") do
m[#m + 1] = w
end
if m[1] == "target" then
meta:set_string ("target", (m[2] and tostring (m[2])) or "")
elseif m[1] == "targets" then
send_targets_message (pos)
elseif m[1] == "transfer" then
send_to_target (pos)
end
elseif type (msg) == "table" then
if msg.action and tostring (msg.action) == "transfer" then
send_to_target (pos, msg.target, msg.slot or msg.item)
end
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)
send_to_target (pos)
end
}
}
end
return nil
end
minetest.register_node("lwcomponents:conduit", {
description = S("Conduit"),
drawtype = "glasslike_framed",
tiles = { "lwconduit_edge.png", "lwconduit.png" },
is_ground_content = false,
groups = { cracky = 3 },
sounds = default.node_sound_stone_defaults (),
paramtype = "none",
param1 = 0,
paramtype2 = "none",
param2 = 0,
floodable = false,
_digistuff_channelcopier_fieldname = "channel",
mesecons = mesecon_support (),
digiline = digilines_support (),
on_construct = on_construct,
on_destruct = on_destruct,
on_receive_fields = on_receive_fields,
after_place_node = after_place_node,
can_dig = can_dig,
on_blast = on_blast,
on_timer = on_timer,
on_rightclick = on_rightclick
})
minetest.register_node("lwcomponents:conduit_locked", {
description = S("Conduit (locked)"),
drawtype = "glasslike_framed",
tiles = { "lwconduit_edge.png", "lwconduit.png" },
is_ground_content = false,
groups = { cracky = 3 },
sounds = default.node_sound_stone_defaults (),
paramtype = "none",
param1 = 0,
paramtype2 = "none",
param2 = 0,
floodable = false,
_digistuff_channelcopier_fieldname = "channel",
mesecons = mesecon_support (),
digiline = digilines_support (),
on_construct = on_construct,
on_destruct = on_destruct,
on_receive_fields = on_receive_fields,
after_place_node = after_place_node_locked,
can_dig = can_dig,
on_blast = on_blast,
on_timer = on_timer,
on_rightclick = on_rightclick
})
utils.hopper_add_container({
{"top", "lwcomponents:conduit", "main"}, -- take items from above into hopper below
{"bottom", "lwcomponents:conduit", "main"}, -- insert items below from hopper above
{"side", "lwcomponents:conduit", "main"}, -- insert items from hopper at side
})
utils.hopper_add_container({
{"top", "lwcomponents:conduit_locked", "main"}, -- take items from above into hopper below
{"bottom", "lwcomponents:conduit_locked", "main"}, -- insert items below from hopper above
{"side", "lwcomponents:conduit_locked", "main"}, -- insert items from hopper at side
})
end -- utils.digilines_supported or utils.mesecon_supported

300
connections.lua Normal file
View File

@@ -0,0 +1,300 @@
local connections = { }
function connections:new (mod_storage, name)
local obj = { }
setmetatable (obj, self)
self.__index = self
obj.connector_list = { }
obj.name = tostring (name)
obj.storage = mod_storage
if mod_storage then
local stored = mod_storage:get_string (obj.name)
if stored == "" then
stored = "{ }"
end
obj.connector_list = minetest.deserialize (stored)
if not obj.connector_list then
obj.connector_list = { }
end
end
return obj
end
function connections:load ()
if self.storage then
local stored = self.storage:get_string (self.name)
if stored == "" then
stored = "{ }"
end
self.connector_list = minetest.deserialize (stored)
end
end
function connections:store ()
if self.storage then
self.storage:set_string (self.name, minetest.serialize (self.connector_list))
end
end
function connections:add_node (pos, id)
self.connector_list[minetest.pos_to_string (pos, 0)] =
{
id = (id and tostring (id)) or nil,
checked = false
}
self:store ()
end
function connections:remove_node (pos)
self.connector_list[minetest.pos_to_string (pos, 0)] = nil
self:store ()
end
function connections:set_id (pos, id)
local con = self.connector_list[minetest.pos_to_string (pos, 0)]
if con then
con.id = (id and tostring (id)) or nil
self:store ()
return true
end
return false
end
local function is_connected (self, pos, id, tally, test_coords)
if not id then
return nil
end
local con = self.connector_list[minetest.pos_to_string (pos, 0)]
if con and not con.checked then
con.checked = true
if con.id == id then
con.checked = false
return pos, tally
end
for i = 1, #test_coords do
local result, agg = is_connected (self,
{
x = pos.x + test_coords[i].x,
y = pos.y + test_coords[i].y,
z = pos.z + test_coords[i].z
},
id,
tally,
test_coords)
if result then
con.checked = false
return result, (tally + agg + 1)
end
end
con.checked = false
end
return nil, 0
end
function connections:is_connected (pos, id)
return is_connected (self,
pos,
tostring (id),
0,
{
{ 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
function connections:is_connected_horizontal (pos, id)
return is_connected (self,
pos,
tostring (id),
0,
{
{ x = 1, y = 0, z = 0 },
{ x = -1, y = 0, z = 0 },
{ x = 0, y = 0, z = 1 },
{ x = 0, y = 0, z = -1 }
})
end
function connections:is_connected_vertical (pos, id)
return is_connected (self,
pos,
tostring (id),
0,
{
{ x = 0, y = 1, z = 0 },
{ x = 0, y = -1, z = 0 }
})
end
local function get_connected_ids (self, pos, test_coords, list)
local con = self.connector_list[minetest.pos_to_string (pos, 0)]
if con and not con.checked then
con.checked = true
if con.id then
list[#list + 1] =
{
pos = { x = pos.x, y = pos.y, z = pos.z },
id = con.id
}
end
for i = 1, #test_coords do
get_connected_ids (self,
{
x = pos.x + test_coords[i].x,
y = pos.y + test_coords[i].y,
z = pos.z + test_coords[i].z
},
test_coords,
list)
end
con.checked = false
end
return list
end
function connections:get_connected_ids (pos)
local list = get_connected_ids (self,
pos,
{
{ 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 }
},
{ })
for i = #list, 1, -1 do
for j = 1, i - 1, 1 do
if list[i].pos.x == list[j].pos.x and
list[i].pos.y == list[j].pos.y and
list[i].pos.z == list[j].pos.z then
list[i] = nil
break
end
end
end
return list
end
function connections:get_connected_ids_horizontal (pos)
return get_connected_ids (self,
pos,
{
{ x = 1, y = 0, z = 0 },
{ x = -1, y = 0, z = 0 },
{ x = 0, y = 0, z = 1 },
{ x = 0, y = 0, z = -1 }
},
{ })
end
function connections:get_connected_ids_vertical (pos)
return get_connected_ids (self,
pos,
{
{ x = 0, y = 1, z = 0 },
{ x = 0, y = -1, z = 0 }
},
{ })
end
function connections:get_connected_ids_north_south (pos)
return get_connected_ids (self,
pos,
{
{ x = 0, y = 0, z = 1 },
{ x = 0, y = 0, z = -1 }
},
{ })
end
function connections:get_connected_ids_east_west (pos)
return get_connected_ids (self,
pos,
{
{ x = 1, y = 0, z = 0 },
{ x = -1, y = 0, z = 0 }
},
{ })
end
return connections
--

View File

@@ -94,6 +94,80 @@ minetest.register_craft( {
}, },
}) })
minetest.register_craft( {
output = "lwcomponents:breaker",
recipe = {
{ "default:chest", "default:pick_stone" },
{ "default:copper_ingot", "default:steel_ingot" },
},
})
minetest.register_craft( {
output = "lwcomponents:breaker_locked",
recipe = {
{ "default:chest_locked", "default:pick_stone" },
{ "default:copper_ingot", "default:steel_ingot" },
},
})
minetest.register_craft( {
output = "lwcomponents:deployer",
recipe = {
{ "default:chest", "group:wood" },
{ "default:copper_ingot", "default:steel_ingot" },
},
})
minetest.register_craft( {
output = "lwcomponents:deployer_locked",
recipe = {
{ "default:chest_locked", "group:wood" },
{ "default:copper_ingot", "default:steel_ingot" },
},
})
minetest.register_craft( {
output = "lwcomponents:fan",
recipe = {
{ "default:chest", "default:steel_ingot" },
{ "default:copper_ingot", "default:steel_ingot" },
},
})
minetest.register_craft( {
output = "lwcomponents:fan_locked",
recipe = {
{ "default:chest_locked", "default:steel_ingot" },
{ "default:copper_ingot", "default:steel_ingot" },
},
})
minetest.register_craft( {
output = "lwcomponents:conduit 5",
recipe = {
{ "default:stone", "", "default:stone" },
{ "", "default:chest", "" },
{ "default:stone", "default:steel_ingot", "default:stone" },
},
})
minetest.register_craft( {
output = "lwcomponents:conduit_locked 5",
recipe = {
{ "default:stone", "", "default:stone" },
{ "", "default:chest_locked", "" },
{ "default:stone", "default:steel_ingot", "default:stone" },
},
})
end -- utils.digilines_supported or utils.mesecon_supported end -- utils.digilines_supported or utils.mesecon_supported
@@ -117,10 +191,45 @@ minetest.register_craft( {
}, },
}) })
minetest.register_craft( {
output = "lwcomponents:hologram",
recipe = {
{ "dye:red", "dye:green", "dye:blue" },
{ "default:copper_ingot", "default:steel_ingot", "default:copper_ingot" },
{ "default:chest", "default:stone", "default:glass" },
},
})
minetest.register_craft( {
output = "lwcomponents:hologram_locked",
recipe = {
{ "dye:red", "dye:green", "dye:blue" },
{ "default:copper_ingot", "default:steel_ingot", "default:copper_ingot" },
{ "default:chest_locked", "default:stone", "default:glass" },
},
})
end -- utils.digilines_supported end -- utils.digilines_supported
if utils.digilines_supported and utils.digistuff_supported then
minetest.register_craft({
output = "lwcomponents:player_button",
recipe = {
{ "mesecons_button:button_off", "digilines:wire_std_00000000" }
},
})
end -- utils.digilines_supported and utils.digistuff_supported
if utils.mesecon_supported and mesecon.mvps_push then if utils.mesecon_supported and mesecon.mvps_push then
minetest.register_craft ({ minetest.register_craft ({

View File

@@ -5,3 +5,4 @@ digilines?
unifieddyes? unifieddyes?
intllib? intllib?
hopper? hopper?
digistuff?

679
deployer.lua Normal file
View File

@@ -0,0 +1,679 @@
local utils = ...
local S = utils.S
if utils.digilines_supported or utils.mesecon_supported then
local deploy_interval = 1.0
local function send_deploy_message (pos, slot, name, range)
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 = "deploy",
name = name,
slot = slot,
range = range })
end
end
end
end
local function deployer_front (pos, param2)
if param2 == 0 then
return { x = pos.x, y = pos.y, z = pos.z - 1 }
elseif param2 == 1 then
return { x = pos.x - 1, y = pos.y, z = pos.z }
elseif param2 == 2 then
return { x = pos.x, y = pos.y, z = pos.z + 1 }
elseif 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 get_deploy_pos (pos, param2, range)
local deploypos = { x = pos.x, y = pos.y, z = pos.z }
for i = 1, range do
deploypos = deployer_front (deploypos, param2)
if i < range then
local node = minetest.get_node_or_nil (deploypos)
if not node or node.name ~= "air" then
local nodedef = utils.find_item_def (node.name)
if not nodedef or not nodedef.buildable_to then
return nil
end
end
end
end
return deploypos
end
local function place_node (itemname, pos)
local node = minetest.get_node_or_nil ({ x = pos.x, y = pos.y - 1, z = pos.z })
if not node then
return false
end
local nodedef = utils.find_item_def (node.name)
if node.name == "air" or not nodedef or (nodedef and nodedef.buildable_to) then
return false
end
node = minetest.get_node_or_nil (pos)
if not node then
return false
end
nodedef = utils.find_item_def (node.name)
if node.name ~= "air" then
if not nodedef or not nodedef.buildable_to or minetest.is_protected (pos, "") then
return false
end
end
local stack = ItemStack (itemname)
local itemdef = utils.find_item_def (itemname)
if stack and itemdef then
local placed = false
local pointed_thing =
{
type = "node",
under = { x = pos.x, y = pos.y - 1, z = pos.z },
above = pos,
}
if node.name ~= "air" and nodedef and nodedef.buildable_to then
pointed_thing =
{
type = "node",
under = pos,
above = { x = pos.x, y = pos.y + 1, z = pos.z },
}
end
if itemdef and itemdef.on_place then
local result, msg = pcall (itemdef.on_place, stack, nil, pointed_thing)
placed = result
if not placed then
if utils.settings.alert_handler_errors then
minetest.log ("error", "on_place handler for "..itemname.." crashed - "..msg)
end
end
end
if not placed then
if not minetest.registered_nodes[itemname] then
return false
end
minetest.set_node (pos, { name = itemname, param1 = 0, param2 = 0 })
if itemdef and itemdef.after_place_node then
local result, msg = pcall (itemdef.after_place_node, pos, nil, stack, pointed_thing)
if not result then
if utils.settings.alert_handler_errors then
minetest.log ("error", "after_place_node handler for "..nodename.." crashed - "..msg)
end
end
end
if itemdef and itemdef.sounds and itemdef.sounds.place then
pcall (minetest.sound_play, itemdef.sounds.place, { pos = pos })
end
end
end
return true
end
-- slot:
-- nil - next item, no drop if empty
-- number - 1 item from slot, no drop if empty
-- string - name of item to drop, no drop if none
-- range:
-- 1 - 5 from front of deployer
local function deploy_item (pos, node, slot, range)
local meta = minetest.get_meta (pos)
range = math.min (math.max (tonumber (range) or 1, 1), 5)
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)
local deploypos = get_deploy_pos (pos, node.param2, range)
if item and deploypos then
if place_node (name, deploypos) then
stack:set_count (stack:get_count () - 1)
inv:set_stack ("main", slot, stack)
send_deploy_message (pos, slot, name, range)
return true, slot, name, range
end
end
end
end
end
end
return false
end
local function deployer_off (pos)
local node = minetest.get_node (pos)
if node then
if node.name == "lwcomponents:deployer_on" then
node.name = "lwcomponents:deployer"
minetest.get_node_timer (pos):stop ()
minetest.swap_node (pos, node)
elseif node.name == "lwcomponents:deployer_locked_on" then
node.name = "lwcomponents:deployer_locked"
minetest.get_node_timer (pos):stop ()
minetest.swap_node (pos, node)
end
end
end
local function deployer_on (pos, node, slot, range)
local node = minetest.get_node (pos)
range = tonumber (range) or 1
if slot and tostring (slot) == "nil" then
slot = nil
end
if node and range < 6 and range > 0 then
if node.name == "lwcomponents:deployer" then
node.name = "lwcomponents:deployer_on"
minetest.swap_node (pos, node)
deploy_item (pos, node, slot, range)
minetest.get_node_timer (pos):start (deploy_interval)
elseif node.name == "lwcomponents:deployer_locked" then
node.name = "lwcomponents:deployer_locked_on"
minetest.swap_node (pos, node)
deploy_item (pos, node, slot, range)
minetest.get_node_timer (pos):start (deploy_interval)
end
end
end
local function after_place_node (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)
-- 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", "Deployer (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
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
preserve_metadata (pos, node, meta, { stack })
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 on_timer (pos, elapsed)
deployer_off (pos)
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] == "deploy" then
if tostring (m[2]) == nil then
m[2] = "nil"
elseif m[2] and tonumber (m[2]) then
m[2] = tonumber (m[2])
end
deployer_on (pos, node, m[2], m[3])
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)
deployer_on (pos, node, "nil", 1)
end
}
}
end
return nil
end
minetest.register_node("lwcomponents:deployer", {
description = S("Deployer"),
tiles = { "lwdeployer.png", "lwdeployer.png", "lwdeployer.png",
"lwdeployer.png", "lwdeployer.png", "lwdeployer_face.png"},
is_ground_content = false,
groups = { cracky = 3 },
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 (),
on_receive_fields = on_receive_fields,
after_place_node = after_place_node,
can_dig = can_dig,
on_blast = on_blast,
on_timer = on_timer,
on_rightclick = on_rightclick
})
minetest.register_node("lwcomponents:deployer_locked", {
description = S("Deployer (locked)"),
tiles = { "lwdeployer.png", "lwdeployer.png", "lwdeployer.png",
"lwdeployer.png", "lwdeployer.png", "lwdeployer_face.png"},
is_ground_content = false,
groups = { cracky = 3 },
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 (),
on_receive_fields = on_receive_fields,
after_place_node = after_place_node_locked,
can_dig = can_dig,
on_blast = on_blast,
on_timer = on_timer,
on_rightclick = on_rightclick
})
minetest.register_node("lwcomponents:deployer_on", {
description = S("Deployer"),
tiles = { "lwdeployer.png", "lwdeployer.png", "lwdeployer.png",
"lwdeployer.png", "lwdeployer.png", "lwdeployer_face_on.png"},
is_ground_content = false,
groups = { cracky = 3, not_in_creative_inventory = 1 },
sounds = default.node_sound_stone_defaults (),
paramtype = "none",
param1 = 0,
paramtype2 = "facedir",
param2 = 1,
light_source = 3,
floodable = false,
drop = "lwcomponents:deployer",
_digistuff_channelcopier_fieldname = "channel",
mesecons = mesecon_support (),
digiline = digilines_support (),
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:deployer_locked_on", {
description = S("Deployer (locked)"),
tiles = { "lwdeployer.png", "lwdeployer.png", "lwdeployer.png",
"lwdeployer.png", "lwdeployer.png", "lwdeployer_face_on.png"},
is_ground_content = false,
groups = { cracky = 3, not_in_creative_inventory = 1 },
sounds = default.node_sound_stone_defaults (),
paramtype = "none",
param1 = 0,
paramtype2 = "facedir",
param2 = 1,
light_source = 3,
floodable = false,
drop = "lwcomponents:deployer_locked",
_digistuff_channelcopier_fieldname = "channel",
mesecons = mesecon_support (),
digiline = digilines_support (),
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
})
utils.hopper_add_container({
{"top", "lwcomponents:deployer", "main"}, -- take items from above into hopper below
{"bottom", "lwcomponents:deployer", "main"}, -- insert items below from hopper above
{"side", "lwcomponents:deployer", "main"}, -- insert items from hopper at side
})
utils.hopper_add_container({
{"top", "lwcomponents:deployer_locked", "main"}, -- take items from above into hopper below
{"bottom", "lwcomponents:deployer_locked", "main"}, -- insert items below from hopper above
{"side", "lwcomponents:deployer_locked", "main"}, -- insert items from hopper at side
})
utils.hopper_add_container({
{"top", "lwcomponents:deployer_on", "main"}, -- take items from above into hopper below
{"bottom", "lwcomponents:deployer_on", "main"}, -- insert items below from hopper above
{"side", "lwcomponents:deployer_on", "main"}, -- insert items from hopper at side
})
utils.hopper_add_container({
{"top", "lwcomponents:deployer_locked_on", "main"}, -- take items from above into hopper below
{"bottom", "lwcomponents:deployer_locked_on", "main"}, -- insert items below from hopper above
{"side", "lwcomponents:deployer_locked_on", "main"}, -- insert items from hopper at side
})
end -- utils.digilines_supported or utils.mesecon_supported
--

View File

@@ -60,7 +60,7 @@ end
local function send_detect_message (pos, item_type, name, label, item_pos, count) local function send_detect_message (pos, detected_list)
if utils.digilines_supported then if utils.digilines_supported then
local meta = minetest.get_meta (pos) local meta = minetest.get_meta (pos)
@@ -72,11 +72,7 @@ local function send_detect_message (pos, item_type, name, label, item_pos, count
utils.digilines_default_rules, utils.digilines_default_rules,
channel, channel,
{ action = "detect", { action = "detect",
type = item_type, detected = detected_list })
name = name,
label = label,
pos = to_relative_coords (pos, item_pos),
count = count })
end end
end end
end end
@@ -132,6 +128,33 @@ end
local function get_entity_height (objref)
if objref.get_luaentity then
entity = objref:get_luaentity ()
if entity and entity.name then
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 function detect (pos)
local meta = minetest.get_meta (pos) local meta = minetest.get_meta (pos)
local detected = false local detected = false
@@ -140,6 +163,7 @@ local function detect (pos)
local radius = meta:get_int ("radius") local radius = meta:get_int ("radius")
local mode = meta:get_int ("mode") local mode = meta:get_int ("mode")
local object = minetest.get_objects_inside_radius (pos, radius + 0.5) local object = minetest.get_objects_inside_radius (pos, radius + 0.5)
local detected_list = { }
for i = 1, #object do for i = 1, #object do
if object[i]:is_player () then if object[i]:is_player () then
@@ -148,12 +172,16 @@ local function detect (pos)
if meta:get_string ("players") == "true" and if meta:get_string ("players") == "true" and
filter_item (pos, mode, object[i]:get_pos ()) then filter_item (pos, mode, object[i]:get_pos ()) then
send_detect_message (pos, detected_list[#detected_list + 1] =
"player", {
object[i]:get_player_name (), type = "player",
object[i]:get_player_name (), name = object[i]:get_player_name (),
object[i]:get_pos (), label = object[i]:get_player_name (),
1) pos = to_relative_coords (pos, object[i]:get_pos ()),
count = 1,
hp = object[i]:get_hp (),
height = get_entity_height (object[i])
}
detected = true detected = true
end end
@@ -169,12 +197,17 @@ local function detect (pos)
local stack = ItemStack (object[i]:get_luaentity ().itemstring or "") local stack = ItemStack (object[i]:get_luaentity ().itemstring or "")
if stack and not stack:is_empty () then if stack and not stack:is_empty () then
send_detect_message (pos,
"drop", detected_list[#detected_list + 1] =
stack:get_name (), {
stack:get_name (), type = "drop",
object[i]:get_pos (), name = stack:get_name (),
stack:get_count ()) label = stack:get_name (),
pos = to_relative_coords (pos, object[i]:get_pos ()),
count = stack:get_count (),
hp = 0,
height = 0
}
detected = true detected = true
end end
@@ -198,12 +231,16 @@ local function detect (pos)
object[i]:get_luaentity () and object[i]:get_luaentity () and
object[i]:get_luaentity ().name) or "" object[i]:get_luaentity ().name) or ""
send_detect_message (pos, detected_list[#detected_list + 1] =
"entity", {
name, type = "entity",
label, name = name,
object[i]:get_pos (), label = label,
1) pos = to_relative_coords (pos, object[i]:get_pos ()),
count = 1,
hp = object[i]:get_hp (),
height = get_entity_height (object[i])
}
detected = true detected = true
@@ -223,12 +260,16 @@ local function detect (pos)
if node and node.name ~= "air" and node.name ~= "ignore" and if node and node.name ~= "air" and node.name ~= "ignore" and
filter_item (pos, mode, testpos) then filter_item (pos, mode, testpos) then
send_detect_message (pos, detected_list[#detected_list + 1] =
"node", {
node.name, type = "node",
node.name, name = node.name,
testpos, label = node.name,
1) pos = testpos,
count = 1,
hp = 0,
height = 0
}
detected = true detected = true
end end
@@ -239,6 +280,8 @@ local function detect (pos)
if detected then if detected then
mesecons_on (pos) mesecons_on (pos)
send_detect_message (pos, detected_list)
else else
mesecons_off (pos) mesecons_off (pos)
end end
@@ -576,7 +619,9 @@ local function digilines_support ()
if meta then if meta then
local this_channel = meta:get_string ("channel") local this_channel = meta:get_string ("channel")
if this_channel ~= "" and this_channel == channel then if this_channel ~= "" and this_channel == channel and
type (msg) == "string" then
local m = { } local m = { }
for w in string.gmatch(msg, "[^%s]+") do for w in string.gmatch(msg, "[^%s]+") do
m[#m + 1] = w m[#m + 1] = w

View File

@@ -7,6 +7,26 @@ 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) local function dispense_pos (pos, node)
if node.param2 == 0 then if node.param2 == 0 then
return { x = pos.x, y = pos.y, z = pos.z - 1 } return { x = pos.x, y = pos.y, z = pos.z - 1 }
@@ -24,18 +44,17 @@ end
local function dispense_velocity (node) local function dispense_velocity (node)
local force = 25 --math.random (30 , 35)
local tilt = (math.random (1 , 2001) - 1001) / 1000 local tilt = (math.random (1 , 2001) - 1001) / 1000
local sway = (math.random (1 , 4001) - 2001) / 1000 local sway = (math.random (1 , 4001) - 2001) / 1000
if node.param2 == 0 then if node.param2 == 0 then
return { x = sway, y = tilt, z = -force } return { x = sway, y = tilt, z = -dispenser_force }
elseif node.param2 == 1 then elseif node.param2 == 1 then
return { x = -force, y = tilt, z = sway } return { x = -dispenser_force, y = tilt, z = sway }
elseif node.param2 == 2 then elseif node.param2 == 2 then
return { x = sway, y = tilt, z = force } return { x = sway, y = tilt, z = dispenser_force }
elseif node.param2 == 3 then elseif node.param2 == 3 then
return { x = force, y = tilt, z = sway } return { x = dispenser_force, y = tilt, z = sway }
else else
return { x = 0, y = 0, z = 0 } return { x = 0, y = 0, z = 0 }
end end
@@ -118,11 +137,31 @@ local function dispense_item (pos, node, slot)
if item then if item then
item:set_count (1) item:set_count (1)
local spawn_pos = dispense_pos (pos, node)
local owner = meta:get_string ("owner")
local obj, cancel = nil, false
local obj = minetest.add_item (dispense_pos (pos, node), item) 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)
obj:set_velocity (dispense_velocity (node))
end
if obj then if obj then
obj:set_velocity (dispense_velocity (node))
stack:set_count (stack:get_count () - 1) stack:set_count (stack:get_count () - 1)
inv:set_stack ("main", slot, stack) inv:set_stack ("main", slot, stack)
@@ -325,7 +364,9 @@ local function digilines_support ()
if meta then if meta then
local this_channel = meta:get_string ("channel") local this_channel = meta:get_string ("channel")
if this_channel ~= "" and this_channel == channel then if this_channel ~= "" and this_channel == channel and
type (msg) == "string" then
local m = { } local m = { }
for w in string.gmatch(msg, "[^%s]+") do for w in string.gmatch(msg, "[^%s]+") do
m[#m + 1] = w m[#m + 1] = w

51
docs/api.txt Normal file
View File

@@ -0,0 +1,51 @@
lwcomponents.version ()
Returns this mod version as a string. eg. "0.1.5".
lwcomponents.register_spawner (itemname, spawn_func)
itemname:
Registered string name of the spawner item
spawn_func:
The function to call to spawn the mob of the form -
spawn_func (spawn_pos, itemstack, owner, spawner_pos, spawner_dir, force)
spawn_pos:
The position the entity should be spawned at.
itemstack:
The spawner ItemStack, of the name itemname.
owner:
As string of the player's name that will own the spawned entity,
if applicable. This may be "" for no owner.
spawner_pos:
The position of the block calling this function.
spawner_dir:
A single unit vector of the direction the spawner block is facing.
eg. { x = -1, y = 0, z = 0 }
force:
Recommended force (for velocity) of spawned entity.
Can use vector.multiply (spawner_dir, force).
This function should return the ObjectRef of the spawned entity or
nil. If this function returns nil for ObjectRef a second boolean
value should be returned for whether to cancel the action.
eg. If too many mobs:
return nil, true
eg. If only chance of spawn and out of luck:
return nil, false
The register function return true on success, or false on failure
(parameter type check failed or the spawn item has already been
registered).

52
docs/breaker.txt Normal file
View File

@@ -0,0 +1,52 @@
Breaker
-------
* This block is only available if digilines and/or mesecons are loaded.
Breakers dig the node up to 5 nodes directly in front of them and drop
the item at the back of them. The node is only dug if the breaker has a
tool that can dig it or if it can be dug by hand, and there are no nodes
before of it. ie. cannot dig 2nd node if 1st node has something in it.
The tool is worn if used. Also acts as a digilines conductor. If the
hopper mod is loaded, will take tools from the top and sides.
Only the owner can dig or access the form of the locked version.
UI
Channel - digilines channel of breaker.
Top 1 slot inventory - tool to use.
Bottom 32 slot inventory - player's inventory.
Mesecons
Digs the node in front (always the 1st node position) when power is
turned on, if it can.
Digilines messages
"break n"
Digs the node at n nodes in front when power is turned on, if it can.
n should be a number between 1 and 5. If omitted 1 is assumed.
"eject side"
Drop the tool in the tool slot at the given side. Valid sides are "left",
"right", "back", "front". If side is omitted or invalid "front" is used.
When a breaker digs a node or wears out the tool a digilines message is
sent with the breaker's channel. The message is a table with the following
keys:
{
action = "<action>",
name = "<name>",
range = <number>
}
action
Will be "break" or "tool".
name
For "break" action the registered node name of what was dug.
For "tool" action the registered tool name of the tool that wore out.
range
For "break" action the nodes forward that was dug.
For "tool" action always nil.

33
docs/collector.txt Normal file
View File

@@ -0,0 +1,33 @@
Collector
---------
* This block is only available if digilines is loaded.
Picks up dropped items in adjacent block, with optional filtering. Also
acts as a digilines conductor. If the hopper mod is loaded, will take items
from the top and sides, and release them from the bottom.
Only the owner can dig or access the form of the locked version.
UI
Channel - digilines channel of collector.
Left 16 slot inventory - storage of picked up items.
Right 8 slot inventory - Filter list. Place what items should be picked
up in this list. Leave empty to pick up all.
Bottom 32 slot inventory - player's inventory.
Digilines messages
"start"
Start the collector.
"stop"
Stop the collector.
When items are picked up a digilines message is sent with the collector's
channel. The message is a table with the following keys:
{
action = "collect",
name = "<itemname>", -- name of picked up items.
count = <count> -- number of the item picked up.
}

66
docs/conduit.txt Normal file
View File

@@ -0,0 +1,66 @@
Conduit
-------
* This block is only available if digilines and/or mesecons are loaded.
Conduits are connected in a circuit, and can move items from their
inventory to another conduit in the same circuit.
When a conduit node is placed it has a simple form that asks for a channel.
This channel is both the digilines' channel and the target id of this
conduit within the circuit. A conduit does not have to be given a name.
Most of them are just used to connect other conduits together.
Transfer of items takes 0.1 seconds per conduit node moved.
Also acts as a digilines conductor. If the hopper mod is loaded, will
take items from the top and sides, and release them from the bottom.
Only the owner can dig or access the form of the locked version.
UI
Channel - digilines channel/target id of circuit.
Target - target id/channel of circuit this circuit will transfer to.
Automatic - if checked transfers next item every second without command.
Top right 16 slot inventory - storage of items.
Bottom 32 slot inventory - player's inventory.
Mesecons
Transfers the next item when power is turned on to the target circuit.
Digilines messages
"target <id>"
Set the target of the conduit. id should be the channel of another
conduit on the same circiut. This takes a moment to take effect, so
delay any transfers.
"targets"
Conduit will send a digilines message with its own channel in the form:
{
action = "targets",
targets = { ... } -- list of string channels of all other conduits
-- with a channel on the same circuit.
}
"transfer"
Simple transfer. Transfers the next item in the inventory to the target
circuit (same as mesecons power).
table message
{
action = "transfer",
target = "<channel>",
slot = <number>,
item = "<itemname>"
}
If target is not given, the circuit's set target is used.
slot should be a number between 1 to 16. If the slot is empty nothing
is transferred.
item should be the registered item name. If the circuit's inventory
does not contain any nothing is transferred.
Only slot or item should be given. If both are given slot is used. If
neither are given the next item in the inventory is transferred.

57
docs/deployer.txt Normal file
View File

@@ -0,0 +1,57 @@
Deployer
-------
* This block is only available if digilines and/or mesecons are loaded.
Deployers place the node up to 5 nodes directly in front of them. The
node is only placed if there are no nodes before of it which are not
replaceable. ie. cannot place 2nd node if 1st node has something in it.
Also acts as a digilines conductor. If the hopper mod is loaded, will
take items from the top and sides, and release them from the bottom.
Only the owner can dig or access the form of the locked version.
UI
Channel - digilines channel of breaker.
Top 16 slot inventory - storage of items to place.
Bottom 32 slot inventory - player's inventory.
Mesecons
Places the node in front (always the 1st node position) when power is
turned on, if it can.
Digilines messages
"deploy <slot or itemname> <n>"
Places the node at n nodes in front when power is turned on, if it can.
n should be a number between 1 and 5. If omitted 1 is assumed.
If slot is a number, places an item from that slot. No placement if
slot is empty.
eg. "deploy 7"
If itemname is given, places the item of the name given. No placement
if deployer does not contain the item.
eg. "deploy default:stone"
If n is given with no slot/itemname use "nil".
eg. "deploy nil 3"
When a deployer places a node a digilines message is sent with the
deployer's channel. The message is a table with the following
keys:
{
action = "deploy",
name = "<name>",
slot = <slot>,
range = <number>
}
action
Will be "deploy".
name
The registered node name of what was placed.
range
The nodes forward that was placed.

112
docs/detector.txt Normal file
View File

@@ -0,0 +1,112 @@
Detector
--------
* This block is only available if digilines and/or mesecons are loaded.
Detects items or entities within a given radius. Also acts as a
digilines conductor.
Only the owner can dig or access the form of the locked version.
UI
Channel - digilines channel of detector.
Radius - block distance from detector to detect.
Entities - if checked detects entities.
Players - if checked detects players.
Drops - if checked detects drops.
Nodes - if checked detects nodes.
mode:
All - detects to radius in all directions, including diagonal.
Forward - detects to radius directly in front of the detector (one block high).
Up - detects to radius directly above the detector (one block wide).
Down - detects to radius directly below the detector (one block wide).
Mesecons
Mesecons power is turned on when something is detected, and turned off
when nothing is detected.
Digilines messages
"start"
Start the detector.
"stop"
Stop the detector.
"radius <n>"
Set radius of the detector. <n> should be a number from 1 to 5, and is
trimmed to this range.
"entities <true|false>"
Set detection of entities on or off.
"players <true|false>"
Set detection of players on or off.
"drops <true|false>"
Set detection of drops on or off.
"nodes <true|false>"
Set detection of nodes on or off.
"mode all"
"mode forward"
"mode up"
"mode down"
Set the detector's mode.
When items or entities are detected a digilines message is sent with the
detector's channel. A message is sent for each found item/entity. The
message is a table with the following keys:
{
action = "detect",
detected = table
}
The detected field is a list of detected items. Each entry is of the form:
{
type = "<type>", -- will be "entity", "player", "drop" or "node"
name = "<name>",
label = "<label>",
pos = { x = n, y = n, z = n },
count = <count>,
hp = <number>,
height = <number>
}
type
Will be "entity", "player", "drop" or "node".
name
For "entity" the registered entity name.
For "player" the player's name.
For "drop" the registered item name.
For "node" the registered item name.
label
For "entity" the name tag text.
For "player" the player's name.
For "drop" the registered item name.
For "node" the registered item name.
pos
The relative position of the detected item/entity from the detector,
facing the direction of the detector.
+x = right
-x = left
+z = forward
-z = behind
+y = above
-y = below
count
The count of items for a "drop", or 1 for everything else.
hp
Health points for players and entities. Zero for everything else.
height
Height for players and entities. Zero for everything else. This is simply
the top position of the object's collision box.

21
docs/digiswitch.txt Normal file
View File

@@ -0,0 +1,21 @@
DigiSwitch
----------
* This block is only available if both digilines and mesecons are loaded.
Digiswitches act as both a digilines message target and a digilines cable,
as well as a mesecons power source. They can be placed beside each other
to form a bank, horizontally or vertically.
Right click the digiswitch to give it a channel.
Mesecon power can be delivered at 6 sides of the digiswitch, the adjacent
4 in the (x, z), above and below. Around the connector on these sides are a
colored border indicating the side. The sides are named "red", "green",
"blue", "yellow", "white" and "black".
The digilines message sent to the digiswitch dictates the action, "on" or
"off". The action can be followed with the side to act upon, separated by
a space. eg. "on white". If a side is stated only that side is acted upon.
If the side is omitted (or is invalid) all 6 sides are acted upon. If the
side name "switch" is give the power is supplied the same as a mesecons
switch (all horizontal sides, one below, this height and one above).

43
docs/dispenser.txt Normal file
View File

@@ -0,0 +1,43 @@
Dispenser
---------
* This block is only available if digilines and/or mesecons are loaded.
Contains an inventory and dispenses (with velocity) an item on command.
Also acts as a digilines conductor. If the hopper mod is loaded, will take
items from the top and sides, and release them from the bottom.
To spawn entities from dispensers include the lwcomponents_spawners mod.
Only the owner can dig or access the form of the locked version.
UI
Channel - digilines channel of dispenser.
Top 16 slot inventory - storage of items to dispense.
Bottom 32 slot inventory - player's inventory.
Mesecons
Dispenses the next item when power is turned on.
Digilines messages
"dispense"
Dispenses the next item. No dispense if dispenser is empty.
"dispense <slot>"
Dispenses 1 item from the given slot (1 to 16). No dispense if slot is
empty.
eg. "dispense 7"
"dispense <itemname>"
Dispenses 1 item of the given name. No dispense if dispenser does not
contain the item.
eg. "dispense default:stone"
When an item is dropped a digilines message is sent with the dropper's
channel. The message is a table with the following keys:
{
action = "dispense",
name = "<itemname>", -- name of dropped item
slot = <slot> -- slot number the item was taken from (1 to 16).
}

40
docs/dropper.txt Normal file
View File

@@ -0,0 +1,40 @@
Dropper
-------
* This block is only available if digilines and/or mesecons are loaded.
Contains an inventory and drops an item on command. Also acts as a
digilines conductor. If the hopper mod is loaded, will take items from the
top and sides, and release them from the bottom.
Only the owner can dig or access the form of the locked version.
UI
Channel - digilines channel of dropper.
Top 16 slot inventory - storage of items to drop.
Bottom 32 slot inventory - player's inventory.
Mesecons
Drops the next item when power is turned on.
Digilines messages
"drop"
Drops the next item. No drop if dropper is empty.
"drop <slot>"
Drops 1 item from the given slot (1 to 16). No drop if slot is empty.
eg. "drop 7"
"drop <itemname>"
Drops 1 item of the given name. No drop if dropper does not contain the
item.
eg. "drop default:stone"
When an item is dropped a digilines message is sent with the dropper's
channel. The message is a table with the following keys:
{
action = "drop",
name = "<itemname>", -- name of dropped item
slot = <slot> -- slot number the item was taken from (1 to 16).
}

24
docs/fan.txt Normal file
View File

@@ -0,0 +1,24 @@
Fan
---
* This block is only available if digilines and/or mesecons are loaded.
Fans blow any entity, player or drop in front of the fan for 5 node
spaces in the direction of the fan. A node placed in these 5 spaces blocks
the fan's action beyond the placed node. Also acts as a digilines conductor.
Only the owner can dig or access the form of the locked version.
UI
Channel - digilines channel of fan.
Mesecons
Fan runs while power is turned on.
Digilines messages
"start"
Starts the fan.
"stop"
Stops the fan.

107
docs/hologram.txt Normal file
View File

@@ -0,0 +1,107 @@
Hologram
--------
* This block is only available if digilines is loaded.
Projects a hologram above the hologram node. Also acts as a digilines
conductor.
The hologram occupies a space 15x15x15. The lower level of the hologram
is 2 blocks above the hologram node (so the hologram node can be hidden
beneath a floor). The hologram node is in the x, z horizontal center, ie.
the hologram can extend 7 blocks in each direction from the node.
Colored blocks cannot be interacted with, but will be replaced if built
into. If a block already exists where the hologram requires a color, it
is not placed unless the block is a color block from this hologram block.
If an existing block is dug while a holograms is displayed it is not
filled in, the hologram has to be re-displayed.
Only the owner can dig or access the form of the locked version.
UI
Channel - digilines channel of hologram.
Digilines messages
"clear"
Removes any hologram currently projected.
table
To display a hologram a table of dimensions holo[15][15][15] is sent as
the message. The table structure is holo[layer][line][block]. In the
direction the hologram block is facing, the layers run from bottom to
top, the lines run from back to front, and the blocks run from right to
left. Each block value can be nil for no display, or a string with the
color. Valid colors are:
"black"
"gray"
"silver"
"white"
"sky"
"blue"
"cyan"
"lime"
"green"
"magenta"
"purple"
"pink"
"red"
"yellow"
"orange"
"brown"
If anything else no color block is placed.
For example:
{
{
{ "black", nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, "green" },
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{ "blue", nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, "red" }
},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{
{ "orange", nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, "lime" },
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{ "purple", nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, "yellow" }
},
}
will display a hologram with a black and green block at the back of
the bottom layer, and orange and lime at the back of the top layer.

17
docs/movefloor.txt Normal file
View File

@@ -0,0 +1,17 @@
MoveFloor
---------
* This block is only available if mesecons and mesecons_mvps is loaded.
The MoveFloor block responds to a mesecons power source in the 4 horizontal
directions. If the power source is one higher the MoveFloor moves up to
that height. If the power source is one lower the MoveFloor moves down to
that height. Powering an adjacent block has no effect. The power source
should be turned off before another move or the MoveFloor will oscillate.
Any horizontally adjoining MoveFloor acts as a single block (only one
needs to be powered).
The MoveFloor will move up to 3 blocks stacked on it.
If using a DigiSwitch as the power source use the side name "switch" or
the MoveFloor will not move.

21
docs/player_button.txt Normal file
View File

@@ -0,0 +1,21 @@
Player Button
-------------
* This block is only available if both digilines and digistuff are loaded.
When pressed sends a digilines message with the name of the player that
pressed the button.
The first time the button is right clicked a form opens to set the
digilines channel. After that right click presses the button. The
digilines cannot be changed after its set.
UI
Channel - digilines channel of button.
When the button is pressed a digilines message is sent with the button's
channel in the form:
{
action = "player",
name = <player name>
}

69
docs/puncher.txt Normal file
View File

@@ -0,0 +1,69 @@
Puncher
-------
* This block is only available if digilines and/or mesecons are loaded.
Punches players or entities within a given reach. Also acts as a
digilines conductor.
Only the owner can dig or access the form of the locked version.
UI
Channel - digilines channel of puncher.
Reach - block distance from puncher to punch.
Entities - if checked punches entities.
Players - if checked punches players.
mode:
Forward - punches to reach extent directly in front of the puncher (one block high).
Up - detects to reach extent directly above the puncher (one block wide).
Down - detects to reach extent directly below the puncher (one block wide).
Mesecons
Punches the next item when power is turned on.
Digilines messages
"start"
Start the puncher.
"stop"
Stop the puncher.
"reach <n>"
Set reach of the puncher. <n> should be a number from 1 to 5, and is
trimmed to this range.
"entities <true|false>"
Set punching of entities on or off.
"players <true|false>"
Set punching of players on or off.
"mode forward"
"mode up"
"mode down"
Set the puncher's mode.
"punch"
Action a single punch if the puncher is turned on.
When a player or entity is punched a digilines message is sent with the
puncher's channel. The message is a table with the following keys:
{
action = "punch",
type = "<type>", -- will be "entity" or "player"
name = "<name>",
label = "<label>"
}
type
Will be "entity" or "player".
name
For "entity" the registered entity name.
For "player" the player's name.
label
For "entity" the name tag text.
For "player" the player's name.

46
docs/siren.txt Normal file
View File

@@ -0,0 +1,46 @@
Siren
-----
* This block is only available if digilines and/or mesecons are loaded.
Plays a sound repeatedly while active. Also acts as a digilines conductor.
digilines conductor.
Only the owner can dig or access the form of the locked version.
UI
Channel - digilines channel of siren.
Distance - block distance the sound can be heard (range 0 to 100).
Volume - volume the sound is played.
Sound - select Buzzer, Horn, Raid or Siren.
Mesecons
Sound plays while mesecons power is applied.
Digilines messages
"start"
Start the siren (turn on).
"stop"
Stop the siren (turn off).
"distance <n>"
Set block distance the sound can be heard. <n> should be a number
from 1 to 100, and is trimmed to this range.
"volume <n>"
Set the sound volume. <n> should be a number from 1 to 100, and is
trimmed to this range.
"sound buzzer"
"sound horn"
"sound raid"
"sound siren"
Set the sound of the siren.
"siren on"
Activate the siren, if its on.
"siren off"
deactivate the siren.

View File

@@ -0,0 +1,9 @@
Solid Color Conductors
----------------------
* These blocks are only defined if mesecons and unifieddyes are loaded.
Provides 2 blocks that can be colored the same as Solid Color Block (with
the air brush) and is both a mesecons and digilines conductor.
The Solid Color Conductor block conducts in the 'default' directions and
the Solid Color Horizontal Conductor only conducts horizontally.

View File

@@ -301,7 +301,9 @@ local function digilines_support ()
if meta then if meta then
local this_channel = meta:get_string ("channel") local this_channel = meta:get_string ("channel")
if this_channel ~= "" and this_channel == channel then if this_channel ~= "" and this_channel == channel and
type (msg) == "string" then
local m = { } local m = { }
for w in string.gmatch(msg, "[^%s]+") do for w in string.gmatch(msg, "[^%s]+") do
m[#m + 1] = w m[#m + 1] = w

459
fan.lua Normal file
View File

@@ -0,0 +1,459 @@
local utils = ...
local S = utils.S
if utils.digilines_supported or utils.mesecon_supported then
local fan_interval = 0.2
local fan_force = 15.0
local function direction_vector (node)
local axis = math.floor (node.param2 / 4)
local rotate = node.param2 % 4
local vec = { x = 0, y = 0, z = 0 }
if rotate == 0 then
vec = { x = 0, y = 0, z = -1 }
elseif rotate == 1 then
vec = { x = -1, y = 0, z = 0 }
elseif rotate == 2 then
vec = { x = 0, y = 0, z = 1 }
elseif rotate == 3 then
vec = { x = 1, y = 0, z = 0 }
end
if axis == 1 then
vec = vector.rotate (vec, { x = math.pi / -2, y = 0, z = 0 })
elseif axis == 2 then
vec = vector.rotate (vec, { x = math.pi / 2, y = 0, z = 0 })
elseif axis == 3 then
vec = vector.rotate (vec, { x = 0, y = 0, z = math.pi / 2 })
elseif axis == 4 then
vec = vector.rotate (vec, { x = 0, y = 0, z = math.pi / -2 })
elseif axis == 5 then
vec = vector.rotate (vec, { x = math.pi, y = 0, z = 0 })
end
return vec
end
local function blow (pos)
local meta = minetest.get_meta (pos)
local node = minetest.get_node (pos)
local dir = direction_vector (node)
local reach = 5
for r = 1, reach, 1 do
local tpos = vector.add (pos, vector.multiply (dir, r))
local tnode = minetest.get_node_or_nil (tpos)
if tnode and tnode.name ~= "air" then
local def = utils.find_item_def (tnode.name)
if def and def.walkable then
return
end
end
local object = minetest.get_objects_inside_radius (tpos, 1.5)
local vel = vector.multiply (dir, (dir.y > 0 and fan_force / 2) or fan_force)
for i = 1, #object do
if object[i].add_velocity then
local opos = object[i]:get_pos ()
if opos.x >= (tpos.x - 0.5) and opos.x <= (tpos.x + 0.5) and
opos.z >= (tpos.z - 0.5) and opos.z <= (tpos.z + 0.5) and
opos.y >= (tpos.y - 0.5) and opos.y <= (tpos.y + 0.5) then
if object[i].get_luaentity and object[i]:get_luaentity () and
object[i]:get_luaentity ().name and
object[i]:get_luaentity ().name == "__builtin:item" then
object[i]:add_velocity (vector.multiply (vel, 5))
else
object[i]:add_velocity (vel)
end
end
end
end
end
end
local function fan_off (pos)
local node = minetest.get_node (pos)
if node then
if node.name == "lwcomponents:fan_on" then
node.name = "lwcomponents:fan"
minetest.get_node_timer (pos):stop ()
minetest.swap_node (pos, node)
elseif node.name == "lwcomponents:fan_locked_on" then
node.name = "lwcomponents:fan_locked"
minetest.get_node_timer (pos):stop ()
minetest.swap_node (pos, node)
end
end
end
local function fan_on (pos)
local node = minetest.get_node (pos)
if node then
if node.name == "lwcomponents:fan" then
node.name = "lwcomponents:fan_on"
minetest.swap_node (pos, node)
minetest.get_node_timer (pos):start (fan_interval)
elseif node.name == "lwcomponents:fan_locked" then
node.name = "lwcomponents:fan_locked_on"
minetest.swap_node (pos, node)
minetest.get_node_timer (pos):start (fan_interval)
end
end
end
local function on_place (itemstack, placer, pointed_thing)
local param2 = 0
if placer and placer:is_player () then
param2 = minetest.dir_to_facedir (placer:get_look_dir (), true)
elseif pointed_thing and pointed_thing.type == "node" then
param2 = minetest.dir_to_facedir (vector.subtract (pointed_thing.under, pointed_thing.above), true)
end
return minetest.item_place (itemstack, placer, pointed_thing, param2)
end
local function after_place_node (pos, placer, itemstack, pointed_thing)
local meta = minetest.get_meta (pos)
local spec =
"size[7.5,3]"..
"field[1,1;6,2;channel;Channel;${channel}]"..
"button_exit[2.5,2;3,1;submit;Set]"
meta:set_string ("formspec", spec)
-- 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", "Hologram (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
local meta = minetest.get_meta(pos)
if fields.submit then
meta:set_string ("channel", fields.channel)
end
end
local function on_blast (pos, intensity)
local meta = minetest.get_meta (pos)
if meta then
if intensity >= 1.0 then
clear_map (pos)
minetest.remove_node (pos)
else -- intensity < 1.0
clear_map (pos)
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
preserve_metadata (pos, node, meta, { stack })
utils.item_drop (stack, nil, pos)
minetest.remove_node (pos)
end
end
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_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 on_timer (pos, elapsed)
blow (pos)
return true
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 then
if type (msg) == "string" then
local m = { }
for w in string.gmatch(msg, "[^%s]+") do
m[#m + 1] = w
end
if m[1] == "start" then
fan_on (pos)
elseif m[1] == "stop" then
fan_off (pos)
end
end
end
end
end,
}
}
end
return nil
end
local function mesecon_support ()
if utils.mesecon_supported then
return
{
effector =
{
rules = utils.mesecon_default_rules,
action_on = function (pos, node)
-- do something to turn the effector on
fan_on (pos)
end,
action_off = function (pos, node)
-- do something to turn the effector off
fan_off (pos)
end,
}
}
end
return nil
end
minetest.register_node("lwcomponents:fan", {
description = S("Fan"),
tiles = { "lwfan.png", "lwfan.png", "lwfan.png",
"lwfan.png", "lwfan.png", "lwfan_face.png"},
is_ground_content = false,
groups = { cracky = 3 },
sounds = default.node_sound_stone_defaults (),
paramtype = "none",
param1 = 0,
paramtype2 = "facedir",
param2 = 0,
floodable = false,
drop = "lwcomponents:fan",
_digistuff_channelcopier_fieldname = "channel",
mesecons = mesecon_support (),
digiline = digilines_support (),
on_place = on_place,
on_receive_fields = on_receive_fields,
can_dig = can_dig,
after_place_node = after_place_node,
on_blast = on_blast,
on_rightclick = on_rightclick,
})
minetest.register_node("lwcomponents:fan_locked", {
description = S("Fan (locked)"),
tiles = { "lwfan.png", "lwfan.png", "lwfan.png",
"lwfan.png", "lwfan.png", "lwfan_face.png"},
is_ground_content = false,
groups = { cracky = 3 },
sounds = default.node_sound_stone_defaults (),
paramtype = "none",
param1 = 0,
paramtype2 = "facedir",
param2 = 0,
floodable = false,
drop = "lwcomponents:fan_locked",
_digistuff_channelcopier_fieldname = "channel",
mesecons = mesecon_support (),
digiline = digilines_support (),
on_place = on_place,
on_receive_fields = on_receive_fields,
can_dig = can_dig,
after_place_node = after_place_node_locked,
on_blast = on_blast,
on_rightclick = on_rightclick,
})
minetest.register_node("lwcomponents:fan_on", {
description = S("Fan"),
tiles = { "lwfan.png", "lwfan.png", "lwfan.png",
"lwfan.png", "lwfan.png", "lwfan_face_on.png"},
is_ground_content = false,
groups = { cracky = 3, not_in_creative_inventory = 1 },
sounds = default.node_sound_stone_defaults (),
paramtype = "none",
param1 = 0,
paramtype2 = "facedir",
param2 = 0,
floodable = false,
drop = "lwcomponents:fan",
_digistuff_channelcopier_fieldname = "channel",
mesecons = mesecon_support (),
digiline = digilines_support (),
on_place = on_place,
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:fan_locked_on", {
description = S("Fan (locked)"),
tiles = { "lwfan.png", "lwfan.png", "lwfan.png",
"lwfan.png", "lwfan.png", "lwfan_face_on.png"},
is_ground_content = false,
groups = { cracky = 3, not_in_creative_inventory = 1 },
sounds = default.node_sound_stone_defaults (),
paramtype = "none",
param1 = 0,
paramtype2 = "facedir",
param2 = 0,
floodable = false,
drop = "lwcomponents:fan_locked",
_digistuff_channelcopier_fieldname = "channel",
mesecons = mesecon_support (),
digiline = digilines_support (),
on_place = on_place,
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

424
hologram.lua Normal file
View File

@@ -0,0 +1,424 @@
local utils = ...
local S = utils.S
if utils.digilines_supported then
local hologram_block =
{
black = {
node = "lwcomponents:hologram_black",
image = "lwhologram_black.png",
color = { a = 128, r = 0, g = 0, b = 0 } },
orange = {
node = "lwcomponents:hologram_orange",
image = "lwhologram_orange.png",
color = { a = 128, r = 255, g = 128, b = 0 } },
magenta = {
node = "lwcomponents:hologram_magenta",
image = "lwhologram_magenta.png",
color = { a = 128, r = 255, g = 0, b = 255 } },
sky = {
node = "lwcomponents:hologram_sky",
image = "lwhologram_sky.png",
color = { a = 128, r = 0, g = 128, b = 255 } },
yellow = {
node = "lwcomponents:hologram_yellow",
image = "lwhologram_yellow.png",
color = { a = 128, r = 255, g = 255, b = 0 } },
pink = {
node = "lwcomponents:hologram_pink",
image = "lwhologram_pink.png",
color = { a = 128, r = 255, g = 128, b = 128 } },
cyan = {
node = "lwcomponents:hologram_cyan",
image = "lwhologram_cyan.png",
color = { a = 128, r = 0, g = 255, b = 255 } },
gray = {
node = "lwcomponents:hologram_gray",
image = "lwhologram_gray.png",
color = { a = 128, r = 128, g = 128, b = 128 } },
silver = {
node = "lwcomponents:hologram_silver",
image = "lwhologram_silver.png",
color = { a = 128, r = 192, g = 192, b = 192 } },
red = {
node = "lwcomponents:hologram_red",
image = "lwhologram_red.png",
color = { a = 128, r = 255, g = 0, b = 0 } },
green = {
node = "lwcomponents:hologram_green",
image = "lwhologram_green.png",
color = { a = 128, r = 0, g = 128, b = 0 } },
blue = {
node = "lwcomponents:hologram_blue",
image = "lwhologram_blue.png",
color = { a = 128, r = 0, g = 0, b = 255 } },
brown = {
node = "lwcomponents:hologram_brown",
image = "lwhologram_brown.png",
color = { a = 128, r = 128, g = 64, b = 0 } },
lime = {
node = "lwcomponents:hologram_lime",
image = "lwhologram_lime.png",
color = { a = 128, r = 0, g = 255, b = 0 } },
purple = {
node = "lwcomponents:hologram_purple",
image = "lwhologram_purple.png",
color = { a = 128, r = 128, g = 0, b = 128 } },
white = {
node = "lwcomponents:hologram_white",
image = "lwhologram_white.png",
color = { a = 128, r = 255, g = 255, b = 255 } },
}
local function rotate_to_dir (center, param2, point)
local base = vector.subtract (point, center)
if param2 == 1 then
base = vector.rotate (base, { x = 0, y = (math.pi * 1.5), z = 0 })
elseif param2 == 2 then
base = vector.rotate (base, { x = 0, y = math.pi, z = 0 })
elseif param2 == 3 then
base = vector.rotate (base, { x = 0, y = (math.pi * 0.5), z = 0 })
end
return vector.add (base, center)
end
local function draw_map (pos, map)
local meta = minetest.get_meta (pos)
local holonode = minetest.get_node (pos)
if meta and holonode and type (map) == "table" then
local id = meta:get_int ("block_id")
for y = 1, 15 do
local layer = (type (map[y]) == "table" and map[y]) or { }
for x = 1, 15 do
local line = (type (layer[x]) == "table" and layer[x]) or { }
for z = 1, 15 do
local map_point = { x = z + pos.x - 8, y = y + pos.y + 1, z = (16 - x) + pos.z - 8 }
local holopos = rotate_to_dir (pos, holonode.param2, map_point)
local node = utils.get_far_node (holopos)
local draw = false
if node and node.name ~= "air" then
if node.name:sub (1, 22) == "lwcomponents:hologram_" then
local nodemeta = minetest.get_meta (holopos)
if nodemeta and nodemeta:get_int ("block_id") == id then
draw = true
end
end
else
draw = true
end
if draw then
local holonode = hologram_block[line[z]]
if node then
utils.destroy_node (holopos)
end
if holonode then
minetest.set_node (holopos, { name = holonode.node })
local nodemeta = minetest.get_meta (holopos)
if nodemeta then
nodemeta:set_int ("block_id", id)
end
end
end
end
end
end
end
end
local function clear_map (pos)
draw_map (pos, { })
end
local function on_destruct (pos)
clear_map (pos)
end
local function after_place_node (pos, placer, itemstack, pointed_thing)
local meta = minetest.get_meta (pos)
local spec =
"size[7.5,3]"..
"field[1,1;6,2;channel;Channel;${channel}]"..
"button_exit[2.5,2;3,1;submit;Set]"
local id = math.random (1000000)
meta:set_string ("formspec", spec)
meta:set_int ("block_id", id)
-- 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", "Hologram (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
local meta = minetest.get_meta(pos)
if fields.submit then
meta:set_string ("channel", fields.channel)
end
end
local function on_blast (pos, intensity)
local meta = minetest.get_meta (pos)
if meta then
if intensity >= 1.0 then
clear_map (pos)
minetest.remove_node (pos)
else -- intensity < 1.0
clear_map (pos)
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
preserve_metadata (pos, node, meta, { stack })
utils.item_drop (stack, nil, pos)
minetest.remove_node (pos)
end
end
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_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 then
if type (msg) == "string" then
local m = { }
for w in string.gmatch(msg, "[^%s]+") do
m[#m + 1] = w
end
if m[1] == "clear" then
clear_map (pos)
end
elseif type (msg) == "table" then
draw_map (pos, msg)
end
end
end
end,
}
}
end
return nil
end
minetest.register_node("lwcomponents:hologram", {
description = S("Hologram"),
tiles = { "lwhologram.png", "lwhologram.png", "lwhologram.png",
"lwhologram.png", "lwhologram.png", "lwhologram_face.png"},
is_ground_content = false,
groups = { cracky = 3 },
sounds = default.node_sound_stone_defaults (),
paramtype = "light",
param1 = 0,
paramtype2 = "facedir",
param2 = 1,
floodable = false,
_digistuff_channelcopier_fieldname = "channel",
digiline = digilines_support (),
on_destruct = on_destruct,
after_place_node = after_place_node,
on_receive_fields = on_receive_fields,
on_blast = on_blast,
can_dig = can_dig,
on_rightclick = on_rightclick
})
minetest.register_node("lwcomponents:hologram_locked", {
description = S("Hologram (locked)"),
tiles = { "lwhologram.png", "lwhologram.png", "lwhologram.png",
"lwhologram.png", "lwhologram.png", "lwhologram_face.png"},
is_ground_content = false,
groups = { cracky = 3 },
sounds = default.node_sound_stone_defaults (),
paramtype = "light",
param1 = 0,
paramtype2 = "facedir",
param2 = 1,
floodable = false,
_digistuff_channelcopier_fieldname = "channel",
digiline = digilines_support (),
on_destruct = on_destruct,
after_place_node = after_place_node_locked,
on_receive_fields = on_receive_fields,
on_blast = on_blast,
can_dig = can_dig,
on_rightclick = on_rightclick
})
local function register_hologram_block (block)
local bc = hologram_block[block]
minetest.register_node(bc.node, {
description = S("Hologram "..block),
tiles = { bc.image },
drawtype = "glasslike",
light_source = 7,
use_texture_alpha = "blend",
sunlight_propagates = true,
walkable = false,
pointable = false,
diggable = false,
climbable = false,
buildable_to = true,
floodable = true,
is_ground_content = false,
groups = { not_in_creative_inventory = 1 },
paramtype = "light",
param1 = 255,
post_effect_color = bc.color,
})
end
register_hologram_block ("black")
register_hologram_block ("orange")
register_hologram_block ("magenta")
register_hologram_block ("sky")
register_hologram_block ("yellow")
register_hologram_block ("pink")
register_hologram_block ("cyan")
register_hologram_block ("gray")
register_hologram_block ("silver")
register_hologram_block ("red")
register_hologram_block ("green")
register_hologram_block ("blue")
register_hologram_block ("brown")
register_hologram_block ("lime")
register_hologram_block ("purple")
register_hologram_block ("white")
end -- utils.digilines_supported

View File

@@ -1,4 +1,4 @@
local version = "0.1.2" local version = "0.1.8"
local mod_storage = minetest.get_mod_storage () local mod_storage = minetest.get_mod_storage ()
@@ -16,12 +16,21 @@ local utils = { }
local modpath = minetest.get_modpath ("lwcomponents") local modpath = minetest.get_modpath ("lwcomponents")
loadfile (modpath.."/utils.lua") (utils, mod_storage) loadfile (modpath.."/utils.lua") (utils, mod_storage)
loadfile (modpath.."/settings.lua") (utils)
loadfile (modpath.."/api.lua") (utils)
utils.connections = loadfile (modpath.."/connections.lua") ()
loadfile (modpath.."/dropper.lua") (utils) loadfile (modpath.."/dropper.lua") (utils)
loadfile (modpath.."/collector.lua") (utils) loadfile (modpath.."/collector.lua") (utils)
loadfile (modpath.."/dispenser.lua") (utils) loadfile (modpath.."/dispenser.lua") (utils)
loadfile (modpath.."/detector.lua") (utils) loadfile (modpath.."/detector.lua") (utils)
loadfile (modpath.."/siren.lua") (utils) loadfile (modpath.."/siren.lua") (utils)
loadfile (modpath.."/puncher.lua") (utils) loadfile (modpath.."/puncher.lua") (utils)
loadfile (modpath.."/player_button.lua") (utils)
loadfile (modpath.."/hologram.lua") (utils)
loadfile (modpath.."/breaker.lua") (utils)
loadfile (modpath.."/deployer.lua") (utils)
loadfile (modpath.."/fan.lua") (utils)
loadfile (modpath.."/conduit.lua") (utils, mod_storage)
loadfile (modpath.."/extras.lua") (utils) loadfile (modpath.."/extras.lua") (utils)
loadfile (modpath.."/digiswitch.lua") (utils) loadfile (modpath.."/digiswitch.lua") (utils)
loadfile (modpath.."/movefloor.lua") (utils) loadfile (modpath.."/movefloor.lua") (utils)

View File

@@ -64,6 +64,11 @@ Media license
siren images derived from images from https://openclipart.org, which is siren images derived from images from https://openclipart.org, which is
public domain. public domain.
fan images derived from images from https://openclipart.org, which is
public domain.
player button images derived from mesecons button image.
All other media, or media not covered by a licence, is licensed All other media, or media not covered by a licence, is licensed
Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0) Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)

View File

@@ -3,4 +3,4 @@ description = Various components for mesecons and digilines.
title = LWComponents title = LWComponents
name = lwcomponents name = lwcomponents
depends = default depends = default
optional_depends = lwdrops, mesecons, digilines, unifieddyes, intllib, hopper optional_depends = lwdrops, mesecons, digilines, unifieddyes, intllib, hopper, digistuff

232
player_button.lua Normal file
View File

@@ -0,0 +1,232 @@
local utils = ...
local S = utils.S
if utils.digilines_supported and utils.digistuff_supported then
local function on_contruct (pos)
local meta = minetest.get_meta(pos)
local spec =
"size[7.5,3]"..
"field[1,1;6,2;channel;Channel;${channel}]"..
"button_exit[2.5,2;3,1;submit;Set]"
meta:set_string("formspec", spec)
end
local function on_receive_fields (pos, formname, fields, sender)
local meta = minetest.get_meta(pos)
if fields.submit then
if fields.channel ~= "" then
meta:set_string ("channel", fields.channel)
meta:set_string ("formspec", "")
minetest.swap_node (pos, { name = "lwcomponents:player_button_off",
param2 = minetest.get_node(pos).param2 })
else
minetest.chat_send_player (sender:get_player_name(), "Please set a channel!")
end
end
end
local function player_button_push (pos, node, player)
local meta = minetest.get_meta (pos)
if player and player:is_player () then
local channel = meta:get_string ("channel")
local formspec = meta:get_string ("formspec")
if channel:len () > 0 and formspec:len () == 0 then
utils.digilines_receptor_send (pos,
digistuff.button_get_rules (node),
channel,
{ action = "player",
name = player:get_player_name () })
end
end
if node.name == "lwcomponents:player_button_off" then
node.name = "lwcomponents:player_button_on"
minetest.swap_node(pos, node)
if digistuff.mesecons_installed then
minetest.sound_play ("mesecons_button_push", { pos = pos })
end
minetest.get_node_timer (pos):start (0.25)
end
end
local function player_button_turnoff (pos)
local node = minetest.get_node(pos)
local meta = minetest.get_meta(pos)
if node.name == "lwcomponents:player_button_on" then
node.name = "lwcomponents:player_button_off"
minetest.swap_node (pos, node)
if digistuff.mesecons_installed then
minetest.sound_play ("mesecons_button_pop", { pos = pos })
end
end
end
minetest.register_node ("lwcomponents:player_button", {
description = "Player Button",
drawtype = "nodebox",
tiles = {
"lwplayer_button_side.png",
"lwplayer_button_side.png",
"lwplayer_button_side.png",
"lwplayer_button_side.png",
"lwplayer_button_side.png",
"lwplayer_button.png"
},
paramtype = "light",
paramtype2 = "facedir",
legacy_wallmounted = true,
walkable = false,
sunlight_propagates = true,
drop = "lwcomponents:player_button",
selection_box = {
type = "fixed",
fixed = { -6/16, -6/16, 5/16, 6/16, 6/16, 8/16 }
},
node_box = {
type = "fixed",
fixed = {
{ -6/16, -6/16, 6/16, 6/16, 6/16, 8/16 }, -- the thin plate behind the button
{ -4/16, -2/16, 4/16, 4/16, 2/16, 6/16 } -- the button itself
}
},
groups = { dig_immediate = 2, digiline_receiver = 1 },
_digistuff_channelcopier_fieldname = "channel",
sounds = default and default.node_sound_stone_defaults(),
digiline =
{
receptor = {},
wire = {
rules = digistuff.button_get_rules,
},
},
on_construct = on_contruct,
after_place_node = digistuff.place_receiver,
after_destruct = digistuff.remove_receiver,
on_receive_fields = on_receive_fields,
})
minetest.register_node ("lwcomponents:player_button_off", {
description = "Player Button",
drawtype = "nodebox",
tiles = {
"lwplayer_button_side.png",
"lwplayer_button_side.png",
"lwplayer_button_side.png",
"lwplayer_button_side.png",
"lwplayer_button_side.png",
"lwplayer_button.png"
},
paramtype = "light",
paramtype2 = "facedir",
legacy_wallmounted = true,
walkable = false,
sunlight_propagates = true,
drop = "lwcomponents:player_button",
selection_box = {
type = "fixed",
fixed = { -6/16, -6/16, 5/16, 6/16, 6/16, 8/16 }
},
node_box = {
type = "fixed",
fixed = {
{ -6/16, -6/16, 6/16, 6/16, 6/16, 8/16 }, -- the thin plate behind the button
{ -4/16, -2/16, 4/16, 4/16, 2/16, 6/16 } -- the button itself
}
},
groups = { dig_immediate = 2, digiline_receiver = 1, not_in_creative_inventory = 1 },
_digistuff_channelcopier_fieldname = "channel",
sounds = default and default.node_sound_stone_defaults(),
digiline =
{
receptor = {},
wire = {
rules = digistuff.button_get_rules,
},
effector = {
action = digistuff.button_handle_digilines,
},
},
after_destruct = digistuff.remove_receiver,
on_rightclick = player_button_push,
})
minetest.register_node ("lwcomponents:player_button_on", {
description = "Player Button",
drawtype = "nodebox",
tiles = {
"lwplayer_button_side.png",
"lwplayer_button_side.png",
"lwplayer_button_side.png",
"lwplayer_button_side.png",
"lwplayer_button_side.png",
"lwplayer_button_on.png"
},
paramtype = "light",
paramtype2 = "facedir",
legacy_wallmounted = true,
walkable = false,
sunlight_propagates = true,
light_source = 7,
drop = "lwcomponents:player_button",
selection_box = {
type = "fixed",
fixed = { -6/16, -6/16, 5/16, 6/16, 6/16, 8/16 }
},
node_box = {
type = "fixed",
fixed = {
{ -6/16, -6/16, 6/16, 6/16, 6/16, 8/16 },
{ -4/16, -2/16, 11/32, 4/16, 2/16, 6/16 }
}
},
groups = { dig_immediate = 2, digiline_receiver = 1, not_in_creative_inventory = 1 },
_digistuff_channelcopier_fieldname = "channel",
sounds = default and default.node_sound_stone_defaults(),
digiline =
{
receptor = {},
wire = {
rules = digistuff.button_get_rules,
},
},
after_destruct = digistuff.remove_receiver,
-- on_rightclick = player_button_push,
on_timer = player_button_turnoff,
})
end -- utils.digilines_supported and utils.digistuff_supported

View File

@@ -421,7 +421,9 @@ local function digilines_support ()
if meta then if meta then
local this_channel = meta:get_string ("channel") local this_channel = meta:get_string ("channel")
if this_channel ~= "" and this_channel == channel then if this_channel ~= "" and this_channel == channel and
type (msg) == "string" then
local m = { } local m = { }
for w in string.gmatch(msg, "[^%s]+") do for w in string.gmatch(msg, "[^%s]+") do
m[#m + 1] = w m[#m + 1] = w

View File

@@ -13,7 +13,7 @@ CC BY-SA 3.0
Version Version
======= =======
0.1.2 0.1.8
Minetest Version Minetest Version
@@ -34,6 +34,7 @@ digilines
unifieddyes unifieddyes
intllib intllib
hopper hopper
digistuff
Installation Installation
@@ -50,399 +51,45 @@ Description
=========== ===========
Various components for mesecons and digilines. Various components for mesecons and digilines.
* Dropper, drops an item on command.
* Dispenser, dispenses (with velocity) an item on command.
Dropper * Collector, picks up dropped items in adjacent block, with optional filtering.
------- * Detector, detects items or entities within a given radius.
* This block is only available if digilines and/or mesecons are loaded. * Siren, plays a sound repeatedly while active.
* Puncher, punches players or entities within a given reach.
Contains an inventory and drops an item on command. Also acts as a * Player button, sends digilines message with player name.
digilines conductor. If the hopper mod is loaded, will take items from the * Breaker, digs the nodes directly in front.
top and sides, and release them from the bottom. * Deployers, places the nodes directly in front.
* Hologram, projects a hologram above the hologram node.
UI * Fan, blows any entity, player or drop in front of the fan.
* Conduit, connected in a circuit to move items.
Channel - digilines channel of dropper. * Digiswitch, digilines controlled mesecons power.
Top 16 slot inventory - storage of items to drop. * Movefloor, similar to vertical mesecons movestone.
Bottom 32 slot inventory - player's inventory. * Solid color conductor blocks, same as Solid Color Block but also mesecons
and digilines conductor.
Mesecons
Drops the next item when power is turned on. To spawn entities from dispensers include the lwcomponents_spawners mod.
Digilines messages See the docs folder for details on each item.
"drop"
Drops the next item. No drop if dropper is empty.
"drop <slot>"
Drops 1 item from the given slot (1 to 16). No drop if slot is empty.
eg. "drop 7"
"drop <itemname>"
Drops 1 item of the given name. No drop if dropper does not contain the
item.
eg. "drop default:stone"
When an item is dropped a digilines message is sent with the dropper's
channel. The message is a table with the following keys:
{
action = "drop",
name = "<itemname>", -- name of dropped item
slot = <slot> -- slot number the item was taken from (1 to 16).
}
Dispenser
---------
* This block is only available if digilines and/or mesecons are loaded.
Contains an inventory and dispenses (with velocity) an item on command.
Also acts as a digilines conductor. If the hopper mod is loaded, will take
items from the top and sides, and release them from the bottom.
UI
Channel - digilines channel of dispenser.
Top 16 slot inventory - storage of items to dispense.
Bottom 32 slot inventory - player's inventory.
Mesecons
Dispenses the next item when power is turned on.
Digilines messages
"dispense"
Dispenses the next item. No dispense if dispenser is empty.
"dispense <slot>"
Dispenses 1 item from the given slot (1 to 16). No dispense if slot is
empty.
eg. "dispense 7"
"dispense <itemname>"
Dispenses 1 item of the given name. No dispense if dispenser does not
contain the item.
eg. "dispense default:stone"
When an item is dropped a digilines message is sent with the dropper's
channel. The message is a table with the following keys:
{
action = "dispense",
name = "<itemname>", -- name of dropped item
slot = <slot> -- slot number the item was taken from (1 to 16).
}
Collector
---------
* This block is only available if digilines is loaded.
Picks up dropped items in adjacent block, with optional filtering. Also
acts as a digilines conductor. If the hopper mod is loaded, will take items
from the top and sides, and release them from the bottom.
UI
Channel - digilines channel of collector.
Left 16 slot inventory - storage of picked up items.
Right 8 slot inventory - Filter list. Place what items should be picked
up in this list. Leave empty to pick up all.
Bottom 32 slot inventory - player's inventory.
Digilines messages
"start"
Start the collector.
"stop"
Stop the collector.
When items are picked up a digilines message is sent with the collector's
channel. The message is a table with the following keys:
{
action = "collect",
name = "<itemname>", -- name of picked up items.
count = <count> -- number of the item picked up.
}
Detector
--------
* This block is only available if digilines and/or mesecons are loaded.
Detects items or entities within a given radius. Also acts as a
digilines conductor.
UI
Channel - digilines channel of detector.
Radius - block distance from detector to detect.
Entities - if checked detects entities.
Players - if checked detects players.
Drops - if checked detects drops.
Nodes - if checked detects nodes.
mode:
All - detects to radius in all directions, including diagonal.
Forward - detects to radius directly in front of the detector (one block high).
Up - detects to radius directly above the detector (one block wide).
Down - detects to radius directly below the detector (one block wide).
Mesecons
Mesecons power is turned on when something is detected, and turned off
when nothing is detected.
Digilines messages
"start"
Start the detector.
"stop"
Stop the detector.
"radius <n>"
Set radius of the detector. <n> should be a number from 1 to 5, and is
trimmed to this range.
"entities <true|false>"
Set detection of entities on or off.
"players <true|false>"
Set detection of players on or off.
"drops <true|false>"
Set detection of drops on or off.
"nodes <true|false>"
Set detection of nodes on or off.
"mode all"
"mode forward"
"mode up"
"mode down"
Set the detector's mode.
When items or entities are detected a digilines message is sent with the
detector's channel. A message is sent for each found item/entity. The
message is a table with the following keys:
{
action = "detect",
type = "<type>", -- will be "entity", "player", "drop" or "node"
name = "<name>",
label = "<label>",
pos = { x = n, y = n, z = n },
count = <count>
}
type
Will be "entity", "player", "drop" or "node".
name
For "entity" the registered entity name.
For "player" the player's name.
For "drop" the registered item name.
For "node" the registered item name.
label
For "entity" the name tag text.
For "player" the player's name.
For "drop" the registered item name.
For "node" the registered item name.
pos
The relative position of the detected item/entity from the detector,
facing the direction of the detector.
+x = right
-x = left
+z = forward
-z = behind
+y = above
-y = below
count
The count of items for a "drop", or 1 for everything else.
Siren
-----
* This block is only available if digilines and/or mesecons are loaded.
Plays a sound repeatedly while active. Also acts as a digilines conductor.
UI
Channel - digilines channel of siren.
Distance - block distance the sound can be heard (range 0 to 100).
Volume - volume the sound is played.
Sound - select Buzzer, Horn, Raid or Siren.
Mesecons
Sound plays while mesecons power is applied.
Digilines messages
"start"
Start the siren (turn on).
"stop"
Stop the siren (turn off).
"distance <n>"
Set block distance the sound can be heard. <n> should be a number
from 1 to 100, and is trimmed to this range.
"volume <n>"
Set the sound volume. <n> should be a number from 1 to 100, and is
trimmed to this range.
"sound buzzer"
"sound horn"
"sound raid"
"sound siren"
Set the sound of the siren.
"siren on"
Activate the siren, if its on.
"siren off"
deactivate the siren.
Puncher
-------
* This block is only available if digilines and/or mesecons are loaded.
Punches players or entities within a given reach. Also acts as a
digilines conductor.
UI
Channel - digilines channel of detector.
Reach - block distance from puncher to punch.
Entities - if checked punches entities.
Players - if checked punches players.
mode:
Forward - punches to reach extent directly in front of the puncher (one block high).
Up - detects to reach extent directly above the puncher (one block wide).
Down - detects to reach extent directly below the puncher (one block wide).
Mesecons
Punches the next item when power is turned on.
Digilines messages
"start"
Start the puncher.
"stop"
Stop the puncher.
"reach <n>"
Set reach of the puncher. <n> should be a number from 1 to 5, and is
trimmed to this range.
"entities <true|false>"
Set punching of entities on or off.
"players <true|false>"
Set punching of players on or off.
"mode forward"
"mode up"
"mode down"
Set the puncher's mode.
"punch"
Action a single punch if the puncher is turned on.
When a player or entity is punched a digilines message is sent with the
puncher's channel. The message is a table with the following keys:
{
action = "punch",
type = "<type>", -- will be "entity" or "player"
name = "<name>",
label = "<label>"
}
type
Will be "entity" or "player".
name
For "entity" the registered entity name.
For "player" the player's name.
label
For "entity" the name tag text.
For "player" the player's name.
DigiSwitch
----------
* This block is only available if both digilines and mesecons are loaded.
Digiswitches act as both a digilines message target and a digilines cable,
as well as a mesecons power source. They can be placed beside each other
to form a bank, horizontally or vertically.
Right click the digiswitch to give it a channel.
Mesecon power can be delivered at 6 sides of the digiswitch, the adjacent
4 in the (x, z), above and below. Around the connector on these sides are a
colored border indicating the side. The sides are named "red", "green",
"blue", "yellow", "white" and "black".
The digilines message sent to the digiswitch dictates the action, "on" or
"off". The action can be followed with the side to act upon, separated by
a space. eg. "on white". If a side is stated only that side is acted upon.
If the side is omitted (or is invalid) all 6 sides are acted upon. If the
side name "switch" is give the power is supplied the same as a mesecons
switch (all horizontal sides, one below, this height and one above).
MoveFloor
---------
* This block is only available if mesecons and mesecons_mvps is loaded.
The MoveFloor block responds to a mesecons power source in the 4 horizontal
directions. If the power source is one higher the MoveFloor moves up to
that height. If the power source is one lower the MoveFloor moves down to
that height. Powering an adjacent block has no effect. The power source
should be turned off before another move or the MoveFloor will oscillate.
Any horizontally adjoining MoveFloor acts as a single block (only one
needs to be powered).
The MoveFloor will move up to 3 blocks stacked on it.
If using a DigiSwitch as the power source use the side name "switch" or
the MoveFloor will not move.
Solid Color Conductors
----------------------
* These blocks are only defined if mesecons and unifieddyes are loaded.
Provides 2 blocks that can be colored the same as Solid Color Block (with
the air brush) and is both a mesecons and digilines conductor.
The Solid Color Conductor block conducts in the 'default' directions and
the Solid Color Horizontal Conductor only conducts horizontally.
The following are also defined as variants of the original mod item, if The following are also defined as variants of the original mod item, if
the relevant mod is loaded. the relevant mod is loaded.
+ lwcomponents:touchscreen - digistuff:touchscreen as full sized node. * Touchscreen, full node variant of digistuff:touchscreen.
+ lwcomponents:panel - digistuff:panel as full sized node. * Panel, full node variant of digistuff:panel.
The mod supports the following settings:
Spawn mobs
Allow dispensers to spawn mobs instead of spawners.
Default: true
Alert handler errors
Issue errors when handler's of other mods fail.
Default: true

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 64 KiB

14
settings.lua Normal file
View File

@@ -0,0 +1,14 @@
local utils = ...
utils.settings = { }
utils.settings.spawn_mobs =
minetest.settings:get_bool ("lwcomponents_spawn_mobs", true)
utils.settings.alert_handler_errors =
minetest.settings:get_bool ("lwcomponents_alert_handler_errors", true)
--

5
settingtypes.txt Normal file
View File

@@ -0,0 +1,5 @@
# Allow dispensers to spawn mobs instead of spawners.
lwcomponents_spawn_mobs (Spawn mobs) bool true
# Issue errors when handler's of other mods fail.
lwcomponents_alert_handler_errors (Alert handler errors) bool true

View File

@@ -433,7 +433,9 @@ local function digilines_support ()
if meta then if meta then
local this_channel = meta:get_string ("channel") local this_channel = meta:get_string ("channel")
if this_channel ~= "" and this_channel == channel then if this_channel ~= "" and this_channel == channel and
type (msg) == "string" then
local m = { } local m = { }
for w in string.gmatch(msg, "[^%s]+") do for w in string.gmatch(msg, "[^%s]+") do
m[#m + 1] = w m[#m + 1] = w

BIN
textures/lwbreaker.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 495 B

BIN
textures/lwbreaker_face.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 539 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 535 B

BIN
textures/lwbreaker_rear.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
textures/lwconduit.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
textures/lwconduit_edge.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
textures/lwdeployer.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 495 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
textures/lwfan.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 495 B

BIN
textures/lwfan_face.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 899 B

BIN
textures/lwfan_face_on.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 772 B

BIN
textures/lwhologram.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 495 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 539 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 B

BIN
textures/lwhologram_red.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 B

BIN
textures/lwhologram_sky.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 420 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 431 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 B

118
utils.lua
View File

@@ -129,6 +129,15 @@ end
-- check for digistuff
if minetest.global_exists ("digistuff") then
utils.digistuff_supported = true
else
utils.digistuff_supported = false
end
function utils.can_interact_with_node (pos, player) function utils.can_interact_with_node (pos, player)
if not player or not player:is_player () then if not player or not player:is_player () then
return false return false
@@ -153,4 +162,113 @@ end
function utils.get_far_node (pos)
local node = minetest.get_node (pos)
if node.name == "ignore" then
minetest.get_voxel_manip ():read_from_map (pos, pos)
node = minetest.get_node (pos)
if node.name == "ignore" then
return nil
end
end
return node
end
function utils.find_item_def (name)
local def = minetest.registered_items[name]
if not def then
def = minetest.registered_craftitems[name]
end
if not def then
def = minetest.registered_nodes[name]
end
if not def then
def = minetest.registered_tools[name]
end
return def
end
function utils.destroy_node (pos)
local node = utils.get_far_node (pos)
if node then
local items = minetest.get_node_drops (node, nil)
if items then
for i = 1, #items do
local stack = ItemStack (items[i])
if stack and not stack:is_empty () then
local name = stack:get_name ()
local def = utils.find_item_def (name)
if def then
if def.preserve_metadata then
def.preserve_metadata (pos, node, minetest.get_meta (pos), { stack })
end
utils.on_destroy (stack)
end
end
end
end
minetest.remove_node (pos)
end
end
utils.registered_spawners = { }
-- each entry [spawner_itemname] = spawner_func
function utils.register_spawner (itemname, spawn_func)
if type (itemname) == "string" and type (spawn_func) == "function" then
if not utils.registered_spawners[itemname] then
utils.registered_spawners[itemname] = spawn_func
return true
end
end
return false
end
function utils.spawn_registered (itemname, spawn_pos, itemstack, owner, spawner_pos, spawner_dir, force)
local func = utils.registered_spawners[itemname]
if func then
local result, obj, cancel = pcall (func, spawn_pos, itemstack, owner, spawner_pos, spawner_dir, force)
if result and (obj == nil or type (obj) == "userdata" or type (obj) == "table") then
return obj, cancel
end
minetest.log ("error", "lwcomponents.register_spawner spawner function for "..itemname.." failed "..
((type (obj) == "string" and obj) or ""))
return nil, true
end
return nil, false
end
-- --