Compare commits

..

7 Commits

Author SHA1 Message Date
loosewheel
17d23114fc Add files via upload 2021-11-23 04:48:27 +10:00
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
30 changed files with 2212 additions and 234 deletions

View File

@@ -2,7 +2,7 @@ local utils = ...
-- function (spawn_pos, itemstack, owner, spawner_pos, spawner_dir)
-- 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

View File

@@ -37,7 +37,27 @@ end
local function send_break_message (pos, action, name)
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)
@@ -49,7 +69,8 @@ local function send_break_message (pos, action, name)
utils.digilines_default_rules,
channel,
{ action = action,
name = name })
name = name,
range = range })
end
end
end
@@ -105,21 +126,11 @@ end
local function play_dug_sound (pos, nodename)
local def = utils.find_item_def (nodename)
if def and def.sounds and def.sounds.dug then
minetest.sound_play (def.sounds.dug, { pos = pos })
end
end
local function can_break_node (pos)
local function can_break_node (pos, breakpos)
local node = minetest.get_node (pos)
if node then
local dig_node = minetest.get_node (get_breaker_side (pos, node.param2, "front"))
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]
@@ -160,40 +171,85 @@ end
local function break_node (pos)
local diggable, tool, wear = can_break_node (pos)
local node = minetest.get_node (pos)
local function dig_node (pos, toolname)
local node = minetest.get_node_or_nil (pos)
local dig = false
local drops = nil
if diggable and node then
local break_pos = get_breaker_side (pos, node.param2, "front")
local break_node = minetest.get_node (break_pos)
if toolname == true then
dig = true
toolname = nil
end
if break_node then
local items = minetest.get_node_drops (break_node, tool)
local break_name = break_node.name
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
local eject_pos = get_breaker_side (pos, node.param2, "back")
drops = { }
for i = 1, #items do
local stack = ItemStack (items[i])
if stack and not stack:is_empty () then
local item_def = utils.find_item_def (stack:get_name ())
if item_def and item_def.preserve_metadata then
item_def.preserve_metadata (pos, node, minetest.get_meta (pos), { stack })
drops[i] = ItemStack (items[i])
end
utils.item_drop (stack, nil, eject_pos)
end
if def and def.preserve_metadata then
def.preserve_metadata (pos, node, minetest.get_meta (pos), drops)
end
end
minetest.remove_node (break_pos)
play_dug_sound (break_pos, break_name)
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)
send_break_message (pos, "break", break_name, range)
end
end
end
end
end
end
@@ -222,22 +278,24 @@ end
local function breaker_on (pos)
local function breaker_on (pos, range)
local node = minetest.get_node (pos)
if node then
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)
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)
break_node (pos, range)
minetest.get_node_timer (pos):start (break_interval)
end
@@ -298,7 +356,7 @@ local function after_place_node_locked (pos, placer, itemstack, pointed_thing)
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 ()..")")
meta:set_string ("infotext", "Breaker (owned by "..placer:get_player_name ()..")")
end
-- If return true no item is taken from itemstack
@@ -480,7 +538,7 @@ local function digilines_support ()
end
if m[1] == "break" then
breaker_on (pos)
breaker_on (pos, m[2])
elseif m[1] == "eject" then
eject_tool (pos, m[2])
@@ -508,7 +566,7 @@ local function mesecon_support ()
action_on = function (pos, node)
-- do something to turn the effector on
breaker_on (pos)
breaker_on (pos, 1)
end,
}
}
@@ -522,7 +580,7 @@ end
minetest.register_node("lwcomponents:breaker", {
description = S("Breaker"),
tiles = { "lwbreaker.png", "lwbreaker.png", "lwbreaker.png",
"lwbreaker.png", "lwbreaker.png", "lwbreaker_face.png"},
"lwbreaker.png", "lwbreaker_rear.png", "lwbreaker_face.png"},
is_ground_content = false,
groups = { cracky = 3 },
sounds = default.node_sound_stone_defaults (),
@@ -551,7 +609,7 @@ minetest.register_node("lwcomponents:breaker", {
minetest.register_node("lwcomponents:breaker_locked", {
description = S("Breaker (locked)"),
tiles = { "lwbreaker.png", "lwbreaker.png", "lwbreaker.png",
"lwbreaker.png", "lwbreaker.png", "lwbreaker_face.png"},
"lwbreaker.png", "lwbreaker_rear.png", "lwbreaker_face.png"},
is_ground_content = false,
groups = { cracky = 3 },
sounds = default.node_sound_stone_defaults (),
@@ -581,7 +639,7 @@ minetest.register_node("lwcomponents:breaker_locked", {
minetest.register_node("lwcomponents:breaker_on", {
description = S("Breaker"),
tiles = { "lwbreaker.png", "lwbreaker.png", "lwbreaker.png",
"lwbreaker.png", "lwbreaker.png", "lwbreaker_face_on.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 (),
@@ -611,7 +669,7 @@ minetest.register_node("lwcomponents:breaker_on", {
minetest.register_node("lwcomponents:breaker_locked_on", {
description = S("Breaker (locked)"),
tiles = { "lwbreaker.png", "lwbreaker.png", "lwbreaker.png",
"lwbreaker.png", "lwbreaker.png", "lwbreaker_face_on.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 (),

View File

@@ -37,3 +37,24 @@ 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.
v0.1.9
* Fixed infotext on various nodes.

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", "Conduit (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

@@ -113,6 +113,24 @@ minetest.register_craft( {
})
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 = {
@@ -130,6 +148,26 @@ minetest.register_craft( {
},
})
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

View File

@@ -5,5 +5,4 @@ digilines?
unifieddyes?
intllib?
hopper?
mobs?
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, hp, height)
local function send_detect_message (pos, detected_list)
if utils.digilines_supported then
local meta = minetest.get_meta (pos)
@@ -72,13 +72,7 @@ local function send_detect_message (pos, item_type, name, label, item_pos, count
utils.digilines_default_rules,
channel,
{ action = "detect",
type = item_type,
name = name,
label = label,
pos = to_relative_coords (pos, item_pos),
count = count,
hp = hp,
height = height })
detected = detected_list })
end
end
end
@@ -169,6 +163,7 @@ local function detect (pos)
local radius = meta:get_int ("radius")
local mode = meta:get_int ("mode")
local object = minetest.get_objects_inside_radius (pos, radius + 0.5)
local detected_list = { }
for i = 1, #object do
if object[i]:is_player () then
@@ -177,14 +172,16 @@ local function detect (pos)
if meta:get_string ("players") == "true" and
filter_item (pos, mode, object[i]:get_pos ()) then
send_detect_message (pos,
"player",
object[i]:get_player_name (),
object[i]:get_player_name (),
object[i]:get_pos (),
1,
object[i]:get_hp (),
get_entity_height (object[i]))
detected_list[#detected_list + 1] =
{
type = "player",
name = object[i]:get_player_name (),
label = object[i]:get_player_name (),
pos = to_relative_coords (pos, object[i]:get_pos ()),
count = 1,
hp = object[i]:get_hp (),
height = get_entity_height (object[i])
}
detected = true
end
@@ -200,14 +197,17 @@ local function detect (pos)
local stack = ItemStack (object[i]:get_luaentity ().itemstring or "")
if stack and not stack:is_empty () then
send_detect_message (pos,
"drop",
stack:get_name (),
stack:get_name (),
object[i]:get_pos (),
stack:get_count (),
0,
0)
detected_list[#detected_list + 1] =
{
type = "drop",
name = stack:get_name (),
label = stack:get_name (),
pos = to_relative_coords (pos, object[i]:get_pos ()),
count = stack:get_count (),
hp = 0,
height = 0
}
detected = true
end
@@ -231,14 +231,16 @@ local function detect (pos)
object[i]:get_luaentity () and
object[i]:get_luaentity ().name) or ""
send_detect_message (pos,
"entity",
name,
label,
object[i]:get_pos (),
1,
object[i]:get_hp (),
get_entity_height (object[i]))
detected_list[#detected_list + 1] =
{
type = "entity",
name = name,
label = label,
pos = to_relative_coords (pos, object[i]:get_pos ()),
count = 1,
hp = object[i]:get_hp (),
height = get_entity_height (object[i])
}
detected = true
@@ -258,14 +260,16 @@ local function detect (pos)
if node and node.name ~= "air" and node.name ~= "ignore" and
filter_item (pos, mode, testpos) then
send_detect_message (pos,
"node",
node.name,
node.name,
testpos,
1,
0,
0)
detected_list[#detected_list + 1] =
{
type = "node",
name = node.name,
label = node.name,
pos = testpos,
count = 1,
hp = 0,
height = 0
}
detected = true
end
@@ -276,6 +280,8 @@ local function detect (pos)
if detected then
mesecons_on (pos)
send_detect_message (pos, detected_list)
else
mesecons_off (pos)
end

View File

@@ -7,6 +7,10 @@ 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 }
@@ -40,18 +44,17 @@ end
local function dispense_velocity (node)
local force = 25 --math.random (30 , 35)
local tilt = (math.random (1 , 2001) - 1001) / 1000
local sway = (math.random (1 , 4001) - 2001) / 1000
if node.param2 == 0 then
return { x = sway, y = tilt, z = -force }
return { x = sway, y = tilt, z = -dispenser_force }
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
return { x = sway, y = tilt, z = force }
return { x = sway, y = tilt, z = dispenser_force }
elseif node.param2 == 3 then
return { x = force, y = tilt, z = sway }
return { x = dispenser_force, y = tilt, z = sway }
else
return { x = 0, y = 0, z = 0 }
end
@@ -80,73 +83,6 @@ end
local function try_spawn (pos, node, item, owner)
if utils.mobs_supported and utils.settings.spawn_mobs then
local mob = item:get_name ()
local item_def = minetest.registered_craftitems[mob]
local spawn_pos = dispense_pos (pos, node)
if item_def and item_def.groups and item_def.groups.spawn_egg then
if mob:sub (mob:len () - 3) == "_set" then
mob = mob:sub (1, mob:len () - 4)
if minetest.registered_entities[mob] then
local data = item:get_metadata ()
local smob = minetest.add_entity (spawn_pos, mob, data)
local ent = smob and smob:get_luaentity ()
if ent then
-- set owner if not a monster
if owner:len () > 0 and ent.type ~= "monster" then
ent.owner = owner
ent.tamed = true
end
end
return smob
end
else
if minetest.registered_entities[mob] then
local smob = minetest.add_entity (spawn_pos, mob)
local ent = smob and smob:get_luaentity ()
if ent then
-- set owner if not a monster
if owner:len () > 0 and ent.type ~= "monster" then
ent.owner = owner
ent.tamed = true
end
end
return smob
end
end
elseif mob == "mobs:egg" then
if math.random (1, 10) == 1 then
local smob = minetest.add_entity (spawn_pos, "mobs_animal:chicken")
local ent = smob and smob:get_luaentity ()
if ent then
-- set owner if not a monster
if owner:len () > 0 and ent.type ~= "monster" then
ent.owner = owner
ent.tamed = true
end
end
return smob
end
end
end
return nil
end
-- slot:
-- nil - next item, no dispense if empty
-- number - 1 item from slot, no dispense if empty
@@ -203,28 +139,29 @@ local function dispense_item (pos, node, slot)
item:set_count (1)
local spawn_pos = dispense_pos (pos, node)
local owner = meta:get_string ("owner")
local obj, cancel = nil, false
local obj, cancel = utils.spawn_registered (name,
if utils.settings.spawn_mobs then
obj, cancel = utils.spawn_registered (name,
spawn_pos,
item,
owner,
pos,
dispense_dir (node))
dispense_dir (node),
dispenser_force)
if obj == nil and cancel then
return false
end
if not obj then
obj = try_spawn (pos, node, item, owner)
end
if not obj then
obj = minetest.add_item (spawn_pos, item)
obj:set_velocity (dispense_velocity (node))
end
if obj then
obj:set_velocity (dispense_velocity (node))
stack:set_count (stack:get_count () - 1)
inv:set_stack ("main", slot, stack)

View File

@@ -13,7 +13,7 @@ lwcomponents.register_spawner (itemname, spawn_func)
spawn_func:
The function to call to spawn the mob of the form -
spawn_func (spawn_pos, itemstack, owner, spawner_pos, spawner_dir)
spawn_func (spawn_pos, itemstack, owner, spawner_pos, spawner_dir, force)
spawn_pos:
The position the entity should be spawned at.
@@ -32,9 +32,13 @@ lwcomponents.register_spawner (itemname, spawn_func)
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 weather to cancel the action.
value should be returned for whether to cancel the action.
eg. If too many mobs:
return nil, true

View File

@@ -2,11 +2,12 @@ Breaker
-------
* This block is only available if digilines and/or mesecons are loaded.
Breakers dig the node 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, of if it can be dug by hand. 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.
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.
@@ -17,23 +18,26 @@ Top 1 slot inventory - tool to use.
Bottom 32 slot inventory - player's inventory.
Mesecons
Digs the node in front when power is turned on, if it can.
Digs the node in front (always the 1st node position) when power is
turned on, if it can.
Digilines messages
"break"
Digs the node in front when power is turned on, if it can.
"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 puncher's channel. The message is a table with the following
sent with the breaker's channel. The message is a table with the following
keys:
{
action = "<action>",
name = "<name>"
name = "<name>",
range = <number>
}
action
@@ -42,3 +46,7 @@ action
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.

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.

View File

@@ -59,8 +59,14 @@ Digilines messages
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>",

View File

@@ -6,11 +6,7 @@ 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.
Dispensers support mobs mod if loaded and Spawn mobs setting is enabled.
Will spawn the entity from an 'egg' if possible, or the 'egg' is dispensed.
If a chicken egg is dispensed a 10% chance a chicken is dispensed instead.
If the spawned entity can be owned (or tamed) and the dispenser is owned
the owner of the dispenser is set as the owner of the entity.
To spawn entities from dispensers include the lwcomponents_spawners mod.
Only the owner can dig or access the form of the locked version.

78
fan.lua
View File

@@ -13,17 +13,33 @@ local fan_force = 15.0
local function direction_vector (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 }
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
@@ -39,11 +55,15 @@ local function blow (pos)
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, fan_force)
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
@@ -113,6 +133,20 @@ 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)
@@ -136,7 +170,7 @@ local function after_place_node_locked (pos, placer, itemstack, pointed_thing)
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 ()..")")
meta:set_string ("infotext", "Fan (owned by "..placer:get_player_name ()..")")
end
-- If return true no item is taken from itemstack
@@ -309,7 +343,7 @@ end
minetest.register_node("lwcomponents:fan", {
description = S("Breaker"),
description = S("Fan"),
tiles = { "lwfan.png", "lwfan.png", "lwfan.png",
"lwfan.png", "lwfan.png", "lwfan_face.png"},
is_ground_content = false,
@@ -318,7 +352,7 @@ minetest.register_node("lwcomponents:fan", {
paramtype = "none",
param1 = 0,
paramtype2 = "facedir",
param2 = 1,
param2 = 0,
floodable = false,
drop = "lwcomponents:fan",
_digistuff_channelcopier_fieldname = "channel",
@@ -326,6 +360,7 @@ minetest.register_node("lwcomponents:fan", {
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,
@@ -336,7 +371,7 @@ minetest.register_node("lwcomponents:fan", {
minetest.register_node("lwcomponents:fan_locked", {
description = S("Breaker (locked)"),
description = S("Fan (locked)"),
tiles = { "lwfan.png", "lwfan.png", "lwfan.png",
"lwfan.png", "lwfan.png", "lwfan_face.png"},
is_ground_content = false,
@@ -345,7 +380,7 @@ minetest.register_node("lwcomponents:fan_locked", {
paramtype = "none",
param1 = 0,
paramtype2 = "facedir",
param2 = 1,
param2 = 0,
floodable = false,
drop = "lwcomponents:fan_locked",
_digistuff_channelcopier_fieldname = "channel",
@@ -353,6 +388,7 @@ minetest.register_node("lwcomponents:fan_locked", {
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,
@@ -363,7 +399,7 @@ minetest.register_node("lwcomponents:fan_locked", {
minetest.register_node("lwcomponents:fan_on", {
description = S("Breaker"),
description = S("Fan"),
tiles = { "lwfan.png", "lwfan.png", "lwfan.png",
"lwfan.png", "lwfan.png", "lwfan_face_on.png"},
is_ground_content = false,
@@ -372,7 +408,7 @@ minetest.register_node("lwcomponents:fan_on", {
paramtype = "none",
param1 = 0,
paramtype2 = "facedir",
param2 = 1,
param2 = 0,
floodable = false,
drop = "lwcomponents:fan",
_digistuff_channelcopier_fieldname = "channel",
@@ -380,6 +416,7 @@ minetest.register_node("lwcomponents:fan_on", {
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,
@@ -391,7 +428,7 @@ minetest.register_node("lwcomponents:fan_on", {
minetest.register_node("lwcomponents:fan_locked_on", {
description = S("Breaker (locked)"),
description = S("Fan (locked)"),
tiles = { "lwfan.png", "lwfan.png", "lwfan.png",
"lwfan.png", "lwfan.png", "lwfan_face_on.png"},
is_ground_content = false,
@@ -400,7 +437,7 @@ minetest.register_node("lwcomponents:fan_locked_on", {
paramtype = "none",
param1 = 0,
paramtype2 = "facedir",
param2 = 1,
param2 = 0,
floodable = false,
drop = "lwcomponents:fan_locked",
_digistuff_channelcopier_fieldname = "channel",
@@ -408,6 +445,7 @@ minetest.register_node("lwcomponents:fan_locked_on", {
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,

View File

@@ -1,4 +1,4 @@
local version = "0.1.6"
local version = "0.1.9"
local mod_storage = minetest.get_mod_storage ()
@@ -18,6 +18,7 @@ local modpath = minetest.get_modpath ("lwcomponents")
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.."/collector.lua") (utils)
loadfile (modpath.."/dispenser.lua") (utils)
@@ -27,7 +28,9 @@ 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.."/digiswitch.lua") (utils)
loadfile (modpath.."/movefloor.lua") (utils)

View File

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

View File

@@ -13,7 +13,7 @@ CC BY-SA 3.0
Version
=======
0.1.6
0.1.9
Minetest Version
@@ -34,7 +34,6 @@ digilines
unifieddyes
intllib
hopper
mobs
digistuff
@@ -59,12 +58,17 @@ Various components for mesecons and digilines.
* Siren, plays a sound repeatedly while active.
* Puncher, punches players or entities within a given reach.
* Player button, sends digilines message with player name.
* Breaker, digs the node directly in front.
* Breaker, digs the nodes directly in front.
* Deployers, places the nodes directly in front.
* Hologram, projects a hologram above the hologram node.
* Fan, blows any entity, player or drop in front of the fan.
* Conduit, connected in a circuit to move items.
* Digiswitch, digilines controlled mesecons power.
* Movefloor, similar to vertical mesecons movestone.
* Solid color conductor blocks, same as Solid Color Block but also mesecons and digilines conductor.
* Solid color conductor blocks, same as Solid Color Block but also mesecons
and digilines conductor.
To spawn entities from dispensers include the lwcomponents_spawners mod.
See the docs folder for details on each item.
@@ -77,4 +81,16 @@ the relevant mod is loaded.
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
------------------------------------------------------------------------

View File

@@ -6,6 +6,9 @@ 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)
--

View File

@@ -1,2 +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

@@ -269,7 +269,7 @@ local function after_place_node_locked (pos, placer, itemstack, pointed_thing)
local meta = minetest.get_meta (pos)
meta:set_string ("owner", placer:get_player_name ())
meta:set_string ("infotext", "Detector (owned by "..placer:get_player_name ()..")")
meta:set_string ("infotext", "Siren (owned by "..placer:get_player_name ()..")")
end
-- If return true no item is taken from itemstack

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

View File

@@ -129,15 +129,6 @@ end
-- check for mobs
if minetest.global_exists ("mobs") then
utils.mobs_supported = true
else
utils.mobs_supported = false
end
-- check for digistuff
if minetest.global_exists ("digistuff") then
utils.digistuff_supported = true
@@ -259,17 +250,18 @@ end
function utils.spawn_registered (itemname, spawn_pos, itemstack, owner, spawner_pos, spawner_dir)
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)
local result, obj, cancel = pcall (func, spawn_pos, itemstack, owner, spawner_pos, spawner_dir, force)
if result and (obj == nil or type (obj) == "userdata") then
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")
minetest.log ("error", "lwcomponents.register_spawner spawner function for "..itemname.." failed "..
((type (obj) == "string" and obj) or ""))
return nil, true
end