Compare commits

..

59 Commits

Author SHA1 Message Date
loosewheel
729947a4dc Add files via upload 2022-02-24 08:32:23 +10:00
loosewheel
493167998d Add files via upload 2022-02-24 08:28:38 +10:00
loosewheel
9a118751e4 Add files via upload 2022-02-24 08:26:34 +10:00
loosewheel
0de1dfd620 Add files via upload 2022-02-24 08:24:13 +10:00
loosewheel
b2ac93d3d5 Add files via upload 2022-02-24 08:23:23 +10:00
loosewheel
14202a3a2e Add files via upload 2022-02-24 08:22:17 +10:00
loosewheel
3150c50312 Add files via upload 2022-02-22 14:38:06 +10:00
loosewheel
e507646519 Add files via upload 2022-02-22 14:04:04 +10:00
loosewheel
2f99a60cbd Add files via upload 2022-02-22 14:02:10 +10:00
loosewheel
e9cf28a648 Add files via upload 2022-02-22 13:59:52 +10:00
loosewheel
ebe1720922 Add files via upload 2022-02-22 13:58:38 +10:00
loosewheel
61e20f57ed Add files via upload 2022-02-22 13:58:03 +10:00
loosewheel
eaf6a679c3 Add files via upload 2022-02-19 14:08:26 +10:00
loosewheel
f41ab00398 Add files via upload 2022-02-19 14:06:27 +10:00
loosewheel
7f42fde4a0 Add files via upload 2022-02-19 14:04:44 +10:00
loosewheel
6f8a194042 Add files via upload 2022-02-16 01:49:12 +10:00
loosewheel
84ddc82c95 Add files via upload 2022-02-16 01:46:56 +10:00
loosewheel
36aaf42d9a Add files via upload 2022-02-15 07:14:40 +10:00
loosewheel
c879735c84 Add files via upload 2022-02-15 07:06:04 +10:00
loosewheel
76a8d37edb Add files via upload 2022-02-15 06:31:00 +10:00
loosewheel
1a450bdc2a Add files via upload 2022-02-15 06:28:44 +10:00
loosewheel
c11eb22f31 Add files via upload 2022-02-15 06:26:14 +10:00
loosewheel
e4aabe5ebe Add files via upload 2022-02-15 06:25:24 +10:00
loosewheel
3cfd9adb1f Add files via upload 2022-02-15 06:24:40 +10:00
loosewheel
51ab3bdc3c Add files via upload 2022-02-05 02:14:40 +10:00
loosewheel
f873bb551f Add files via upload 2022-02-05 02:08:42 +10:00
loosewheel
326275cea6 Add files via upload 2022-02-05 02:07:16 +10:00
loosewheel
f869a4c40b Add files via upload 2022-02-05 02:05:18 +10:00
loosewheel
37488db8b9 Add files via upload 2022-02-05 02:04:35 +10:00
loosewheel
cf54a3d548 Add files via upload 2022-02-05 02:03:48 +10:00
loosewheel
9519eae026 Add files via upload 2022-01-20 17:58:09 +10:00
loosewheel
5caa7b6408 Add files via upload 2022-01-08 20:03:32 +10:00
loosewheel
6d4369ee91 Add files via upload 2022-01-07 18:55:19 +10:00
loosewheel
c7ec545ef7 Add files via upload 2022-01-07 18:53:39 +10:00
loosewheel
923faa59a3 Add files via upload 2022-01-07 18:50:47 +10:00
loosewheel
201c01131f Add files via upload 2022-01-07 18:49:57 +10:00
loosewheel
a0c9dd1d0c Add files via upload 2022-01-07 18:49:14 +10:00
loosewheel
c43dab66d7 Add files via upload 2021-12-06 21:15:05 +10:00
loosewheel
ca31c40d8b Add files via upload 2021-12-05 01:24:47 +10:00
loosewheel
2b61dfb872 Add files via upload 2021-11-29 11:29:56 +10:00
loosewheel
1459dc2029 Add files via upload 2021-11-29 11:27:33 +10:00
loosewheel
a3f6a4d203 Add files via upload 2021-11-29 11:25:24 +10:00
loosewheel
6c8a60c3f7 Add files via upload 2021-11-29 11:24:38 +10:00
loosewheel
be384872dd Add files via upload 2021-11-29 11:22:46 +10:00
loosewheel
ec08eebfd3 Add files via upload 2021-11-25 07:15:45 +10:00
loosewheel
cf8c44cb80 Add files via upload 2021-11-25 07:06:57 +10:00
loosewheel
46d8b2fcff Update readme.txt 2021-11-24 19:53:05 +10:00
loosewheel
2dabff4239 Add files via upload 2021-11-24 19:36:15 +10:00
loosewheel
b931c3105c Add files via upload 2021-11-24 19:35:15 +10:00
loosewheel
61825c93af Add files via upload 2021-11-24 19:33:57 +10:00
loosewheel
bd75cddfc8 Add files via upload 2021-11-24 19:31:55 +10:00
loosewheel
1c2486c938 Add files via upload 2021-11-24 19:30:03 +10:00
loosewheel
a45734b65a Add files via upload 2021-11-24 19:28:47 +10:00
loosewheel
16db2b969f Add files via upload 2021-11-24 19:28:07 +10:00
loosewheel
e845b002b4 Create lwcomponents_cannon_barrel.obj 2021-11-24 19:27:35 +10:00
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
85 changed files with 9564 additions and 338 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

@@ -138,9 +138,9 @@ local function can_break_node (pos, breakpos)
if node_def then
-- try tool first
local tool = get_tool (pos)
local dig_params = nil
if tool then
local dig_params = nil
local tool_def = minetest.registered_items[tool:get_name ()]
if tool_def then
@@ -222,6 +222,35 @@ end
local function eject_item (pos, stack, eject_pos)
if utils.pipeworks_supported then
local node = utils.get_far_node (eject_pos)
if node and minetest.get_item_group (node.name, "tube") > 0 then
local owner = nil
local meta = minetest.get_meta (pos)
if meta then
local o = meta:get_string ("owner")
if o ~= "" then
owner = o
end
end
local vel = vector.subtract (eject_pos, pos)
pipeworks.tube_inject_item (pos, pos, vel, stack, owner)
return
end
end
utils.item_drop (stack, nil, eject_pos)
end
local function break_node (pos, range)
local node = minetest.get_node_or_nil (pos)
@@ -242,7 +271,7 @@ local function break_node (pos, range)
local eject_pos = get_breaker_side (pos, node.param2, "back")
for i = 1, #drops do
utils.item_drop (drops[i], nil, eject_pos)
eject_item (pos, drops[i], eject_pos)
end
add_wear (pos, wear)
@@ -324,7 +353,7 @@ end
local function after_place_node (pos, placer, itemstack, pointed_thing)
local function after_place_base (pos, placer, itemstack, pointed_thing)
local meta = minetest.get_meta (pos)
local spec =
"formspec_version[3]\n"..
@@ -342,6 +371,13 @@ local function after_place_node (pos, placer, itemstack, pointed_thing)
inv:set_size ("tool", 1)
inv:set_width ("tool", 1)
end
local function after_place_node (pos, placer, itemstack, pointed_thing)
after_place_base (pos, placer, itemstack, pointed_thing)
utils.pipeworks_after_place (pos)
-- If return true no item is taken from itemstack
return false
@@ -350,15 +386,17 @@ end
local function after_place_node_locked (pos, placer, itemstack, pointed_thing)
after_place_node (pos, placer, itemstack, pointed_thing)
after_place_base (pos, placer, itemstack, pointed_thing)
if placer and placer:is_player () then
local meta = minetest.get_meta (pos)
meta:set_string ("owner", placer:get_player_name ())
meta:set_string ("infotext", "Dropper (owned by "..placer:get_player_name ()..")")
meta:set_string ("infotext", "Breaker (owned by "..placer:get_player_name ()..")")
end
utils.pipeworks_after_place (pos)
-- If return true no item is taken from itemstack
return false
end
@@ -577,12 +615,126 @@ end
local function pipeworks_support ()
if utils.pipeworks_supported then
return
{
priority = 100,
input_inventory = "tool",
connect_sides = { left = 1, right = 1, back = 1, bottom = 1, top = 1 },
insert_object = function (pos, node, stack, direction)
local meta = minetest.get_meta (pos)
local inv = (meta and meta:get_inventory ()) or nil
if inv then
return inv:add_item ("tool", stack)
end
return stack
end,
can_insert = function (pos, node, stack, direction)
if stack and not stack:is_empty () then
local def = utils.find_item_def (stack:get_name ())
if def and def.tool_capabilities then
local meta = minetest.get_meta (pos)
local inv = (meta and meta:get_inventory ()) or nil
if inv then
return inv:room_for_item ("tool", stack)
end
end
end
return false
end,
can_remove = function (pos, node, stack, dir)
-- returns the maximum number of items of that stack that can be removed
local meta = minetest.get_meta (pos)
local inv = (meta and meta:get_inventory ()) or nil
if inv then
local slots = inv:get_size ("tool")
for i = 1, slots, 1 do
local s = inv:get_stack ("tool", i)
if s and not s:is_empty () and utils.is_same_item (stack, s) then
return s:get_count ()
end
end
end
return 0
end,
remove_items = function (pos, node, stack, dir, count)
-- removes count items and returns them
local meta = minetest.get_meta (pos)
local inv = (meta and meta:get_inventory ()) or nil
local left = count
if inv then
local slots = inv:get_size ("tool")
for i = 1, slots, 1 do
local s = inv:get_stack ("tool", i)
if s and not s:is_empty () and utils.is_same_item (s, stack) then
if s:get_count () > left then
s:set_count (s:get_count () - left)
inv:set_stack ("tool", i, s)
left = 0
else
left = left - s:get_count ()
inv:set_stack ("tool", i, nil)
end
end
if left == 0 then
break
end
end
end
local result = ItemStack (stack)
result:set_count (count - left)
return result
end
}
end
return nil
end
local breaker_groups = { cracky = 3 }
if utils.pipeworks_supported then
breaker_groups.tubedevice = 1
breaker_groups.tubedevice_receiver = 1
end
local breaker_on_groups = { cracky = 3, not_in_creative_inventory = 1 }
if utils.pipeworks_supported then
breaker_on_groups.tubedevice = 1
breaker_on_groups.tubedevice_receiver = 1
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 },
groups = table.copy (breaker_groups),
sounds = default.node_sound_stone_defaults (),
paramtype = "none",
param1 = 0,
@@ -594,9 +746,11 @@ minetest.register_node("lwcomponents:breaker", {
mesecons = mesecon_support (),
digiline = digilines_support (),
tube = pipeworks_support (),
on_receive_fields = on_receive_fields,
can_dig = can_dig,
after_dig_node = utils.pipeworks_after_dig,
after_place_node = after_place_node,
on_blast = on_blast,
on_timer = on_timer,
@@ -611,7 +765,7 @@ minetest.register_node("lwcomponents:breaker_locked", {
tiles = { "lwbreaker.png", "lwbreaker.png", "lwbreaker.png",
"lwbreaker.png", "lwbreaker_rear.png", "lwbreaker_face.png"},
is_ground_content = false,
groups = { cracky = 3 },
groups = table.copy (breaker_groups),
sounds = default.node_sound_stone_defaults (),
paramtype = "none",
param1 = 0,
@@ -623,9 +777,11 @@ minetest.register_node("lwcomponents:breaker_locked", {
mesecons = mesecon_support (),
digiline = digilines_support (),
tube = pipeworks_support (),
on_receive_fields = on_receive_fields,
can_dig = can_dig,
after_dig_node = utils.pipeworks_after_dig,
after_place_node = after_place_node_locked,
on_blast = on_blast,
on_timer = on_timer,
@@ -641,7 +797,7 @@ minetest.register_node("lwcomponents:breaker_on", {
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 },
groups = table.copy (breaker_on_groups),
sounds = default.node_sound_stone_defaults (),
paramtype = "none",
param1 = 0,
@@ -654,9 +810,11 @@ minetest.register_node("lwcomponents:breaker_on", {
mesecons = mesecon_support (),
digiline = digilines_support (),
tube = pipeworks_support (),
on_receive_fields = on_receive_fields,
can_dig = can_dig,
after_dig_node = utils.pipeworks_after_dig,
after_place_node = after_place_node,
on_blast = on_blast,
on_timer = on_timer,
@@ -671,7 +829,7 @@ minetest.register_node("lwcomponents:breaker_locked_on", {
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 },
groups = table.copy (breaker_on_groups),
sounds = default.node_sound_stone_defaults (),
paramtype = "none",
param1 = 0,
@@ -684,9 +842,11 @@ minetest.register_node("lwcomponents:breaker_locked_on", {
mesecons = mesecon_support (),
digiline = digilines_support (),
tube = pipeworks_support (),
on_receive_fields = on_receive_fields,
can_dig = can_dig,
after_dig_node = utils.pipeworks_after_dig,
after_place_node = after_place_node_locked,
on_blast = on_blast,
on_timer = on_timer,

452
camera.lua Normal file
View File

@@ -0,0 +1,452 @@
local utils = ...
local S = utils.S
if utils.digilines_supported then
local function is_drop (obj)
if obj then
local entity = obj.get_luaentity and obj:get_luaentity ()
return (entity and entity.name and entity.name == "__builtin:item")
end
return false
end
local function get_entity_dims (obj)
local dims = { -0.5, 0, -0.5, 0.5, 2, 0.5 }
local found = false
if obj.get_luaentity then
local entity = obj:get_luaentity ()
if entity and entity.name then
local def = minetest.registered_entities[entity.name]
if def and type (def.collisionbox) == "table" then
dims = { def.collisionbox[1] or -0.5,
def.collisionbox[2] or -0.5,
def.collisionbox[3] or -0.5,
def.collisionbox[4] or 0.5,
def.collisionbox[5] or 0.5,
def.collisionbox[6] or 0.5 }
found = true
end
end
end
if not found then
local props = obj:get_properties ()
if props and props.collisionbox and type (props.collisionbox) == "table" then
dims = { props.collisionbox[1] or -0.5,
props.collisionbox[2] or -0.5,
props.collisionbox[3] or -0.5,
props.collisionbox[4] or 0.5,
props.collisionbox[5] or 0.5,
props.collisionbox[6] or 0.5 }
end
end
dims[1] = math.min (dims[1], dims[3])
dims[3] = dims[1]
dims[4] = math.max (dims[4], dims[6])
dims[6] = dims[4]
if (dims[3] - dims[1]) < 1 then
dims[1] = -0.5
dims[3] = -0.5
dims[4] = 0.5
dims[6] = 0.5
end
return dims
end
local function get_entity (pos)
local objects = minetest.get_objects_inside_radius (pos, 2.0)
if #objects > 0 then
for _, obj in ipairs (objects) do
if obj.get_pos then
if obj:is_player () then
local epos = vector.round (obj:get_pos ())
if epos.x == pos.x and epos.z == pos.z and
(epos.y == pos.y or epos.y == pos.y - 1) then
return 1
end
end
if not is_drop (obj) then
local epos = vector.new (obj:get_pos ())
local dims = get_entity_dims (obj)
if pos.x >= (epos.x + dims[1]) and pos.x <= (epos.x + dims[4]) and
pos.y >= (epos.y + dims[2]) and pos.y <= (epos.y + dims[5]) and
pos.z >= (epos.z + dims[3]) and pos.z <= (epos.z + dims[6]) then
return 2
end
end
end
end
end
return nil
end
local function camera_scan (pos, resolution, distance)
local node = utils.get_far_node (pos)
local image = { }
for y = 1, resolution, 1 do
image[y] = { }
for x = 1, resolution, 1 do
image[y][x] = "000000"
end
end
if node then
local dir = vector.multiply (minetest.facedir_to_dir (node.param2), -1)
local last_pos = nil
local last_color = "000000"
local view = (distance * 1.414213562) / resolution
for dist = distance, 1, -1 do
local scale = dist / distance
for y = 1, resolution, 1 do
for x = 1, resolution, 1 do
local horz = (x - (resolution / 2)) * scale * view
local vert = (y - (resolution / 2)) * scale * view
local tpos = nil
if dir.x ~= 0 then
tpos = vector.round ({ x = (dist * dir.x) + pos.x, y = pos.y - vert, z = horz + pos.z })
else
tpos = vector.round ({ x = horz + pos.x, y = pos.y - vert, z = (dist * dir.z) + pos.z })
end
if last_pos and vector.equals (last_pos, tpos) then
if last_color then
image[y][x] = last_color
end
else
local entity = get_entity (tpos)
if entity == 1 then
local color = (((distance - dist) / distance) * 98) + 30
last_color = string.format ("00%02X00", color)
image[y][x] = last_color
elseif entity == 2 then
local color = (((distance - dist) / distance) * 98) + 30
last_color = string.format ("0000%02X", color)
image[y][x] = last_color
else
local node = utils.get_far_node (tpos)
if node and node.name ~= "air" then
local color = (((distance - dist) / distance) * 98) + 30
last_color = string.format ("%02X%02X%02X", color, color, color)
image[y][x] = last_color
else
last_color = nil
end
end
end
last_pos = tpos
end
end
end
end
return image
end
local function send_scan (pos)
local meta = minetest.get_meta (pos)
if meta then
local channel = meta:get_string ("channel")
if channel:len () > 0 then
local image = camera_scan (pos,
tonumber (meta:get_string ("resolution")),
tonumber (meta:get_string ("distance")))
utils.digilines_receptor_send (pos,
utils.digilines_default_rules,
channel,
image)
end
end
end
local function after_place_node (pos, placer, itemstack, pointed_thing)
local meta = minetest.get_meta (pos)
local spec =
"formspec_version[3]"..
"size[8.5,5.5;true]"..
"field[1.0,1.0;4.0,0.8;channel;Channel;${channel}]"..
"button[5.5,1.0;2.0,0.8;setchannel;Set]"..
"field[1.0,2.5;4.0,0.8;distance;Distance;${distance}]"..
"button[5.5,2.5;2.0,0.8;setdistance;Set]"..
"field[1.0,4.0;4.0,0.8;resolution;Resolution;${resolution}]"..
"button[5.5,4.0;2.0,0.8;setresolution;Set]"
meta:set_string ("formspec", spec)
meta:set_string ("distance", "5")
meta:set_string ("resolution", "16")
-- 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", "Camera (owned by "..placer:get_player_name ()..")")
end
-- If return true no item is taken from itemstack
return false
end
local function on_receive_fields (pos, formname, fields, sender)
if not utils.can_interact_with_node (pos, sender) then
return
end
if fields.setchannel then
local meta = minetest.get_meta (pos)
if meta then
meta:set_string ("channel", fields.channel)
end
end
if fields.setdistance then
local meta = minetest.get_meta (pos)
if meta then
local distance = math.min (math.max (tonumber (fields.distance) or 1, 1), 16)
fields.distance = tostring (distance)
meta:set_string ("distance", tostring (distance))
end
end
if fields.setresolution then
local meta = minetest.get_meta (pos)
if meta then
local resolution = math.min (math.max (tonumber (fields.resolution) or 1, 1), 128)
fields.resolution = tostring (resolution)
meta:set_string ("resolution", tostring (resolution))
end
end
end
local function can_dig (pos, player)
if not utils.can_interact_with_node (pos, player) then
return false
end
return true
end
local function on_blast (pos, intensity)
local meta = minetest.get_meta (pos)
if meta then
if intensity >= 1.0 then
minetest.remove_node (pos)
else -- intensity < 1.0
local node = minetest.get_node_or_nil (pos)
if node then
local items = minetest.get_node_drops (node, nil)
if items and #items > 0 then
local stack = ItemStack (items[1])
if stack then
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 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] == "scan" then
send_scan (pos)
elseif m[1] == "distance" then
local distance = math.min (math.max (tonumber (m[2] or 5) or 5, 1), 16)
meta:set_string ("distance", tostring (distance))
elseif m[1] == "resolution" then
local resolution = math.min (math.max (tonumber (m[2] or 16) or 16, 1), 128)
meta:set_string ("resolution", tostring (resolution))
end
end
end
end,
}
}
end
return nil
end
minetest.register_node("lwcomponents:camera", {
description = S("Camera"),
tiles = { "lwcamera.png", "lwcamera.png", "lwcamera.png",
"lwcamera.png", "lwcamera.png", "lwcamera_lens.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:camera",
_digistuff_channelcopier_fieldname = "channel",
digiline = digilines_support (),
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:camera_locked", {
description = S("Camera (locked)"),
tiles = { "lwcamera.png", "lwcamera.png", "lwcamera.png",
"lwcamera.png", "lwcamera.png", "lwcamera_lens.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:camera_locked",
_digistuff_channelcopier_fieldname = "channel",
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_rightclick = on_rightclick
})
end -- utils.digilines_supported
--

1181
cannon.lua Normal file

File diff suppressed because it is too large Load Diff

293
cannon_shell.lua Normal file
View File

@@ -0,0 +1,293 @@
local utils = ...
local S = utils.S
--[[
on_step info
info.touching_ground = bool
info.standing_on_object = bool
info.collides = bool
info.collisions[n].type = "node"
info.collisions[n].node_pos = vector
info.collisions[n].old_velocity = vector
info.collisions[n].now_velocity = vector
info.collisions[n].axis = "x" | "y" | "z" - axis hit
or
info.collisions[n].type = "object"
info.collisions[n].object = userdata
info.collisions[n].old_velocity = vector
info.collisions[n].now_velocity = vector
info.collisions[n].axis = "x" | "y" | "z" - axis hit
]]
local function get_adjacent_node (collision_info, spawn_pos)
if vector.equals (collision_info.node_pos, spawn_pos) then
return collision_info.node_pos
end
local adj = { x = 0, y = 0, z = 0 }
if collision_info.axis == "x" then
adj.x = (collision_info.old_velocity.x > 0 and -1) or 1
elseif collision_info.axis == "y" then
adj.y = (collision_info.old_velocity.y > 0 and -1) or 1
elseif collision_info.axis == "z" then
adj.z = (collision_info.old_velocity.z > 0 and -1) or 1
end
local pos = vector.new (collision_info.node_pos)
local node = utils.get_far_node (pos)
local def = minetest.registered_nodes[node and node.name or nil]
while (node and node.name ~= "air") and (def and not def.buildable_to) do
local next_pos = vector.add (pos, adj)
if vector.equals (next_pos, spawn_pos) then
return pos
end
pos = next_pos
node = utils.get_far_node (pos)
def = minetest.registered_nodes[node and node.name or nil]
end
return pos
end
local function register_shell (name, description, texture, inventory_image,
stack_max, shell_speed, explode_func)
minetest.register_entity (name.."_entity", {
initial_properties = {
physical = true,
collide_with_objects = true,
collisionbox = { -0.25, -0.125, -0.25, 0.25, 0.125, 0.25 },
pointable = false,
visual_size = { x = 0.7, y = 0.7, z = 0.7 },
visual = "mesh",
mesh = "lwcomponents_shell.obj",
textures = { texture },
use_texture_alpha = false,
is_visible = true,
makes_footstep_sound = false,
automatic_face_movement_dir = false,
automatic_face_movement_max_rotation_per_sec = false,
automatic_rotate = 0,
backface_culling = true,
damage_texture_modifier = "",
glow = 0,
static_save = false,
shaded = true,
show_on_minimap = false,
},
on_activate = function (self, staticdata, dtime_s)
if not self.spawn_pos then
self.spawn_pos = vector.new (self.object:get_pos ())
end
if not self.time_lived then
self.time_lived = 0
end
if not self.shell_speed then
self.shell_speed = shell_speed
end
self.staticdata = staticdata
end,
get_staticdata = function (self)
return self.staticdata
end,
on_step = function (self, dtime, info)
local explode_pos = nil
self.object:set_rotation (vector.dir_to_rotation (self.object:get_velocity ()))
if self.time_lived then
self.time_lived = self.time_lived + dtime
if self.time_lived > self.shell_speed then
self.object:remove ()
return
end
end
if info.collides then
--For each collision that was found in reverse order
for i = #info.collisions, 1, -1 do
local c = info.collisions[i]
if c.type == "node" then
local node = utils.get_far_node (c.node_pos)
if node and node.name ~= "air" then
local def = minetest.registered_nodes[node.name]
if def and def.walkable then
-- adjacent for explosion
explode_pos = get_adjacent_node (c, self.spawn_pos)
--minetest.log ("action", "Shell on node "..node.name.." at "..minetest.pos_to_string (explode_pos)..
--" node at "..minetest.pos_to_string (c.node_pos))
break
end
end
if not explode_pos then
self.object:set_velocity (c.old_velocity)
end
elseif c.type == "object" then
-- explode at this pos
if c.object:get_armor_groups ().immortal then
self.object:set_velocity (c.old_velocity)
else
explode_pos = vector.new (c.object:get_pos ())
--minetest.log ("action", "Shell on entity "..c.object:get_luaentity ().name.." at "..minetest.pos_to_string (explode_pos))
break
end
end
end
end
if explode_pos then
self.object:remove ()
explode_func (explode_pos)
end
end,
on_punch = function (self, puncher, time_from_last_punch, tool_capabilities, dir)
return true
end,
})
minetest.register_craftitem (name, {
description = description,
short_description = description,
groups = { },
inventory_image = inventory_image,
wield_image = inventory_image,
stack_max = stack_max,
})
lwcomponents.register_spawner (name,
function (spawn_pos, itemstack, owner, spawner_pos, spawner_dir, force)
if not itemstack:is_empty() then
local def = minetest.registered_entities[name.."_entity"]
if def then
local obj = minetest.add_entity (spawn_pos, name.."_entity")
if obj then
obj:set_armor_groups ({ immortal = 1 })
obj:set_acceleration ({ x = 0, y = -9.81, z = 0 })
obj:set_rotation (vector.dir_to_rotation (vector.multiply (spawner_dir, shell_speed)))
obj:set_velocity (vector.multiply (spawner_dir, shell_speed))
local luaent = obj:get_luaentity ()
if luaent then
luaent.spawn_pos = { x = spawn_pos.x, y = spawn_pos.y, z = spawn_pos.z }
luaent.time_lived = 0
luaent.shell_speed = shell_speed
end
return obj, false
end
end
end
return nil, false
end)
end
register_shell ("lwcomponents:cannon_shell",
S("Shell"),
"lwcannon_shell.png",
"lwcannon_shell_item.png",
99,
25,
function (pos)
utils.boom (pos,
2, -- node_radius
70, -- node_chance in 100
2, -- fire_radius
5, -- fire_chance in 100
4, -- entity_radius
20, -- entity_damage
false, -- disable_drops
nil, -- node_filter
false, -- burn_all
nil) -- sound
end)
register_shell ("lwcomponents:cannon_soft_shell",
S("Soft Shell"),
"lwcannon_soft_shell.png",
"lwcannon_soft_shell_item.png",
99,
25,
function (pos)
utils.boom (pos,
2, -- node_radius
50, -- node_chance in 100
2, -- fire_radius
5, -- fire_chance in 100
4, -- entity_radius
20, -- entity_damage
false, -- disable_drops
{
buildable_to = true,
buildable_to_undefined = false,
}, -- node_filter
false, -- burn_all
nil) -- sound
end)
if minetest.global_exists ("fire") then
register_shell ("lwcomponents:cannon_fire_shell",
S("Fire Shell"),
"lwcannon_fire_shell.png",
"lwcannon_fire_shell_item.png",
99,
25,
function (pos)
utils.boom (pos,
2, -- node_radius
0, -- node_chance in 100
2, -- fire_radius
70, -- fire_chance in 100
4, -- entity_radius
20, -- entity_damage
false, -- disable_drops
nil, -- node_filter
true, -- burn_all
nil) -- sound
end)
end
--

View File

@@ -43,3 +43,95 @@ 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.
v0.1.10
* Added cannons.
v0.1.11
* Fix to breakers (?).
* Added position aiming to cannons.
v0.1.12
* Added sensitivity option for game controller in cannons.
* Added cannon shells.
* Fixed bug in utils.is_creative.
* Increased cannon pitch to -20 to 70.
v0.1.13
* Removed optional dependency lwdrops.
v0.1.14
* Calls on_drop when item is dropped.
v0.1.15
* Fixed bug call to clear_map in fan on_blast.
* Added pistons.
v0.1.16
* Fixed piston interaction with non-walkable nodes.
v0.1.17
* Fixed unintended global variable in pistons.lua.
v0.1.18
* Added mesecons through wire.
v0.1.19
* Added camera.
v0.1.20
* Valid distance and resolution for camera set by digilines message.
* Imposed maximum resolution of 128 for cameras.
v0.1.21
* Minor bug fix, movefloor global.
* Fixed movefloor so player doesn't fall through floor.
* Transfer timer in moved nodes for pistons.
v0.1.22
* Added storage.
v0.1.23
* Fixed storage indexer not taking items from storage properly.
* Added pipeworks support for:
Storage Indexer
Dropper
Collector
Dispenser
Breaker
Deployer
Cannon
Conduit
* Conduits now work in unloaded blocks.
* Fixed conduits sending items in groups.
* Fixed player attached to controller moving forever when they get blown up.
* Fixed pistons being powered from the pusher side.

View File

@@ -148,7 +148,7 @@ end
local function after_place_node (pos, placer, itemstack, pointed_thing)
local function after_place_base (pos, placer, itemstack, pointed_thing)
local meta = minetest.get_meta (pos)
local is_off = itemstack and (itemstack:get_name () == "lwcomponents:collector" or
itemstack:get_name () == "lwcomponents:collector_locked")
@@ -162,6 +162,13 @@ local function after_place_node (pos, placer, itemstack, pointed_thing)
inv:set_width ("main", 4)
inv:set_size ("filter", 8)
inv:set_width ("filter", 2)
end
local function after_place_node (pos, placer, itemstack, pointed_thing)
after_place_base (pos, placer, itemstack, pointed_thing)
utils.pipeworks_after_place (pos)
-- If return true no item is taken from itemstack
return false
@@ -170,7 +177,7 @@ end
local function after_place_node_locked (pos, placer, itemstack, pointed_thing)
after_place_node (pos, placer, itemstack, pointed_thing)
after_place_base (pos, placer, itemstack, pointed_thing)
if placer and placer:is_player () then
local meta = minetest.get_meta (pos)
@@ -179,6 +186,8 @@ local function after_place_node_locked (pos, placer, itemstack, pointed_thing)
meta:set_string ("infotext", "Collector (owned by "..placer:get_player_name ()..")")
end
utils.pipeworks_after_place (pos)
-- If return true no item is taken from itemstack
return false
end
@@ -427,12 +436,120 @@ end
local function pipeworks_support ()
if utils.pipeworks_supported then
return
{
priority = 100,
input_inventory = "main",
connect_sides = { left = 1, right = 1, front = 1, back = 1, bottom = 1, top = 1 },
insert_object = function (pos, node, stack, direction)
local meta = minetest.get_meta (pos)
local inv = (meta and meta:get_inventory ()) or nil
if inv then
return inv:add_item ("main", stack)
end
return stack
end,
can_insert = function (pos, node, stack, direction)
local meta = minetest.get_meta (pos)
local inv = (meta and meta:get_inventory ()) or nil
if inv then
return inv:room_for_item ("main", stack)
end
return false
end,
can_remove = function (pos, node, stack, dir)
-- returns the maximum number of items of that stack that can be removed
local meta = minetest.get_meta (pos)
local inv = (meta and meta:get_inventory ()) or nil
if inv then
local slots = inv:get_size ("main")
for i = 1, slots, 1 do
local s = inv:get_stack ("main", i)
if s and not s:is_empty () and utils.is_same_item (stack, s) then
return s:get_count ()
end
end
end
return 0
end,
remove_items = function (pos, node, stack, dir, count)
-- removes count items and returns them
local meta = minetest.get_meta (pos)
local inv = (meta and meta:get_inventory ()) or nil
local left = count
if inv then
local slots = inv:get_size ("main")
for i = 1, slots, 1 do
local s = inv:get_stack ("main", i)
if s and not s:is_empty () and utils.is_same_item (s, stack) then
if s:get_count () > left then
s:set_count (s:get_count () - left)
inv:set_stack ("main", i, s)
left = 0
else
left = left - s:get_count ()
inv:set_stack ("main", i, nil)
end
end
if left == 0 then
break
end
end
end
local result = ItemStack (stack)
result:set_count (count - left)
return result
end
}
end
return nil
end
local collector_groups = { cracky = 3 }
if utils.pipeworks_supported then
collector_groups.tubedevice = 1
collector_groups.tubedevice_receiver = 1
end
local collector_on_groups = { cracky = 3, not_in_creative_inventory = 1 }
if utils.pipeworks_supported then
collector_on_groups.tubedevice = 1
collector_on_groups.tubedevice_receiver = 1
end
minetest.register_node("lwcomponents:collector", {
description = S("Collector"),
tiles = { "lwcollector.png", "lwcollector.png", "lwcollector.png",
"lwcollector.png", "lwcollector.png", "lwcollector.png"},
is_ground_content = false,
groups = { cracky = 3 },
groups = table.copy (collector_groups),
sounds = default.node_sound_stone_defaults (),
paramtype = "none",
param1 = 0,
@@ -441,11 +558,13 @@ minetest.register_node("lwcomponents:collector", {
_digistuff_channelcopier_fieldname = "channel",
digiline = digilines_support (),
tube = pipeworks_support (),
on_destruct = on_destruct,
on_receive_fields = on_receive_fields,
after_place_node = after_place_node,
can_dig = can_dig,
after_dig_node = utils.pipeworks_after_dig,
on_blast = on_blast,
on_timer = on_timer,
on_rightclick = on_rightclick
@@ -458,7 +577,7 @@ minetest.register_node("lwcomponents:collector_locked", {
tiles = { "lwcollector.png", "lwcollector.png", "lwcollector.png",
"lwcollector.png", "lwcollector.png", "lwcollector.png"},
is_ground_content = false,
groups = { cracky = 3 },
groups = table.copy (collector_groups),
sounds = default.node_sound_stone_defaults (),
paramtype = "none",
param1 = 0,
@@ -467,11 +586,13 @@ minetest.register_node("lwcomponents:collector_locked", {
_digistuff_channelcopier_fieldname = "channel",
digiline = digilines_support (),
tube = pipeworks_support (),
on_destruct = on_destruct,
on_receive_fields = on_receive_fields,
after_place_node = after_place_node_locked,
can_dig = can_dig,
after_dig_node = utils.pipeworks_after_dig,
on_blast = on_blast,
on_timer = on_timer,
on_rightclick = on_rightclick
@@ -484,7 +605,7 @@ minetest.register_node("lwcomponents:collector_on", {
tiles = { "lwcollector_on.png", "lwcollector_on.png", "lwcollector_on.png",
"lwcollector_on.png", "lwcollector_on.png", "lwcollector_on.png"},
is_ground_content = false,
groups = { cracky = 3, not_in_creative_inventory = 1 },
groups = table.copy (collector_on_groups),
sounds = default.node_sound_stone_defaults (),
paramtype = "none",
param1 = 0,
@@ -493,11 +614,13 @@ minetest.register_node("lwcomponents:collector_on", {
_digistuff_channelcopier_fieldname = "channel",
digiline = digilines_support (),
tube = pipeworks_support (),
on_destruct = on_destruct,
on_receive_fields = on_receive_fields,
after_place_node = after_place_node,
can_dig = can_dig,
after_dig_node = utils.pipeworks_after_dig,
on_blast = on_blast,
on_timer = on_timer,
on_rightclick = on_rightclick
@@ -510,7 +633,7 @@ minetest.register_node("lwcomponents:collector_locked_on", {
tiles = { "lwcollector_on.png", "lwcollector_on.png", "lwcollector_on.png",
"lwcollector_on.png", "lwcollector_on.png", "lwcollector_on.png"},
is_ground_content = false,
groups = { cracky = 3, not_in_creative_inventory = 1 },
groups = table.copy (collector_on_groups),
sounds = default.node_sound_stone_defaults (),
paramtype = "none",
param1 = 0,
@@ -519,11 +642,13 @@ minetest.register_node("lwcomponents:collector_locked_on", {
_digistuff_channelcopier_fieldname = "channel",
digiline = digilines_support (),
tube = pipeworks_support (),
on_destruct = on_destruct,
on_receive_fields = on_receive_fields,
after_place_node = after_place_node_locked,
can_dig = can_dig,
after_dig_node = utils.pipeworks_after_dig,
on_blast = on_blast,
on_timer = on_timer,
on_rightclick = on_rightclick

930
conduit.lua Normal file
View File

@@ -0,0 +1,930 @@
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")
-- forward declare
local run_initialize_forward = nil
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 tnode = utils.get_far_node (transfer_data[slot].pos)
if tnode and (tnode.name == "lwcomponents:conduit" or
tnode.name == "lwcomponents:conduit_locked") 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)
end
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 deliver_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
deliver_earliest (pos)
slot = get_transfer_free_slot (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:set_stack ("transfer", slot, item)
meta:set_string ("transfer_data", minetest.serialize (transfer_data))
run_initialize_forward (pos)
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)
return true, target, slot
end
end
end
end
end
end
end
end
return false
end
local function run_conduit (pos, id)
local node = utils.get_far_node (pos)
if node and (node.name == "lwcomponents:conduit" or
node.name == "lwcomponents:conduit_locked") then
local meta = minetest.get_meta (pos)
if meta and id == meta:get_int ("conduit_id") then
local automatic = meta:get_string ("automatic") == "true"
if automatic then
send_to_target (pos)
end
if run_deliveries (pos) or automatic then
minetest.after (conduit_interval, run_conduit, pos, id)
else
meta:set_int ("run_active", 0)
end
end
end
end
local function run_initialize (pos)
local meta = minetest.get_meta (pos)
if meta then
if meta:get_int ("run_active") == 0 then
meta:set_int ("run_active", 1)
minetest.after (conduit_interval, run_conduit, pos, meta:get_int ("conduit_id"))
end
end
end
run_initialize_forward = run_initialize
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_base (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")
meta:set_int ("conduit_id", math.random (1000000))
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)
end
local function after_place_node (pos, placer, itemstack, pointed_thing)
after_place_base (pos, placer, itemstack, pointed_thing)
utils.pipeworks_after_place (pos)
-- If return true no item is taken from itemstack
return false
end
local function after_place_node_locked (pos, placer, itemstack, pointed_thing)
after_place_base (pos, placer, itemstack, pointed_thing)
if placer and placer:is_player () then
local meta = minetest.get_meta (pos)
meta:set_string ("owner", placer:get_player_name ())
meta:set_string ("infotext", "Conduit (owned by "..placer:get_player_name ()..")")
end
utils.pipeworks_after_place (pos)
-- If return true no item is taken from itemstack
return false
end
local function 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))
run_initialize (pos)
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 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
local function pipeworks_support ()
if utils.pipeworks_supported then
return
{
priority = 100,
input_inventory = "main",
connect_sides = { left = 1, right = 1, front = 1, back = 1, bottom = 1, top = 1 },
insert_object = function (pos, node, stack, direction)
local meta = minetest.get_meta (pos)
local inv = (meta and meta:get_inventory ()) or nil
if inv then
return inv:add_item ("main", stack)
end
return stack
end,
can_insert = function (pos, node, stack, direction)
local meta = minetest.get_meta (pos)
local inv = (meta and meta:get_inventory ()) or nil
if inv then
return inv:room_for_item ("main", stack)
end
return false
end,
can_remove = function (pos, node, stack, dir)
-- returns the maximum number of items of that stack that can be removed
local meta = minetest.get_meta (pos)
local inv = (meta and meta:get_inventory ()) or nil
if inv then
local slots = inv:get_size ("main")
for i = 1, slots, 1 do
local s = inv:get_stack ("main", i)
if s and not s:is_empty () and utils.is_same_item (stack, s) then
return s:get_count ()
end
end
end
return 0
end,
remove_items = function (pos, node, stack, dir, count)
-- removes count items and returns them
local meta = minetest.get_meta (pos)
local inv = (meta and meta:get_inventory ()) or nil
local left = count
if inv then
local slots = inv:get_size ("main")
for i = 1, slots, 1 do
local s = inv:get_stack ("main", i)
if s and not s:is_empty () and utils.is_same_item (s, stack) then
if s:get_count () > left then
s:set_count (s:get_count () - left)
inv:set_stack ("main", i, s)
left = 0
else
left = left - s:get_count ()
inv:set_stack ("main", i, nil)
end
end
if left == 0 then
break
end
end
end
local result = ItemStack (stack)
result:set_count (count - left)
return result
end
}
end
return nil
end
local conduit_groups = { cracky = 3 }
if utils.pipeworks_supported then
conduit_groups.tubedevice = 1
conduit_groups.tubedevice_receiver = 1
end
minetest.register_node("lwcomponents:conduit", {
description = S("Conduit"),
drawtype = "glasslike_framed",
tiles = { "lwconduit_edge.png", "lwconduit.png" },
is_ground_content = false,
groups = table.copy (conduit_groups),
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 (),
tube = pipeworks_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,
after_dig_node = utils.pipeworks_after_dig,
on_blast = on_blast,
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 = table.copy (conduit_groups),
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 (),
tube = pipeworks_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,
after_dig_node = utils.pipeworks_after_dig,
on_blast = on_blast,
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
})
-- legacy code v0.1.23 (24-2-22)
local function convert_conduits ()
local list = conduit_connections:get_full_list ()
for _, data in ipairs (list) do
local node = utils.get_far_node (data.pos)
if node and (node.name == "lwcomponents:conduit" or
node.name == "lwcomponents:conduit_locked") then
local meta = minetest.get_meta (data.pos)
if meta then
if meta:get_int ("conduit_id") == 0 then
meta:set_int ("conduit_id", math.random (1000000))
if meta:get_string ("automatic") == "true" then
meta:set_int ("run_active", 1)
else
local inv = meta:get_inventory ()
if inv and not inv:is_empty ("transfer") then
meta:set_int ("run_active", 1)
end
end
end
end
end
end
end
local function restart_conduits ()
convert_conduits ()
local list = conduit_connections:get_id_list ()
for _, data in ipairs (list) do
local meta = minetest.get_meta (data.pos)
if meta and meta:get_int ("run_active") ~= 0 then
minetest.after (conduit_interval + (math.random (9) / 10),
run_conduit, data.pos, meta:get_int ("conduit_id"))
end
end
end
minetest.register_on_mods_loaded (function ()
minetest.after (3.0, restart_conduits)
end)
end -- utils.digilines_supported or utils.mesecon_supported

334
connections.lua Normal file
View File

@@ -0,0 +1,334 @@
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
function connections:get_id_list ()
local list = { }
for spos, data in pairs (self.connector_list) do
if data.id then
list[#list + 1] =
{
pos = minetest.string_to_pos (spos),
id = data.id
}
end
end
return list
end
function connections:get_full_list ()
local list = { }
for spos, data in pairs (self.connector_list) do
list[#list + 1] =
{
pos = minetest.string_to_pos (spos),
id = data.id
}
end
return list
end
return connections
--

View File

@@ -3,6 +3,108 @@ local S = utils.S
minetest.register_craft( {
output = "lwcomponents:cannon",
recipe = {
{ "default:steel_ingot", "default:steel_ingot", "default:steel_ingot" },
{ "default:chest", "default:wood", "" },
{ "default:copper_ingot", "default:stone", "" },
},
})
minetest.register_craft( {
output = "lwcomponents:cannon_locked",
recipe = {
{ "default:steel_ingot", "default:steel_ingot", "default:steel_ingot" },
{ "default:chest_locked", "default:wood", "" },
{ "default:copper_ingot", "default:stone", "" },
},
})
minetest.register_craft( {
output = "lwcomponents:storage_unit 2",
recipe = {
{ "default:steel_ingot", "group:wood", "group:wood" },
{ "group:wood", "", "group:wood" },
{ "group:wood", "group:wood", "default:chest" },
},
})
minetest.register_craft( {
output = "lwcomponents:storage_unit_locked 2",
recipe = {
{ "default:steel_ingot", "group:wood", "group:wood" },
{ "group:wood", "", "group:wood" },
{ "group:wood", "group:wood", "default:chest_locked" },
},
})
minetest.register_craft( {
output = "lwcomponents:storage_indexer",
recipe = {
{ "default:steel_ingot", "group:wood" },
{ "group:wood", "default:chest" }
},
})
minetest.register_craft( {
output = "lwcomponents:storage_indexer_locked",
recipe = {
{ "default:steel_ingot", "group:wood" },
{ "group:wood", "default:chest_locked" }
},
})
minetest.register_craft( {
output = "lwcomponents:cannon_shell 10",
recipe = {
{ "default:steel_ingot", "default:steel_ingot" },
{ "", "default:coalblock" },
},
})
minetest.register_craft( {
output = "lwcomponents:cannon_soft_shell 10",
recipe = {
{ "default:steel_ingot", "default:steel_ingot" },
{ "default:copper_lump", "default:coalblock" },
},
})
if minetest.global_exists ("fire") then
minetest.register_craft( {
output = "lwcomponents:cannon_fire_shell 10",
recipe = {
{ "default:steel_ingot", "default:steel_ingot" },
{ "default:iron_lump", "default:coalblock" },
},
})
end -- minetest.global_exists ("fire")
if utils.mesecon_supported then
minetest.register_craft( {
output = "lwcomponents:through_wire_off 2",
recipe = {
{ "", "mesecons:wire_00000000_off" },
{ "mesecons:wire_00000000_off", "" },
},
})
end -- utils.mesecon_supported
if utils.digilines_supported or utils.mesecon_supported then
minetest.register_craft( {
@@ -113,6 +215,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 +250,46 @@ 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" },
},
})
minetest.register_craft({
output = "lwcomponents:piston 2",
recipe = {
{ "group:wood", "group:wood", "group:wood" },
{ "default:cobble", "default:steel_ingot", "default:cobble" },
{ "default:stone", "default:copper_ingot", "default:stone" },
}
})
minetest.register_craft({
output = "lwcomponents:piston_sticky",
recipe = {
{"group:sapling"},
{"lwcomponents:piston"},
}
})
end -- utils.digilines_supported or utils.mesecon_supported
@@ -173,6 +333,24 @@ minetest.register_craft( {
},
})
minetest.register_craft( {
output = "lwcomponents:camera",
recipe = {
{ "default:copper_ingot", "default:iron_lump" },
{ "default:chest", "default:stone" },
},
})
minetest.register_craft( {
output = "lwcomponents:camera_locked",
recipe = {
{ "default:copper_ingot", "default:iron_lump" },
{ "default:chest_locked", "default:stone" },
},
})
end -- utils.digilines_supported
@@ -192,7 +370,7 @@ end -- utils.digilines_supported and utils.digistuff_supported
if utils.mesecon_supported and mesecon.mvps_push then
if utils.mesecon_supported then
minetest.register_craft ({
output = "lwcomponents:movefloor",
@@ -203,7 +381,7 @@ minetest.register_craft ({
}
})
end -- utils.mesecon_supported and mesecon.mvps_push
end -- utils.mesecon_supported

View File

@@ -1,9 +1,8 @@
default
lwdrops?
mesecons?
digilines?
unifieddyes?
intllib?
hopper?
mobs?
digistuff?
pipeworks?

View File

@@ -73,7 +73,7 @@ end
local function place_node (itemname, pos)
local function place_node (item, pos)
local node = minetest.get_node_or_nil ({ x = pos.x, y = pos.y - 1, z = pos.z })
if not node then
@@ -100,8 +100,8 @@ local function place_node (itemname, pos)
end
end
local stack = ItemStack (itemname)
local itemdef = utils.find_item_def (itemname)
local stack = ItemStack (item)
local itemdef = utils.find_item_def (stack:get_name ())
if stack and itemdef then
local placed = false
@@ -122,23 +122,23 @@ local function place_node (itemname, pos)
end
if itemdef and itemdef.on_place then
local result, msg = pcall (itemdef.on_place, stack, nil, pointed_thing)
local result, leftover = 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)
minetest.log ("error", "on_place handler for "..stack:get_name ().." crashed - "..leftover)
end
end
end
if not placed then
if not minetest.registered_nodes[itemname] then
if not minetest.registered_nodes[stack:get_name ()] then
return false
end
minetest.set_node (pos, { name = itemname, param1 = 0, param2 = 0 })
minetest.set_node (pos, { name = stack:get_name (), 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)
@@ -154,11 +154,13 @@ local function place_node (itemname, pos)
pcall (minetest.sound_play, itemdef.sounds.place, { pos = pos })
end
end
end
return true
end
return false
end
-- slot:
@@ -219,7 +221,7 @@ local function deploy_item (pos, node, slot, range)
local deploypos = get_deploy_pos (pos, node.param2, range)
if item and deploypos then
if place_node (name, deploypos) then
if place_node (stack, deploypos) then
stack:set_count (stack:get_count () - 1)
inv:set_stack ("main", slot, stack)
@@ -290,7 +292,7 @@ end
local function after_place_node (pos, placer, itemstack, pointed_thing)
local function after_place_base (pos, placer, itemstack, pointed_thing)
local meta = minetest.get_meta (pos)
local spec =
"formspec_version[3]\n"..
@@ -308,6 +310,13 @@ local function after_place_node (pos, placer, itemstack, pointed_thing)
inv:set_size ("main", 16)
inv:set_width ("main", 4)
end
local function after_place_node (pos, placer, itemstack, pointed_thing)
after_place_base (pos, placer, itemstack, pointed_thing)
utils.pipeworks_after_place (pos)
-- If return true no item is taken from itemstack
return false
@@ -316,7 +325,7 @@ end
local function after_place_node_locked (pos, placer, itemstack, pointed_thing)
after_place_node (pos, placer, itemstack, pointed_thing)
after_place_base (pos, placer, itemstack, pointed_thing)
if placer and placer:is_player () then
local meta = minetest.get_meta (pos)
@@ -325,6 +334,8 @@ local function after_place_node_locked (pos, placer, itemstack, pointed_thing)
meta:set_string ("infotext", "Deployer (owned by "..placer:get_player_name ()..")")
end
utils.pipeworks_after_place (pos)
-- If return true no item is taken from itemstack
return false
end
@@ -528,12 +539,120 @@ end
local function pipeworks_support ()
if utils.pipeworks_supported then
return
{
priority = 100,
input_inventory = "main",
connect_sides = { left = 1, right = 1, back = 1, bottom = 1, top = 1 },
insert_object = function (pos, node, stack, direction)
local meta = minetest.get_meta (pos)
local inv = (meta and meta:get_inventory ()) or nil
if inv then
return inv:add_item ("main", stack)
end
return stack
end,
can_insert = function (pos, node, stack, direction)
local meta = minetest.get_meta (pos)
local inv = (meta and meta:get_inventory ()) or nil
if inv then
return inv:room_for_item ("main", stack)
end
return false
end,
can_remove = function (pos, node, stack, dir)
-- returns the maximum number of items of that stack that can be removed
local meta = minetest.get_meta (pos)
local inv = (meta and meta:get_inventory ()) or nil
if inv then
local slots = inv:get_size ("main")
for i = 1, slots, 1 do
local s = inv:get_stack ("main", i)
if s and not s:is_empty () and utils.is_same_item (stack, s) then
return s:get_count ()
end
end
end
return 0
end,
remove_items = function (pos, node, stack, dir, count)
-- removes count items and returns them
local meta = minetest.get_meta (pos)
local inv = (meta and meta:get_inventory ()) or nil
local left = count
if inv then
local slots = inv:get_size ("main")
for i = 1, slots, 1 do
local s = inv:get_stack ("main", i)
if s and not s:is_empty () and utils.is_same_item (s, stack) then
if s:get_count () > left then
s:set_count (s:get_count () - left)
inv:set_stack ("main", i, s)
left = 0
else
left = left - s:get_count ()
inv:set_stack ("main", i, nil)
end
end
if left == 0 then
break
end
end
end
local result = ItemStack (stack)
result:set_count (count - left)
return result
end
}
end
return nil
end
local deployer_groups = { cracky = 3 }
if utils.pipeworks_supported then
deployer_groups.tubedevice = 1
deployer_groups.tubedevice_receiver = 1
end
local deployer_on_groups = { cracky = 3, not_in_creative_inventory = 1 }
if utils.pipeworks_supported then
deployer_on_groups.tubedevice = 1
deployer_on_groups.tubedevice_receiver = 1
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 },
groups = table.copy (deployer_groups),
sounds = default.node_sound_stone_defaults (),
paramtype = "none",
param1 = 0,
@@ -544,10 +663,12 @@ minetest.register_node("lwcomponents:deployer", {
mesecons = mesecon_support (),
digiline = digilines_support (),
tube = pipeworks_support (),
on_receive_fields = on_receive_fields,
after_place_node = after_place_node,
can_dig = can_dig,
after_dig_node = utils.pipeworks_after_dig,
on_blast = on_blast,
on_timer = on_timer,
on_rightclick = on_rightclick
@@ -560,7 +681,7 @@ minetest.register_node("lwcomponents:deployer_locked", {
tiles = { "lwdeployer.png", "lwdeployer.png", "lwdeployer.png",
"lwdeployer.png", "lwdeployer.png", "lwdeployer_face.png"},
is_ground_content = false,
groups = { cracky = 3 },
groups = table.copy (deployer_groups),
sounds = default.node_sound_stone_defaults (),
paramtype = "none",
param1 = 0,
@@ -571,10 +692,12 @@ minetest.register_node("lwcomponents:deployer_locked", {
mesecons = mesecon_support (),
digiline = digilines_support (),
tube = pipeworks_support (),
on_receive_fields = on_receive_fields,
after_place_node = after_place_node_locked,
can_dig = can_dig,
after_dig_node = utils.pipeworks_after_dig,
on_blast = on_blast,
on_timer = on_timer,
on_rightclick = on_rightclick
@@ -588,7 +711,7 @@ minetest.register_node("lwcomponents:deployer_on", {
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 },
groups = table.copy (deployer_on_groups),
sounds = default.node_sound_stone_defaults (),
paramtype = "none",
param1 = 0,
@@ -601,9 +724,11 @@ minetest.register_node("lwcomponents:deployer_on", {
mesecons = mesecon_support (),
digiline = digilines_support (),
tube = pipeworks_support (),
on_receive_fields = on_receive_fields,
can_dig = can_dig,
after_dig_node = utils.pipeworks_after_dig,
after_place_node = after_place_node,
on_blast = on_blast,
on_timer = on_timer,
@@ -617,7 +742,7 @@ minetest.register_node("lwcomponents:deployer_locked_on", {
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 },
groups = table.copy (deployer_on_groups),
sounds = default.node_sound_stone_defaults (),
paramtype = "none",
param1 = 0,
@@ -630,9 +755,11 @@ minetest.register_node("lwcomponents:deployer_locked_on", {
mesecons = mesecon_support (),
digiline = digilines_support (),
tube = pipeworks_support (),
on_receive_fields = on_receive_fields,
can_dig = can_dig,
after_dig_node = utils.pipeworks_after_dig,
after_place_node = after_place_node_locked,
on_blast = on_blast,
on_timer = on_timer,

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
@@ -136,7 +130,7 @@ end
local function get_entity_height (objref)
if objref.get_luaentity then
entity = objref:get_luaentity ()
local entity = objref:get_luaentity ()
if entity and entity.name then
def = minetest.registered_entities[entity.name]
@@ -169,22 +163,25 @@ 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
for i = 1, #object, 1 do
if object[i]:is_player () then
-- player
if meta:get_string ("players") == "true" and
filter_item (pos, mode, object[i]:get_pos ()) then
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
@@ -404,7 +410,6 @@ local function after_place_node (pos, placer, itemstack, pointed_thing)
local is_off = itemstack and (itemstack:get_name () == "lwcomponents:detector" or
itemstack:get_name () == "lwcomponents:detector_locked")
meta:set_string ("inventory", "{ main = { }, filter = { } }")
meta:set_string ("formspec", get_form_spec (is_off, 1, 0, 0, 0, 0, 1))
meta:set_string ("entities", "false")

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,29 +139,31 @@ 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)
end
if obj then
obj:set_velocity (dispense_velocity (node))
end
end
if obj then
stack:set_count (stack:get_count () - 1)
inv:set_stack ("main", slot, stack)
@@ -244,7 +182,7 @@ end
local function after_place_node (pos, placer, itemstack, pointed_thing)
local function after_place_base (pos, placer, itemstack, pointed_thing)
local meta = minetest.get_meta (pos)
local spec =
"formspec_version[3]\n"..
@@ -262,6 +200,13 @@ local function after_place_node (pos, placer, itemstack, pointed_thing)
inv:set_size ("main", 16)
inv:set_width ("main", 4)
end
local function after_place_node (pos, placer, itemstack, pointed_thing)
after_place_base (pos, placer, itemstack, pointed_thing)
utils.pipeworks_after_place (pos)
-- If return true no item is taken from itemstack
return false
@@ -270,7 +215,7 @@ end
local function after_place_node_locked (pos, placer, itemstack, pointed_thing)
after_place_node (pos, placer, itemstack, pointed_thing)
after_place_base (pos, placer, itemstack, pointed_thing)
if placer and placer:is_player () then
local meta = minetest.get_meta (pos)
@@ -279,6 +224,8 @@ local function after_place_node_locked (pos, placer, itemstack, pointed_thing)
meta:set_string ("infotext", "Dispenser (owned by "..placer:get_player_name ()..")")
end
utils.pipeworks_after_place (pos)
-- If return true no item is taken from itemstack
return false
end
@@ -474,12 +421,112 @@ end
local function pipeworks_support ()
if utils.pipeworks_supported then
return
{
priority = 100,
input_inventory = "main",
connect_sides = { left = 1, right = 1, back = 1, bottom = 1, top = 1 },
insert_object = function (pos, node, stack, direction)
local meta = minetest.get_meta (pos)
local inv = (meta and meta:get_inventory ()) or nil
if inv then
return inv:add_item ("main", stack)
end
return stack
end,
can_insert = function (pos, node, stack, direction)
local meta = minetest.get_meta (pos)
local inv = (meta and meta:get_inventory ()) or nil
if inv then
return inv:room_for_item ("main", stack)
end
return false
end,
can_remove = function (pos, node, stack, dir)
-- returns the maximum number of items of that stack that can be removed
local meta = minetest.get_meta (pos)
local inv = (meta and meta:get_inventory ()) or nil
if inv then
local slots = inv:get_size ("main")
for i = 1, slots, 1 do
local s = inv:get_stack ("main", i)
if s and not s:is_empty () and utils.is_same_item (stack, s) then
return s:get_count ()
end
end
end
return 0
end,
remove_items = function (pos, node, stack, dir, count)
-- removes count items and returns them
local meta = minetest.get_meta (pos)
local inv = (meta and meta:get_inventory ()) or nil
local left = count
if inv then
local slots = inv:get_size ("main")
for i = 1, slots, 1 do
local s = inv:get_stack ("main", i)
if s and not s:is_empty () and utils.is_same_item (s, stack) then
if s:get_count () > left then
s:set_count (s:get_count () - left)
inv:set_stack ("main", i, s)
left = 0
else
left = left - s:get_count ()
inv:set_stack ("main", i, nil)
end
end
if left == 0 then
break
end
end
end
local result = ItemStack (stack)
result:set_count (count - left)
return result
end
}
end
return nil
end
local dispenser_groups = { cracky = 3 }
if utils.pipeworks_supported then
dispenser_groups.tubedevice = 1
dispenser_groups.tubedevice_receiver = 1
end
minetest.register_node("lwcomponents:dispenser", {
description = S("Dispenser"),
tiles = { "lwdispenser.png", "lwdispenser.png", "lwdispenser.png",
"lwdispenser.png", "lwdispenser.png", "lwdispenser_face.png"},
is_ground_content = false,
groups = { cracky = 3 },
groups = table.copy (dispenser_groups),
sounds = default.node_sound_stone_defaults (),
paramtype = "none",
param1 = 0,
@@ -490,10 +537,12 @@ minetest.register_node("lwcomponents:dispenser", {
mesecons = mesecon_support (),
digiline = digilines_support (),
tube = pipeworks_support (),
on_receive_fields = on_receive_fields,
after_place_node = after_place_node,
can_dig = can_dig,
after_dig_node = utils.pipeworks_after_dig,
on_blast = on_blast,
on_rightclick = on_rightclick
})
@@ -505,7 +554,7 @@ minetest.register_node("lwcomponents:dispenser_locked", {
tiles = { "lwdispenser.png", "lwdispenser.png", "lwdispenser.png",
"lwdispenser.png", "lwdispenser.png", "lwdispenser_face.png"},
is_ground_content = false,
groups = { cracky = 3 },
groups = table.copy (dispenser_groups),
sounds = default.node_sound_stone_defaults (),
paramtype = "none",
param1 = 0,
@@ -516,10 +565,12 @@ minetest.register_node("lwcomponents:dispenser_locked", {
mesecons = mesecon_support (),
digiline = digilines_support (),
tube = pipeworks_support (),
on_receive_fields = on_receive_fields,
after_place_node = after_place_node_locked,
can_dig = can_dig,
after_dig_node = utils.pipeworks_after_dig,
on_blast = on_blast,
on_rightclick = on_rightclick
})

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,6 +32,10 @@ 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 whether to cancel the action.

View File

@@ -3,11 +3,13 @@ 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.
the item at the back of them, or into a pipeworks tube if one is placed
behind it. 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. Pipeworks tubes can push items
into and pull items from the inventory.
Only the owner can dig or access the form of the locked version.

41
docs/camera.txt Normal file
View File

@@ -0,0 +1,41 @@
Camera
------
* This block is only available if digilines is loaded.
Cameras take an image in the direction they are facing. The colors in the
image represent what is being viewed. Nodes are gray, entities are blue and
players are green. The closer they are to the camera the brighter the color.
The viewing distance of the camera is 1 to 16 nodes. Also acts as a
digilines conductor.
Only the owner can dig or access the form of the locked version.
UI
Channel - digilines channel of camera.
Distance - the viewing distance forward from the camera (1 to 16).
Resolution - the image resolution (for both width and height, 1 to 128).
Digilines messages
"scan"
Sends a digilines message with the camera's channel and a table of the
image as the message (see below).
"distance n"
Sets the viewing distance of the camera. Will be clipped between 1 and
16.
"resolution n"
Sets the image resolution of the camera.
The image is an indexed table of indexed tables. Each inner table is one
line of the image ordered top to bottom. There are resolution number of
lines. Each line has a string value for each pixel of that line left to
right. The string is a hex color string eg. "00FF00". There are resolution
number of pixels per line.
The image format is compatible with digistuff's digiscreens and lwcomputers'
digiscreens and digipanels. It is best to set the resolution of the camera
to the resolution of the display, then the image from the camera can be sent
straight to the display device.

104
docs/cannon.txt Normal file
View File

@@ -0,0 +1,104 @@
Cannon
------
This item is available without digilines or mesecons as it can be used
manually.
Contains a single inventory slot and shoots an item on command.
If the hopper mod is loaded, will take items from the top and sides, and
release them from the bottom. Pipeworks tubes can push items into and pull
items from the inventory.
Cannon rotation range:
side to side - +/-60 degrees (- = left, + = right)
down to up: -20 to 70 degrees (- = down, + = up)
To spawn entities from cannons include the lwcomponents_spawners mod.
Only the owner can dig or access the form of the locked version.
UI
Channel - digilines channel of cannon.
Hide - hides the form so the cannon can be used manually, double right click
any other face besides the rear to bring up the form.
Controller - digistuff game controller digilines channel.
Sensitive - if checked game controller movements have a x3 sensitivity.
Top 1 slot inventory - storage of items to shoot.
Bottom 32 slot inventory - player's inventory.
Manual control
Place some items in the single slot, and click the Hide button. On the
rear panel their are 4 gray buttons. Right clicking them turns the barrel
in that direction 10 degrees. aux + right click turns 1 degree. Clicking
the red button fires an item. To bring up the form again double right click
any other face besides the rear.
Digistuff game controller
Connect a game controller to the cannon with digilines cable. Enter the
game controller's channel in the Controller field of the cannon's form
(click Set). Your turning movements turn the cannon's barrel in the
direction the cannon is facing. If Sensitive is checked the movements
have an increased sensitivity (x3) to try and keep the target in your view,
otherwise x1. Punching shoots an item. The game controller updates every
0.2 seconds, so a quick punch may not register. A locked cannon can only
be controlled by it's owner with a game controller.
Mesecons
Shoots an item when power is turned on.
Digilines messages
"pitch <n>"
Sets the pitch of the barrel. n should be between -20 to 70, and will
be clipped to this range.
eg. "pitch 22"
"rotation <n>"
Sets the rotation of the barrel. n should be between -60 to 60, and will
be clipped to this range.
eg. "rotation 45"
table - aim position
{
action = "aim",
aim = { x, y, z }
}
x is the horizontal left (negative) to right. 0 is straight ahead.
y is the vertical down (negative) to up. 0 is straight ahead.
z is the depth. Must be > 0 or ignored. 1 is the position directly in
front of the cannon.
* The cannon barrel's height is 0.65 above the cannon's placed position.
When aiming for height, if the cannon's base height is taken as -0.5,
and consider height from there. This allows for the barrel height
and a little drop in the projectile at close range.
"fire"
Shoots an item.
* Note: turning the barrel is animated and takes 0.1 seconds per 10
degrees of movement. A fire command while moving is ignored.
Three shells are provided for cannons.
Shell
This shell has a 70% chance of destroying a node within a radius of 2 from
the impact, a 5% chance a flammable node will be set on fire within a
radius of 2 (if fire is installed), and damages players and entities within
a radius of 4 with a maximum of 20 damage points.
Soft Shell
This shell has a 50% chance of destroying only soft (buildable_to) nodes,
such as grass, within a radius of 2 from the impact, a 5% chance a flammable
node will be set on fire within a radius of 2 (if fire is installed), and
damages players and entities within a radius of 4 with a maximum of 20
damage points.
Fire Shell
* This item is only available if fire is installed.
This shell does not destroying nodes, has a 70% chance of setting a node
on fire, whether its flammable or not within a radius of 2, and damages
players and entities within a radius of 4 with a maximum of 20 damage
points.

View File

@@ -4,7 +4,8 @@ Collector
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.
from the top and sides, and release them from the bottom. Pipeworks tubes
can push items into and pull items from the inventory.
Only the owner can dig or access the form of the locked version.

69
docs/conduit.txt Normal file
View File

@@ -0,0 +1,69 @@
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, and will work
in unloaded blocks.
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.
Pipeworks tubes can push items into and pull items from the inventory.
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.

View File

@@ -7,6 +7,7 @@ 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.
Pipeworks tubes can push items into and pull items from the inventory.
Only the owner can dig or access the form of the locked version.

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

@@ -4,13 +4,10 @@ Dispenser
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.
items from the top and sides, and release them from the bottom. Pipeworks
tubes can push items into and pull items from the inventory.
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.

View File

@@ -4,7 +4,8 @@ Dropper
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.
top and sides, and release them from the bottom. Pipeworks tubes can push
items into and pull items from the inventory.
Only the owner can dig or access the form of the locked version.

View File

@@ -1,6 +1,6 @@
MoveFloor
---------
* This block is only available if mesecons and mesecons_mvps is loaded.
* This block is only available if mesecons 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

31
docs/pistons.txt Normal file
View File

@@ -0,0 +1,31 @@
Pistons and sticky pistons
--------------------------
* These blocks are only available if digilines and/or mesecons are loaded.
Pistons push up to the setting Maximum piston nodes (default 15) in front
of the pusher when extended. Sticky piston draw back a single node in
front of the pusher when retracted. Piston also act as a digilines
conductor.
UI
Channel - digilines channel of piston.
Single move - pusher extends 1 node if checked, otherwise 2 nodes.
Mesecons
Piston extends while power is turned on.
Digilines messages
"extend n"
Extends the piston pusher to extent n (0, 1 or 2). If n is not given
pusher extends to maximum extent. 0 is retracted.
"retract"
Same as 'extend 0'.
"single"
Sets piston to single move mode.
"double"
Sets piston to double move mode.

102
docs/storage.txt Normal file
View File

@@ -0,0 +1,102 @@
Storage
-------
Storage is accommodated with two nodes, Storage Unit and Storage Indexer.
Storage units can be interacted with like a basic chest, each with 32 slots,
and visually join together when placed adjacent to each other. Units are
generally accessed via indexers, which action all adjoining units as a
single storage block. Multiple indexers can action a single storage block.
Only the owner can dig or access the form of the locked versions.
Unowned indexers can only access unowned units. Owned indexers can access
units of the same owner or unowned units.
UI
Search - top left.
List - left.
Channel - digilines channel of indexer.
Input - middle.
Output - top right.
Filter - center right.
Player inventor - lower right.
When the UI is accessed the storage is scanned, and its contents are
displayed in the list. The list contains the following columns:
Item button - pressing will place one of these items from storage into the
output.
10 button - pressing will place 10 of the item.
<stack> button - pressing places a full stack.
Count - the total number of this item in storage.
Description - description of the item.
Note that the 10 and stack buttons may vary in number or not appear
depending on the requirements of that item.
The form does not update while open. A request for more items than in
storage will only deliver the amount in storage.
Terms can be entered into the search field, and when enter is pressed or
the Search button is pressed, only items whose description contains these
terms are shown in the list. That is if they match any of the space
separated terms.
Any items placed into the input are placed into storage. If the filter
is clear all items are accepted. If the filter contains items only these
items will be accepted. Any items not accepted or that do not fit into
storage are placed into the output.
When items are placed into the filter a copy is used and the item returns
to where it was taken from. When items are removed from the filter they
are disposed of.
Hoppers placed to the top or sides of an indexer will feed items into the
input. Hoppers placed below an indexer will take items from the output.
Pipeworks tubes can push items into the input, and pull items from the
output.
Every 20 inputs the storage is consolidated to minimize fragmentation.
Digilines messages
"output <item> <count>"
or
{
action = "output",
item = "<item>",
count = <count>
}
Moves the item/s to the output. If count is omitted defaults to 1. If
the requested amount is greater than in storage, only the stored amount
is moved.
"inventory"
Sends a digilines message with it's own channel in the following form:
{
action = "inventory",
inventory = {
<items>
}
}
The inventory key is an indexed list of items in storage. Each item
entry is a table with the following keys:
{
name -- string, the name of the item, as <mod>:<name>
description -- string, description of the item, same as in UI
count -- number, the total number of this item in storage
custom -- true if a custom item (has metadata), false if not
pallet_index -- string if the item has a pallet index, otherwise nil
id -- string, unique id of the item in storage
}
The description is derived in the following manner: from a custom
description in metadata; if none then the short description from
the item's definition; if none then the description from the item's
definition; if none then the item's name, as <mod>:<name>.
Note: When sending output messages the simple item name, as <mod>:<name>,
will work for most items, but not for custom items. With custom items, or
to play it safe, use the table form of the output message and set the item
field with the id field for the item from a returned inventory.

7
docs/through_wire.txt Normal file
View File

@@ -0,0 +1,7 @@
Mesecons Through Wire
---------------------
* This block is only available if mesecons is loaded.
Will transmit mesecons power when placed one to two blocks apart opposing
each other, through solid blocks or open space. Can also be used as a mesecons
crossover.

View File

@@ -118,7 +118,7 @@ end
local function after_place_node (pos, placer, itemstack, pointed_thing)
local function after_place_base (pos, placer, itemstack, pointed_thing)
local meta = minetest.get_meta (pos)
local spec =
"formspec_version[3]\n"..
@@ -136,6 +136,13 @@ local function after_place_node (pos, placer, itemstack, pointed_thing)
inv:set_size ("main", 16)
inv:set_width ("main", 4)
end
local function after_place_node (pos, placer, itemstack, pointed_thing)
after_place_base (pos, placer, itemstack, pointed_thing)
utils.pipeworks_after_place (pos)
-- If return true no item is taken from itemstack
return false
@@ -144,7 +151,7 @@ end
local function after_place_node_locked (pos, placer, itemstack, pointed_thing)
after_place_node (pos, placer, itemstack, pointed_thing)
after_place_base (pos, placer, itemstack, pointed_thing)
if placer and placer:is_player () then
local meta = minetest.get_meta (pos)
@@ -153,6 +160,8 @@ local function after_place_node_locked (pos, placer, itemstack, pointed_thing)
meta:set_string ("infotext", "Dropper (owned by "..placer:get_player_name ()..")")
end
utils.pipeworks_after_place (pos)
-- If return true no item is taken from itemstack
return false
end
@@ -348,12 +357,112 @@ end
local function pipeworks_support ()
if utils.pipeworks_supported then
return
{
priority = 100,
input_inventory = "main",
connect_sides = { left = 1, right = 1, back = 1, bottom = 1, top = 1 },
insert_object = function (pos, node, stack, direction)
local meta = minetest.get_meta (pos)
local inv = (meta and meta:get_inventory ()) or nil
if inv then
return inv:add_item ("main", stack)
end
return stack
end,
can_insert = function (pos, node, stack, direction)
local meta = minetest.get_meta (pos)
local inv = (meta and meta:get_inventory ()) or nil
if inv then
return inv:room_for_item ("main", stack)
end
return false
end,
can_remove = function (pos, node, stack, dir)
-- returns the maximum number of items of that stack that can be removed
local meta = minetest.get_meta (pos)
local inv = (meta and meta:get_inventory ()) or nil
if inv then
local slots = inv:get_size ("main")
for i = 1, slots, 1 do
local s = inv:get_stack ("main", i)
if s and not s:is_empty () and utils.is_same_item (stack, s) then
return s:get_count ()
end
end
end
return 0
end,
remove_items = function (pos, node, stack, dir, count)
-- removes count items and returns them
local meta = minetest.get_meta (pos)
local inv = (meta and meta:get_inventory ()) or nil
local left = count
if inv then
local slots = inv:get_size ("main")
for i = 1, slots, 1 do
local s = inv:get_stack ("main", i)
if s and not s:is_empty () and utils.is_same_item (s, stack) then
if s:get_count () > left then
s:set_count (s:get_count () - left)
inv:set_stack ("main", i, s)
left = 0
else
left = left - s:get_count ()
inv:set_stack ("main", i, nil)
end
end
if left == 0 then
break
end
end
end
local result = ItemStack (stack)
result:set_count (count - left)
return result
end
}
end
return nil
end
local dropper_groups = { cracky = 3 }
if utils.pipeworks_supported then
dropper_groups.tubedevice = 1
dropper_groups.tubedevice_receiver = 1
end
minetest.register_node("lwcomponents:dropper", {
description = S("Dropper"),
tiles = { "lwdropper.png", "lwdropper.png", "lwdropper.png",
"lwdropper.png", "lwdropper.png", "lwdropper_face.png"},
is_ground_content = false,
groups = { cracky = 3 },
groups = table.copy (dropper_groups),
sounds = default.node_sound_stone_defaults (),
paramtype = "none",
param1 = 0,
@@ -364,10 +473,12 @@ minetest.register_node("lwcomponents:dropper", {
mesecons = mesecon_support (),
digiline = digilines_support (),
tube = pipeworks_support (),
on_receive_fields = on_receive_fields,
after_place_node = after_place_node,
can_dig = can_dig,
after_dig_node = utils.pipeworks_after_dig,
on_blast = on_blast,
on_rightclick = on_rightclick
})
@@ -379,7 +490,7 @@ minetest.register_node("lwcomponents:dropper_locked", {
tiles = { "lwdropper.png", "lwdropper.png", "lwdropper.png",
"lwdropper.png", "lwdropper.png", "lwdropper_face.png"},
is_ground_content = false,
groups = { cracky = 3 },
groups = table.copy (dropper_groups),
sounds = default.node_sound_stone_defaults (),
paramtype = "none",
param1 = 0,
@@ -390,10 +501,12 @@ minetest.register_node("lwcomponents:dropper_locked", {
mesecons = mesecon_support (),
digiline = digilines_support (),
tube = pipeworks_support (),
on_receive_fields = on_receive_fields,
after_place_node = after_place_node_locked,
can_dig = can_dig,
after_dig_node = utils.pipeworks_after_dig,
on_blast = on_blast,
on_rightclick = on_rightclick
})

538
explode.lua Normal file
View File

@@ -0,0 +1,538 @@
local utils = ...
local S = utils.S
local explode = { }
if minetest.global_exists ("fire") then
explode.fire_supported = true
function explode.set_fire (pos, burn_all)
local node = utils.get_far_node (pos)
if not node then
return
end
if node.name ~= "air" then
local def = minetest.registered_nodes[node.name]
if not def or not def.buildable_to then
return
end
end
local dirs =
{
{ x = 0, y = -1, z = 0 },
{ x = -1, y = 0, z = 0 },
{ x = 0, y = 0, z = -1 },
{ x = 1, y = 0, z = 0 },
{ x = 0, y = 0, z = 1 }
}
for i = 1, #dirs do
node = utils.get_far_node (vector.add (pos, dirs[i]))
if node and node.name ~= "air" and node.name ~= "fire:basic_flame" then
local def = minetest.registered_nodes[node.name]
if def and def.liquidtype == "none" then
if (def.groups and def.groups.flammable) or burn_all then
minetest.set_node (pos, { name = "fire:basic_flame" })
return
end
end
end
end
end
else
explode.fire_supported = false
function explode.set_fire (pos, burn_all)
end
end
--local function is_same_item (stack1, stack2)
--local copy1 = ItemStack (stack1)
--local copy2 = ItemStack (stack2)
--if copy1 and copy2 then
--copy1:set_count (1)
--copy2:set_count (1)
--if copy1:to_string () == copy2:to_string () then
--return true
--end
--end
--return false
--end
local function dig_node (pos, toolname)
local node = utils.get_far_node (pos)
local dig = false
local drops = nil
if toolname == true then
dig = true
toolname = nil
end
if node and node.name ~= "air" 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
minetest.remove_node (pos)
end
end
return drops
end
local function add_drops (drops, drop)
if drops and drop then
for i = 1, #drop do
local item = ItemStack (drop[i])
if item and not item:is_empty () then
local existing = drops[item:get_name ()]
if existing and utils.is_same_item (item, existing) then
existing:set_count (existing:get_count () + item:get_count ())
else
drops[item:get_name ()] = item
end
end
end
end
end
local function explode_node (pos, dig_chance, intensity, drops, filter)
if not utils.is_protected (pos, nil) then
dig_chance = math.min (math.max (dig_chance, 0), 100)
if math.random (100) <= dig_chance then
local node = utils.get_far_node (pos)
local blasted = false
if node and node.name ~= "air" then
local def = minetest.registered_nodes[node.name]
if def then
if def.diggable == false then
return false
end
for k, v in pairs (filter) do
if def[k] == nil then
if filter[k.."_undefined"] == false then
return false
end
elseif def[k] ~= v then
return false
end
end
if def.on_blast then
def.on_blast (pos, intensity)
blasted = true
end
end
if not blasted then
local drop = dig_node (pos, true)
add_drops (drops, drop)
end
minetest.check_for_falling ({ x = pos.x, y = pos.y + 1, z = pos.z })
return true
end
end
end
return false
end
local function burn_node (pos, fire_chance, burn_all)
if not utils.is_protected (pos, nil) then
fire_chance = math.min (math.max (fire_chance, 0), 100)
if math.random (100) <= fire_chance then
explode.set_fire (pos, burn_all)
end
end
end
local function entity_is_drop (obj)
return obj.get_luaentity and obj:get_luaentity () and
obj:get_luaentity ().name and
obj:get_luaentity ().name == "__builtin:item"
end
local function explode_entities (pos, radius, damage, drops)
local objs = minetest.get_objects_inside_radius (pos, radius)
for _, obj in ipairs (objs) do
-- could be detached player from controller
if obj.get_pos and obj:get_pos () then
local obj_pos = obj:get_pos ()
local dir = vector.direction (pos, obj_pos)
local dist = vector.length (vector.subtract (obj_pos, pos))
local vel = vector.multiply (dir, ((radius + 1) - dist) / (radius + 1) * damage * 5)
if entity_is_drop (obj) then
obj:add_velocity (vel)
elseif not obj:get_armor_groups ().immortal then
local ent_damage = ((radius - dist) / radius * damage / 2) + (damage / 2)
local reason = { type = "set_hp", from = "lwcomponents" }
if obj:is_player() then
local parent = obj:get_attach ()
if parent then
obj:set_detach ()
end
obj:add_velocity (vel)
obj:set_hp (obj:get_hp () - ent_damage, reason)
else
local luaobj = obj:get_luaentity ()
-- object might have disappeared somehow
if luaobj then
if luaobj.name == "digistuff:controller_entity" then
for _, child in ipairs (obj:get_children ()) do
if child:is_player () then
local def = utils.find_item_def ("digistuff:controller_programmed")
if def and def.on_rightclick then
def.on_rightclick (obj:get_pos (), ItemStack (), child)
local ent_damage = ((radius - dist) / radius * damage / 2) + (damage / 2)
local reason = { type = "set_hp", from = "lwcomponents" }
child:add_velocity (vel)
child:set_hp (child:get_hp () - ent_damage, reason)
end
end
end
else
local do_damage = true
local do_knockback = true
local entity_drops = {}
local objdef = minetest.registered_entities[luaobj.name]
if objdef and objdef.on_blast then
do_damage, do_knockback, entity_drops = objdef.on_blast (luaobj, ent_damage)
end
if do_knockback then
obj:add_velocity (vel)
end
if do_damage then
obj:set_hp (obj:get_hp() - ent_damage, reason)
end
add_drops (drops, entity_drops)
end
end
end
end
end
end
end
local function spray_drops (pos, drops, damage)
local max_vel = damage * 2.5
for k, stack in pairs (drops) do
local vel =
{
x = math.random (max_vel) - (max_vel / 2),
y = math.random (max_vel) - (max_vel / 2),
z = math.random (max_vel) - (max_vel / 2)
}
local drop = minetest.add_item (pos, stack)
if drop then
drop:set_velocity (vel)
end
end
end
local function add_effects (pos, radius, drops)
minetest.add_particle ({
pos = pos,
velocity = vector.new (),
acceleration = vector.new (),
expirationtime = 0.4,
size = 30, -- radius * 10,
collisiondetection = false,
vertical = false,
texture = "lwcomponents_boom.png",
glow = 15,
})
minetest.add_particlespawner ({
amount = 64,
time = 0.5,
minpos = vector.subtract (pos, radius / 2),
maxpos = vector.add (pos, radius / 2),
minvel = {x = -10, y = -10, z = -10},
maxvel = {x = 10, y = 10, z = 10},
minacc = vector.new (),
maxacc = vector.new (),
minexptime = 1,
maxexptime = 2.5,
minsize = 9, -- radius * 3,
maxsize = 15, -- radius * 5,
texture = "lwcomponents_smoke.png",
})
-- we just dropped some items. Look at the items entities and pick
-- one of them to use as texture
local texture = "lwcomponents_blast.png" --fallback texture
local node
local most = 0
if drops then
for name, stack in pairs (drops) do
local count = stack:get_count()
if count > most then
most = count
local def = minetest.registered_nodes[name]
if def then
node = { name = name }
end
if def and def.tiles and def.tiles[1] then
if type (def.tiles[1]) == "table" then
texture = def.tiles[1].name or "lwcomponents_blast.png"
elseif type (def.tiles[1]) == "string" then
texture = def.tiles[1]
end
end
end
end
end
minetest.add_particlespawner ({
amount = 64,
time = 0.1,
minpos = vector.subtract (pos, radius / 2),
maxpos = vector.add (pos, radius / 2),
minvel = {x = -3, y = 0, z = -3},
maxvel = {x = 3, y = 5, z = 3},
minacc = {x = 0, y = -10, z = 0},
maxacc = {x = 0, y = -10, z = 0},
minexptime = 0.8,
maxexptime = 2.0,
minsize = 1, -- radius * 0.33,
maxsize = 3, -- radius,
texture = texture,
-- ^ only as fallback for clients without support for `node` parameter
node = node,
collisiondetection = true,
})
end
function utils.boom (pos, -- center of explosion
node_radius, node_chance, -- radius and chance in 100
fire_radius, fire_chance, -- radius and chance in 100
entity_radius, entity_damage, -- radius and max damage applied
disable_drops, -- true to disable drops
node_filter, -- node filter table as { buildable_to = true, buildable_to_undefined = false, ... }
burn_all, -- true to set fire to anything, otherwise only flammable
sound) -- sound on blast, if nil plays default
pos = vector.round (pos)
node_radius = math.floor (node_radius or 1)
fire_radius = math.floor (fire_radius or node_radius)
entity_radius = math.floor (entity_radius or node_radius * 2)
node_chance = node_chance or 80
fire_chance = fire_chance or 30
entity_damage = math.floor (entity_damage or entity_radius)
disable_drops = disable_drops == true
node_filter = node_filter or { }
burn_all = burn_all == true
sound = sound or "lwcannon"
local drops = { }
local effects_radius = (node_radius > 0 and node_radius) or entity_radius
local center_free = false
if not utils.is_protected (pos, nil) then
local center_node = utils.get_far_node (pos)
if not center_node or center_node.name == "air" then
center_free = true
end
end
if node_radius > 0 and node_chance > 0 then
local extents = node_radius * 2
for y = -extents, extents, 1 do
for z = -extents, extents, 1 do
for x = -extents, extents, 1 do
local node_pos = { x = x + pos.x, y = y + pos.y, z = z + pos.z }
local length = vector.length ({ x = x, y = y, z = z })
if node_chance > 0 and length <= node_radius then
if explode_node (node_pos, node_chance, 1.0, drops, node_filter) then
if vector.equals (pos, node_pos) then
center_free = true
end
end
end
end
end
end
end
if fire_radius > 0 and fire_chance > 0 then
local extents = fire_radius * 2
for y = -extents, extents, 1 do
for z = -extents, extents, 1 do
for x = -extents, extents, 1 do
local node_pos = { x = x + pos.x, y = y + pos.y, z = z + pos.z }
local length = vector.length ({ x = x, y = y, z = z })
if fire_chance > 0 and length <= fire_radius then
burn_node (node_pos, fire_chance, burn_all)
end
end
end
end
end
minetest.sound_play (sound,
{
pos = pos,
gain = 2.5,
max_hear_distance = math.min (effects_radius * 20, 128)
},
true)
if center_free then
minetest.set_node (pos, { name = "lwcomponents:boom" })
end
explode_entities (pos, entity_radius, entity_damage, drops)
if not disable_drops then
spray_drops (pos, drops, entity_damage)
end
add_effects (pos, effects_radius, drops)
minetest.log ("action", "A Shell explosion occurred at " .. minetest.pos_to_string (pos) ..
" with radius " .. entity_radius)
end
minetest.register_node ("lwcomponents:boom", {
description = S("Boom"),
drawtype = "airlike",
tiles = { "lwcomponents_boom.png" },
inventory_image = "lwcomponents_boom.png",
wield_image = "lwcomponents_boom.png",
light_source = default.LIGHT_MAX,
use_texture_alpha = "blend",
sunlight_propagates = true,
walkable = false,
pointable = false,
diggable = false,
climbable = false,
buildable_to = true,
floodable = true,
is_ground_content = false,
drop = "",
paramtype = "light",
param1 = 255,
post_effect_color = { a = 128, r = 255, g = 0, b = 0 },
groups = { dig_immediate = 3, not_in_creative_inventory = 1 },
on_construct = function (pos)
minetest.get_node_timer (pos):start (0.5)
end,
on_timer = function (pos, elapsed)
minetest.remove_node (pos)
return false
end,
-- unaffected by explosions
on_blast = function() end,
})
--

74
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
@@ -165,14 +199,10 @@ local function on_blast (pos, intensity)
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)
@@ -318,7 +348,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 +356,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,
@@ -345,7 +376,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 +384,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,
@@ -372,7 +404,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 +412,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,
@@ -400,7 +433,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 +441,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.7"
local version = "0.1.23"
local mod_storage = minetest.get_mod_storage ()
@@ -15,9 +15,11 @@ end
local utils = { }
local modpath = minetest.get_modpath ("lwcomponents")
loadfile (modpath.."/utils.lua") (utils, mod_storage)
loadfile (modpath.."/settings.lua") (utils)
loadfile (modpath.."/utils.lua") (utils, mod_storage)
loadfile (modpath.."/explode.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)
@@ -29,6 +31,13 @@ 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.."/cannon.lua") (utils)
loadfile (modpath.."/cannon_shell.lua") (utils)
loadfile (modpath.."/pistons.lua") (utils)
loadfile (modpath.."/through_wire.lua") (utils)
loadfile (modpath.."/camera.lua") (utils)
loadfile (modpath.."/storage.lua") (utils)
loadfile (modpath.."/extras.lua") (utils)
loadfile (modpath.."/digiswitch.lua") (utils)
loadfile (modpath.."/movefloor.lua") (utils)

View File

@@ -13,6 +13,8 @@ without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
See the GNU Lesser General Public License for more details:
https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
Mesecons through wire code was adapted from mesecons_receiver.
lwsiren-buzz.ogg
@@ -59,6 +61,16 @@ https://creativecommons.org/licenses/by/4.0/
lwmovefloor.ogg
---------------
https://www.freesoundslibrary.com/elevator-sound-effect-elevator-ride-doors-closing-and-opening/
License: Attribution 4.0 International (CC BY 4.0). You are allowed to use
sound effects free of charge and royalty free in your multimedia projects
for commercial or non-commercial purposes.
Media license
-------------
siren images derived from images from https://openclipart.org, which is
@@ -67,8 +79,21 @@ public domain.
fan images derived from images from https://openclipart.org, which is
public domain.
camera lens images derived from images from https://openclipart.org, which
is public domain.
storage nodes images derived from images from https://openclipart.org, which
is public domain.
player button images derived from mesecons button image.
cannon firing and explosion sound from tnt (TumeniNodes/steveygos93),
released under CC0 1.0 (originally from https://freesound.org/s/80401/)
boom image from tnt, released under CC BY-SA 3.0.
Piston images and sounds from mesecons_pistons, released under CC-BY-SA 3.0.
All other media, or media not covered by a licence, is licensed
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
name = lwcomponents
depends = default
optional_depends = lwdrops, mesecons, digilines, unifieddyes, intllib, hopper, mobs, digistuff
optional_depends = mesecons, digilines, unifieddyes, intllib, hopper, digistuff, pipeworks

View File

@@ -0,0 +1,625 @@
# Blender v2.82 (sub 7) OBJ File: 'canon.blend'
# www.blender.org
mtllib lwcomponents_cannon_barrel.mtl
o Canon
v 0.999994 -2.037148 -0.790288
v 0.999994 -0.938179 -2.111386
v 0.999994 -1.251549 1.868645
v 0.999994 -2.145818 0.243561
v 0.999994 -1.824579 1.232245
v 0.999994 -1.517369 -1.690576
v -0.837650 -1.110379 -1.986275
v -0.999994 -1.517369 -1.690576
v -0.999994 -0.938179 -2.111386
v -0.437400 -1.222309 -1.904956
v 0.000000 -1.344629 -1.816076
v 0.437400 -1.222309 -1.904956
v 0.837650 -1.110379 -1.986275
v -0.999994 -2.037148 -0.790289
v -0.999994 -2.145818 0.243560
v -0.999994 -1.824579 1.232244
v -0.000000 -1.538639 1.549804
v 0.089079 -1.516209 1.574724
v 0.947191 -1.300109 1.814725
v -0.089079 -1.516209 1.574724
v -0.947191 -1.300109 1.814724
v -0.999994 -1.251549 1.868644
v 1.673030 -0.625437 3.499885
v 1.414210 0.340481 4.396455
v 1.224740 -0.366620 4.396455
v 1.673030 1.306400 3.499885
v 1.931850 0.340481 3.499885
v -0.517635 0.340481 4.914094
v -0.448284 0.599299 4.914094
v -1.414210 0.340481 4.396455
v 1.673030 1.306400 2.464605
v 0.749998 1.639521 -5.027746
v 0.965919 2.013511 2.464605
v 1.299040 1.090479 -5.027746
v -0.000000 2.272331 2.464605
v 0.965919 -1.332548 3.499884
v -0.000000 -1.591369 2.464605
v 0.965919 -1.332548 2.464605
v -0.000000 -1.591369 3.499884
v -1.673030 -0.625437 3.499884
v -1.224740 -0.366620 4.396455
v -0.000000 -1.073729 4.396455
v 0.258818 -0.107803 4.914094
v -0.000000 -0.177154 4.914094
v -0.965919 2.013511 3.499884
v -0.000000 1.754691 4.396455
v -0.000000 2.272331 3.499884
v -1.299040 -0.409517 -5.027746
v -1.673030 -0.625437 2.464605
v -0.749998 -0.958559 -5.027746
v -0.965919 -1.332548 2.464605
v 1.500000 0.340481 -5.027746
v 1.931850 0.340481 2.464605
v 1.299040 -0.409517 -5.027746
v 1.224740 1.047583 4.396455
v -1.500000 0.340481 -5.027746
v -1.931850 0.340481 2.464605
v -1.299040 1.090479 -5.027746
v 0.965919 2.013511 3.499884
v -0.965919 2.013511 2.464605
v -0.749998 1.639521 -5.027746
v -0.258818 -0.107803 4.914094
v 0.448284 0.081663 4.914094
v -0.965919 -1.332548 3.499884
v -0.707102 -0.884259 4.396455
v 0.000000 1.840482 -5.027746
v -1.673030 1.306400 2.464605
v 0.448284 0.599299 4.914094
v 0.707102 1.565221 4.396455
v -1.673030 1.306400 3.499884
v -0.999994 0.340481 -5.027746
v -0.866022 0.840474 -5.027746
v -0.499992 1.206504 -5.027746
v 0.000000 1.340475 -5.027746
v 0.499992 1.206504 -5.027746
v 0.866022 0.840474 -5.027746
v 0.999994 0.340481 -5.027746
v -0.866022 -0.159511 -5.027746
v -0.499992 -0.525541 -5.027746
v 0.000000 -0.659513 -5.027746
v 0.000000 -1.159519 -5.027746
v 0.499992 -0.525541 -5.027746
v 0.749998 -0.958559 -5.027746
v 0.866022 -0.159511 -5.027746
v 0.258818 0.788765 4.914094
v -0.707102 1.565221 4.396455
v -1.224740 1.047583 4.396455
v -0.258818 0.788765 4.914094
v 0.707102 -0.884259 4.396455
v 1.673030 -0.625437 2.464605
v -0.448284 0.081663 4.914094
v -1.931850 0.340481 3.499884
v -0.000000 0.858117 4.914094
v 0.517635 0.340481 4.914094
v 0.499992 1.206504 -0.017755
v 0.000000 1.340475 -0.017755
v -0.866022 -0.159511 -0.017756
v -0.999994 0.340481 -0.017756
v 0.999994 0.340481 -0.017755
v 0.866022 -0.159511 -0.017755
v 0.000000 -0.659513 -0.017755
v 0.499992 -0.525541 -0.017755
v -0.866022 0.840474 -0.017756
v -0.499992 1.206504 -0.017756
v -0.499992 -0.525541 -0.017756
v 0.866022 0.840474 -0.017755
vt 0.898722 0.101473
vt 0.949058 0.000000
vt 0.949058 0.291647
vt 0.897343 0.177359
vt 0.917533 0.247935
vt 0.921432 0.033397
vt 0.644810 0.718620
vt 0.656466 0.688883
vt 0.656466 0.731202
vt 0.938458 0.774110
vt 0.917273 0.733004
vt 0.946494 0.744866
vt 0.929676 0.806070
vt 0.917273 0.879136
vt 0.938458 0.838029
vt 0.946494 0.867274
vt 0.958858 0.879136
vt 0.720513 0.816705
vt 0.809535 0.875496
vt 0.700708 0.883794
vt 0.829340 0.808407
vt 0.720513 0.741037
vt 0.829340 0.732739
vt 0.829340 0.985218
vt 0.900553 0.888939
vt 0.900554 1.000000
vt 0.829340 0.874157
vt 1.000000 0.879136
vt 0.979470 0.806070
vt 1.000000 0.733004
vt 0.977860 0.812578
vt 0.962344 0.875278
vt 0.958858 0.879136
vt 0.977860 0.799561
vt 0.962344 0.736862
vt 0.333921 0.730752
vt 0.330130 0.692431
vt 0.333921 0.688883
vt 0.900071 0.556676
vt 0.950406 0.658149
vt 0.922781 0.624752
vt 0.950406 0.366502
vt 0.898691 0.480790
vt 0.918881 0.410213
vt 0.255350 0.066011
vt 0.224399 0.000000
vt 0.267734 0.000231
vt 0.463512 0.067703
vt 0.499410 0.000000
vt 0.525690 0.066413
vt 0.258332 0.815437
vt 0.267951 0.798482
vt 0.303850 0.861759
vt 0.463512 0.143300
vt 0.399738 0.689322
vt 0.391714 0.143300
vt 0.455487 0.689322
vt 0.656641 0.142072
vt 0.718822 0.143213
vt 0.728112 0.689215
vt 0.196154 0.065695
vt 0.326930 0.066054
vt 0.391714 0.141456
vt 0.326930 0.141696
vt 0.391714 0.065814
vt 0.584886 0.622872
vt 0.597270 0.688652
vt 0.553935 0.688883
vt 0.442482 0.882141
vt 0.461064 0.811564
vt 0.474668 0.825408
vt 0.062178 0.621619
vt 0.026280 0.689322
vt 0.000000 0.622909
vt 0.595217 0.000034
vt 0.636204 0.213000
vt 0.584886 0.547230
vt 0.650796 0.000000
vt 0.653098 0.222127
vt 0.650827 0.503665
vt 0.656466 0.547187
vt 0.655974 0.499724
vt 0.219718 0.688604
vt 0.196154 0.141337
vt 0.265682 0.688849
vt 0.453892 0.000944
vt 0.174230 0.001002
vt 0.196154 0.547312
vt 0.125951 0.000000
vt 0.656466 0.066476
vt 0.682592 0.000000
vt 0.718647 0.067616
vt 0.062178 0.546022
vt 0.000000 0.547312
vt 0.070203 0.000000
vt 0.493250 0.830475
vt 0.405317 0.740987
vt 0.456085 0.792653
vt 0.391714 0.792653
vt 0.172450 0.755310
vt 0.129645 0.690784
vt 0.177048 0.689322
vt 0.525690 0.547546
vt 0.549254 0.000279
vt 0.679831 0.688329
vt 0.525690 0.142010
vt 0.503765 0.688320
vt 0.133976 0.546022
vt 0.493250 0.895984
vt 0.442482 0.703166
vt 0.474668 0.759899
vt 0.728112 0.000835
vt 0.021924 0.001002
vt 0.133976 0.621619
vt 0.571208 0.835015
vt 0.540118 0.853282
vt 0.525690 0.798482
vt 0.579538 0.893399
vt 0.561589 0.798483
vt 0.540119 0.743682
vt 0.571208 0.761949
vt 0.579538 0.703566
vt 0.597488 0.735205
vt 0.633386 0.725417
vt 0.633386 0.688883
vt 0.107696 0.908522
vt 0.071797 0.862198
vt 0.107697 0.871988
vt 0.053848 0.893838
vt 0.045518 0.835455
vt 0.597487 0.861759
vt 0.633386 0.908082
vt 0.633386 0.871549
vt 0.071798 0.735645
vt 0.107696 0.689322
vt 0.107696 0.725856
vt 0.053848 0.704005
vt 0.045519 0.762388
vt 0.014429 0.744121
vt 0.035899 0.798922
vt 0.000000 0.798922
vt 0.014428 0.853721
vt 0.303850 0.715627
vt 0.241672 0.752160
vt 0.258332 0.688883
vt 0.401333 0.000944
vt 0.391714 0.067703
vt 0.330130 0.761949
vt 0.330130 0.815437
vt 0.267951 0.778904
vt 0.071797 0.688378
vt 0.124357 0.688378
vt 0.649670 0.688620
vt 0.656466 0.622829
vt 0.405317 0.844319
vt 0.169874 0.689322
vt 0.306668 0.475883
vt 0.321261 0.688883
vt 0.255350 0.141653
vt 0.321291 0.185217
vt 0.323562 0.466756
vt 0.326439 0.189159
vt 0.320134 0.000263
vt 0.367559 0.000087
vt 0.493250 0.689322
vt 0.493250 0.754831
vt 0.383346 0.206474
vt 0.389253 0.208272
vt 0.350625 0.460717
vt 0.371562 0.688696
vt 0.380200 0.454116
vt 0.114908 0.899599
vt 0.110220 0.832906
vt 0.120752 0.897599
vt 0.391714 0.690986
vt 0.362403 0.918008
vt 0.341454 0.688883
vt 0.391714 0.925731
vt 0.205773 0.888503
vt 0.241672 0.825226
vt 0.258333 0.888503
vt 0.222434 0.825226
vt 0.196154 0.622909
vt 0.525690 0.623188
vt 0.107697 0.757308
vt 0.174974 0.830908
vt 0.258332 0.761949
vt 0.461064 0.773742
vt 0.205773 0.815437
vt 0.196154 0.798482
vt 0.196154 0.778904
vt 0.222434 0.752160
vt 0.205773 0.761949
vt 0.177048 0.878327
vt 0.335581 0.910942
vt 0.982592 0.366176
vt 0.949058 0.000000
vt 0.982592 0.000124
vt 0.949058 0.366052
vt 0.861526 0.366502
vt 0.829340 0.733004
vt 0.829340 0.367170
vt 0.861526 0.732336
vt 0.760297 0.000668
vt 0.728112 0.365834
vt 0.728112 0.000000
vt 0.760297 0.366502
vt 0.829648 0.365834
vt 0.797463 0.000668
vt 0.829648 0.000000
vt 0.797463 0.366502
vt 0.798698 0.366524
vt 0.761646 0.732553
vt 0.761646 0.366502
vt 0.798699 0.732576
vt 0.829340 0.366688
vt 0.829340 0.732739
vt 0.982592 0.733004
vt 0.950406 0.366502
vt 0.982592 0.367170
vt 0.950406 0.732336
vt 0.898691 0.366502
vt 0.898691 0.732336
vt 0.728112 0.366626
vt 0.728112 0.732678
vt 0.649940 0.784405
vt 0.668522 0.854981
vt 0.649940 0.822226
vt 0.668523 0.751650
vt 0.700708 0.873892
vt 0.700708 0.732739
vt 0.917273 0.874157
vt 0.880109 0.733004
vt 0.917273 0.733004
vt 0.880109 0.874156
vt 0.847923 0.751914
vt 0.847923 0.855245
vt 0.829340 0.784669
vt 0.829340 0.822491
vt 0.866701 0.000163
vt 0.829648 0.366237
vt 0.829648 0.000186
vt 0.866701 0.366215
vt 0.897343 0.000000
vt 0.897343 0.366052
vn 1.0000 0.0000 0.0000
vn -0.0000 -0.5878 -0.8090
vn 0.0000 -0.8660 -0.5000
vn 0.0000 -0.9945 -0.1045
vn -0.0000 -0.9511 0.3090
vn -0.0000 -0.7431 0.6691
vn -0.0000 -0.7432 0.6691
vn 0.0001 -0.7431 0.6691
vn -0.0001 -0.7431 0.6691
vn -1.0000 -0.0000 -0.0000
vn 0.8436 -0.2260 0.4871
vn 0.8436 0.2260 0.4871
vn -0.4956 0.1328 0.8584
vn 0.7060 0.7060 -0.0556
vn 0.2584 0.9644 -0.0556
vn 0.2588 -0.9659 0.0000
vn -0.8436 -0.2260 0.4871
vn 0.1328 -0.4956 0.8584
vn -0.2260 0.8436 0.4871
vn -0.7060 -0.7060 -0.0556
vn 0.9644 -0.2584 -0.0556
vn -0.9644 0.2584 -0.0556
vn 0.2260 0.8436 0.4871
vn -0.2584 0.9644 -0.0556
vn -0.1328 -0.4956 0.8584
vn 0.4956 -0.1328 0.8584
vn -0.2260 -0.8436 0.4871
vn -0.9644 -0.2584 -0.0556
vn 0.9644 0.2584 -0.0556
vn -0.7060 0.7060 -0.0556
vn 0.2588 0.9659 0.0000
vn 0.4956 0.1328 0.8584
vn -0.7071 0.7071 -0.0000
vn 0.9659 0.2588 0.0000
vn 0.0000 0.0000 -1.0000
vn -0.2588 0.9659 0.0000
vn 0.1328 0.4956 0.8584
vn 0.6176 0.6176 0.4871
vn -0.3628 0.3628 0.8584
vn -0.1328 0.4956 0.8584
vn -0.6176 0.6176 0.4871
vn -0.6176 -0.6176 0.4871
vn 0.3628 -0.3628 0.8584
vn -0.8436 0.2260 0.4871
vn 0.7060 -0.7060 -0.0556
vn 0.2260 -0.8436 0.4871
vn 0.9659 -0.2588 0.0000
vn 0.7071 0.7071 0.0000
vn 0.3628 0.3628 0.8584
vn 0.2584 -0.9644 -0.0556
vn -0.2584 -0.9644 -0.0556
vn -0.3628 -0.3628 0.8584
vn -0.4956 -0.1328 0.8584
vn -0.9659 0.2588 -0.0000
vn -0.9659 -0.2588 -0.0000
vn 0.7071 -0.7071 -0.0000
vn 0.6176 -0.6176 0.4871
vn -0.2588 -0.9659 -0.0000
vn 0.0000 0.0000 1.0000
vn -0.7071 -0.7071 0.0000
usemtl None
s off
f 1/1/1 2/2/1 3/3/1
f 4/4/1 3/3/1 5/5/1
f 2/2/1 1/1/1 6/6/1
f 3/3/1 4/4/1 1/1/1
f 7/7/2 8/8/2 9/9/2
f 10/10/2 8/11/2 7/12/2
f 11/13/2 8/11/2 10/10/2
f 11/13/2 6/14/2 8/11/2
f 12/15/2 6/14/2 11/13/2
f 13/16/2 6/14/2 12/15/2
f 6/14/2 13/16/2 2/17/2
f 1/18/3 8/19/3 6/20/3
f 8/19/3 1/18/3 14/21/3
f 4/22/4 14/21/4 1/18/4
f 14/21/4 4/22/4 15/23/4
f 5/24/5 15/25/5 4/26/5
f 15/25/5 5/24/5 16/27/5
f 5/28/6 17/29/6 16/30/6
f 5/28/7 18/31/7 17/29/7
f 5/28/6 19/32/6 18/31/6
f 19/32/8 5/28/8 3/33/8
f 20/34/7 16/30/7 17/29/7
f 21/35/6 16/30/6 20/34/6
f 16/36/9 21/37/9 22/38/9
f 14/39/10 9/40/10 8/41/10
f 9/40/10 14/39/10 22/42/10
f 15/43/10 22/42/10 14/39/10
f 22/42/10 15/43/10 16/44/10
f 23/45/11 24/46/11 25/47/11
f 26/48/12 24/49/12 27/50/12
f 28/51/13 29/52/13 30/53/13
f 31/54/14 32/55/14 33/56/14
f 32/55/14 31/54/14 34/57/14
f 35/58/15 33/59/15 32/60/15
f 27/61/11 24/46/11 23/45/11
f 36/62/16 37/63/16 38/64/16
f 37/63/16 36/62/16 39/65/16
f 40/66/17 41/67/17 30/68/17
f 42/69/18 43/70/18 44/71/18
f 45/72/19 46/73/19 47/74/19
f 48/75/20 9/76/20 49/77/20
f 50/78/20 9/76/20 48/75/20
f 9/76/20 50/78/20 7/79/20
f 22/80/20 49/77/20 9/76/20
f 22/80/20 51/81/20 49/77/20
f 51/81/20 22/80/20 21/82/20
f 52/83/21 53/84/21 54/85/21
f 55/86/12 24/49/12 26/48/12
f 56/87/22 57/88/22 58/89/22
f 47/90/23 46/91/23 59/92/23
f 60/93/24 35/94/24 61/95/24
f 42/69/25 44/71/25 62/96/25
f 24/97/26 63/98/26 25/99/26
f 64/100/27 42/101/27 65/102/27
f 48/75/28 57/103/28 56/104/28
f 66/105/15 35/58/15 32/60/15
f 34/57/29 53/106/29 52/107/29
f 60/93/30 58/89/30 67/108/30
f 58/89/30 60/93/30 61/95/30
f 47/90/31 33/59/31 35/58/31
f 33/59/31 47/90/31 59/92/31
f 42/69/25 62/96/25 65/109/25
f 55/110/32 68/111/32 24/97/32
f 46/91/23 69/112/23 59/92/23
f 61/95/24 35/94/24 66/113/24
f 67/108/33 45/72/33 60/93/33
f 45/72/33 67/108/33 70/114/33
f 27/50/34 31/54/34 26/48/34
f 31/54/34 27/50/34 53/106/34
f 31/54/29 53/106/29 34/57/29
f 71/115/35 56/116/35 58/117/35
f 56/116/35 71/115/35 48/118/35
f 58/117/35 72/119/35 71/115/35
f 61/120/35 72/119/35 58/117/35
f 61/120/35 73/121/35 72/119/35
f 66/122/35 73/121/35 61/120/35
f 66/122/35 74/123/35 73/121/35
f 66/122/35 75/124/35 74/123/35
f 32/125/35 75/124/35 66/122/35
f 32/126/35 76/127/35 75/128/35
f 34/129/35 76/127/35 32/126/35
f 76/127/35 34/129/35 77/130/35
f 78/131/35 48/118/35 71/115/35
f 78/131/35 50/132/35 48/118/35
f 79/133/35 50/132/35 78/131/35
f 80/134/35 50/135/35 79/136/35
f 80/134/35 81/137/35 50/135/35
f 82/138/35 81/137/35 80/134/35
f 82/138/35 83/139/35 81/137/35
f 84/140/35 83/139/35 82/138/35
f 54/141/35 84/140/35 77/130/35
f 52/142/35 77/130/35 34/129/35
f 84/140/35 54/141/35 83/139/35
f 77/130/35 52/142/35 54/141/35
f 45/72/36 35/94/36 60/93/36
f 35/94/36 45/72/36 47/74/36
f 46/143/37 85/144/37 69/145/37
f 69/146/38 26/48/38 59/147/38
f 26/48/38 69/146/38 55/86/38
f 29/52/39 86/148/39 87/149/39
f 86/148/39 29/52/39 88/150/39
f 86/148/40 88/150/40 46/143/40
f 86/151/19 46/73/19 45/72/19
f 70/114/41 86/151/41 45/72/41
f 86/151/41 70/114/41 87/152/41
f 40/66/42 65/153/42 41/67/42
f 65/153/42 40/66/42 64/154/42
f 89/155/43 63/98/43 43/70/43
f 63/98/43 89/155/43 25/99/43
f 30/53/13 29/52/13 87/149/13
f 30/156/44 87/152/44 70/114/44
f 54/85/45 2/157/45 83/158/45
f 90/159/45 2/157/45 54/85/45
f 2/157/45 90/159/45 3/160/45
f 83/158/45 2/157/45 13/161/45
f 3/160/45 38/64/45 19/162/45
f 38/64/45 3/160/45 90/159/45
f 36/62/46 89/163/46 42/164/46
f 54/85/21 53/84/21 90/159/21
f 23/45/47 53/84/47 27/61/47
f 53/84/47 23/45/47 90/159/47
f 26/48/48 33/56/48 59/147/48
f 33/56/48 26/48/48 31/54/48
f 68/111/49 69/165/49 85/166/49
f 69/165/49 68/111/49 55/110/49
f 18/167/50 37/63/50 17/168/50
f 12/169/50 81/170/50 83/158/50
f 81/170/50 12/169/50 11/171/50
f 17/172/51 37/173/51 20/174/51
f 81/175/51 10/176/51 50/177/51
f 10/176/51 81/175/51 11/178/51
f 65/179/52 91/180/52 41/181/52
f 91/180/52 65/179/52 62/182/52
f 30/53/53 91/180/53 28/51/53
f 92/183/44 30/156/44 70/114/44
f 37/63/50 19/162/50 38/64/50
f 19/162/50 37/63/50 18/167/50
f 13/161/50 12/169/50 83/158/50
f 89/155/18 43/70/18 42/69/18
f 41/181/53 91/180/53 30/53/53
f 57/88/54 70/114/54 67/108/54
f 70/114/54 57/88/54 92/183/54
f 57/88/22 67/108/22 58/89/22
f 49/77/55 92/184/55 57/103/55
f 92/184/55 49/77/55 40/66/55
f 40/66/17 30/68/17 92/184/17
f 36/62/56 90/159/56 23/45/56
f 90/159/56 36/62/56 38/64/56
f 89/163/57 23/45/57 25/47/57
f 23/45/57 89/163/57 36/62/57
f 39/185/58 51/186/58 37/173/58
f 51/186/58 39/185/58 64/100/58
f 93/187/37 85/144/37 46/143/37
f 68/111/32 94/188/32 24/97/32
f 88/150/40 93/187/40 46/143/40
f 48/75/28 49/77/28 57/103/28
f 36/62/46 42/164/46 39/65/46
f 39/185/27 42/101/27 64/100/27
f 91/180/59 29/52/59 28/51/59
f 62/182/59 29/52/59 91/180/59
f 62/182/59 88/150/59 29/52/59
f 44/189/59 88/150/59 62/182/59
f 44/189/59 93/187/59 88/150/59
f 43/190/59 93/187/59 44/189/59
f 43/190/59 85/144/59 93/187/59
f 63/191/59 85/144/59 43/190/59
f 63/191/59 68/192/59 85/144/59
f 68/192/59 63/191/59 94/193/59
f 24/97/26 94/188/26 63/98/26
f 51/81/60 40/66/60 49/77/60
f 40/66/60 51/81/60 64/154/60
f 37/173/51 21/194/51 20/174/51
f 21/194/51 37/173/51 51/186/51
f 50/177/51 10/176/51 7/195/51
f 95/196/58 74/197/58 75/198/58
f 74/197/58 95/196/58 96/199/58
f 97/200/34 71/201/34 98/202/34
f 71/201/34 97/200/34 78/203/34
f 84/204/54 99/205/54 77/206/54
f 99/205/54 84/204/54 100/207/54
f 101/208/36 82/209/36 80/210/36
f 82/209/36 101/208/36 102/211/36
f 103/212/56 73/213/56 104/214/56
f 73/213/56 103/212/56 72/215/56
f 98/216/47 72/215/47 103/212/47
f 72/215/47 98/216/47 71/217/47
f 105/218/31 80/219/31 79/220/31
f 80/219/31 105/218/31 101/221/31
f 105/222/48 78/203/48 97/200/48
f 78/203/48 105/222/48 79/223/48
f 96/224/16 73/213/16 74/225/16
f 73/213/16 96/224/16 104/214/16
f 82/209/33 100/207/33 84/204/33
f 100/207/33 82/209/33 102/211/33
f 103/226/35 97/227/35 98/228/35
f 104/229/35 97/227/35 103/226/35
f 104/229/35 105/230/35 97/227/35
f 96/231/35 105/230/35 104/229/35
f 96/232/35 101/233/35 105/234/35
f 95/235/35 101/233/35 96/232/35
f 95/235/35 102/236/35 101/233/35
f 106/237/35 102/236/35 95/235/35
f 106/237/35 100/238/35 102/236/35
f 100/238/35 106/237/35 99/239/35
f 76/240/60 95/241/60 75/242/60
f 95/241/60 76/240/60 106/243/60
f 77/244/55 106/243/55 76/240/55
f 106/243/55 77/244/55 99/245/55

View File

@@ -0,0 +1,162 @@
# Blender v2.82 (sub 7) OBJ File: 'shell.blend'
# www.blender.org
mtllib shell.mtl
o Sell
v 1.188815 0.386266 -2.500000
v 1.188815 -0.386266 -0.000000
v 1.188815 -0.386266 -2.500000
v -1.188815 -0.386266 0.000000
v -1.188815 0.386266 -2.500000
v -1.188815 -0.386266 -2.500000
v 1.188815 0.386266 -0.000000
v 0.951055 -0.309014 0.499997
v 0.734730 -1.011265 -0.000000
v -0.734730 -1.011265 -2.500000
v -0.734730 -1.011265 0.000000
v -0.951055 0.309014 0.499997
v -1.188815 0.386266 0.000000
v 0.237761 -0.077252 2.000000
v 0.440836 -0.606760 1.000000
v 0.713290 -0.231762 1.000000
v 0.734730 1.011265 -2.500000
v 0.146942 0.202250 2.000000
v 0.146942 -0.202250 2.000000
v 0.951055 0.309014 0.499997
v -0.000000 -1.250000 -2.500000
v 0.000000 -1.250000 0.000000
v -0.587785 -0.809015 0.499997
v -0.734730 1.011265 0.000000
v -0.587785 0.809015 0.499997
v 0.000000 1.250000 0.000000
v 0.734730 -1.011265 -2.500000
v 0.734730 1.011265 -0.000000
v -0.000000 1.250000 -2.500000
v -0.146942 -0.202250 2.000000
v -0.237760 -0.077252 2.000000
v -0.951055 -0.309014 0.499997
v -0.734730 1.011265 -2.500000
v -0.237760 0.077252 2.000000
v 0.000000 -0.249996 2.000000
v -0.440836 -0.606760 1.000000
v 0.587785 -0.809015 0.499997
v 0.713290 0.231762 1.000000
v 0.237761 0.077252 2.000000
v 0.587785 0.809015 0.499997
v 0.440836 0.606760 1.000000
v -0.713290 0.231762 1.000000
v -0.440836 0.606760 1.000000
v -0.713290 -0.231762 1.000000
v 0.000000 0.249996 2.000000
v -0.146942 0.202250 2.000000
vn 1.0000 0.0000 0.0000
vn -1.0000 0.0000 0.0000
vn 0.7306 -0.5308 0.4294
vn -0.8090 -0.5878 0.0000
vn -0.9031 0.0000 0.4294
vn 0.8090 0.5878 0.0000
vn 0.0000 0.0000 1.0000
vn 0.9031 0.0000 0.4294
vn 0.0000 0.0000 -1.0000
vn -0.2791 -0.8589 0.4294
vn -0.2791 0.8589 0.4294
vn -0.3090 -0.9511 0.0000
vn 0.7306 0.5308 0.4294
vn 0.3090 0.9511 0.0000
vn -0.8090 0.5878 0.0000
vn -0.3090 0.9511 0.0000
vn 0.3090 -0.9511 0.0000
vn -0.7306 -0.5308 0.4294
vn 0.2791 -0.8589 0.4294
vn 0.8090 -0.5878 0.0000
vn 0.2791 0.8589 0.4294
vn -0.7306 0.5308 0.4294
usemtl None
s off
f 1//1 2//1 3//1
f 4//2 5//2 6//2
f 7//1 2//1 1//1
f 2//3 8//3 9//3
f 4//4 10//4 11//4
f 4//5 12//5 13//5
f 14//3 15//3 16//3
f 1//6 17//6 7//6
f 14//7 18//7 19//7
f 8//8 20//8 16//8
f 10//9 5//9 21//9
f 6//4 10//4 4//4
f 22//10 23//10 11//10
f 24//11 25//11 26//11
f 3//9 5//9 1//9
f 21//9 5//9 27//9
f 11//12 10//12 22//12
f 28//13 20//13 7//13
f 17//14 26//14 28//14
f 7//6 17//6 28//6
f 29//14 26//14 17//14
f 24//15 5//15 13//15
f 29//16 24//16 26//16
f 22//17 27//17 9//17
f 30//7 18//7 31//7
f 11//18 32//18 4//18
f 33//15 5//15 24//15
f 29//9 5//9 33//9
f 31//7 18//7 34//7
f 15//19 19//19 35//19
f 33//16 24//16 29//16
f 27//9 5//9 3//9
f 22//12 10//12 21//12
f 21//17 27//17 22//17
f 13//2 5//2 4//2
f 6//9 5//9 10//9
f 2//20 27//20 3//20
f 9//20 27//20 2//20
f 31//18 36//18 30//18
f 32//5 12//5 4//5
f 17//9 5//9 29//9
f 1//9 5//9 17//9
f 35//7 18//7 30//7
f 16//3 37//3 9//3
f 14//8 38//8 39//8
f 26//21 40//21 28//21
f 41//13 18//13 39//13
f 24//22 42//22 25//22
f 25//11 43//11 26//11
f 31//5 34//5 44//5
f 30//10 36//10 35//10
f 34//22 43//22 42//22
f 44//18 32//18 11//18
f 45//21 18//21 41//21
f 16//8 38//8 14//8
f 9//3 8//3 16//3
f 22//19 15//19 35//19
f 15//3 37//3 16//3
f 16//8 20//8 38//8
f 38//13 20//13 28//13
f 32//5 42//5 12//5
f 13//22 12//22 24//22
f 12//22 42//22 24//22
f 42//22 43//22 25//22
f 46//22 43//22 34//22
f 26//21 45//21 41//21
f 14//3 19//3 15//3
f 35//10 36//10 22//10
f 22//19 37//19 15//19
f 9//19 37//19 22//19
f 44//5 34//5 42//5
f 39//7 18//7 14//7
f 2//8 20//8 8//8
f 7//8 20//8 2//8
f 38//13 41//13 39//13
f 41//21 40//21 26//21
f 44//5 42//5 32//5
f 19//7 18//7 35//7
f 34//7 18//7 46//7
f 46//7 18//7 45//7
f 44//18 36//18 31//18
f 36//10 23//10 22//10
f 38//13 40//13 41//13
f 28//13 40//13 38//13
f 44//18 23//18 36//18
f 11//18 23//18 44//18
f 45//11 43//11 46//11
f 26//11 43//11 45//11

143
models/piston_normal_1.obj Normal file
View File

@@ -0,0 +1,143 @@
# Blender v2.82 (sub 7) OBJ File: ''
# www.blender.org
mtllib piston_normal_1.mtl
o cube
v 0.500000 -0.500000 0.500000
v -0.500000 -0.500000 0.500000
v -0.500000 -0.500000 -0.312500
v 0.500000 -0.500000 -0.312500
v 0.500000 0.500000 0.500000
v 0.500000 0.500000 -0.312500
v -0.500000 0.500000 0.500000
v -0.500000 0.500000 -0.312500
vt 0.666667 0.666667
vt 1.000000 0.666667
vt 1.000000 0.937500
vt 0.666667 0.937500
vt 0.666667 0.666667
vt 1.000000 0.666667
vt 1.000000 0.937500
vt 0.666667 0.937500
vt 0.666667 0.666667
vt 1.000000 0.666667
vt 1.000000 0.937500
vt 0.666667 0.937500
vt 0.666667 0.666667
vt 1.000000 0.666667
vt 1.000000 0.937500
vt 0.666667 0.937500
vt 0.333333 0.333333
vt 0.666667 0.333333
vt 0.666667 0.666667
vt 0.333333 0.666667
vt 0.333333 0.666667
vt 0.666667 1.000000
vt 0.333333 1.000000
vn 0.0000 -1.0000 0.0000
vn 1.0000 -0.0000 0.0000
vn 0.0000 1.0000 0.0000
vn -1.0000 -0.0000 0.0000
vn 0.0000 0.0000 -1.0000
vn 0.0000 -0.0000 1.0000
usemtl m_7
s 1
f 1/1/1 2/2/1 3/3/1 4/4/1
f 5/5/2 1/6/2 4/7/2 6/8/2
f 7/9/3 5/10/3 6/11/3 8/12/3
f 2/13/4 7/14/4 8/15/4 3/16/4
f 8/17/5 6/18/5 4/19/5 3/20/5
f 2/21/6 1/1/6 5/22/6 7/23/6
o cube.000
v 0.500000 -0.500000 -1.312500
v -0.500000 -0.500000 -1.312500
v -0.500000 -0.500000 -1.500000
v 0.500000 -0.500000 -1.500000
v 0.500000 0.500000 -1.312500
v 0.500000 0.500000 -1.500000
v -0.500000 0.500000 -1.312500
v -0.500000 0.500000 -1.500000
vt 0.666667 0.937500
vt 1.000000 0.937500
vt 1.000000 1.000000
vt 0.666667 1.000000
vt 0.666667 0.937500
vt 1.000000 0.937500
vt 1.000000 1.000000
vt 0.666667 1.000000
vt 0.666667 0.937500
vt 1.000000 0.937500
vt 1.000000 1.000000
vt 0.666667 1.000000
vt 0.666667 0.937500
vt 1.000000 0.937500
vt 1.000000 1.000000
vt 0.666667 1.000000
vt 0.333333 0.000000
vt 0.666667 0.000000
vt 0.666667 0.333333
vt 0.333333 0.333333
vt 0.666667 0.333333
vt 1.000000 0.333333
vt 1.000000 0.666667
vt 0.666667 0.666667
vn 0.0000 -1.0000 0.0000
vn 1.0000 0.0000 0.0000
vn 0.0000 1.0000 0.0000
vn -1.0000 0.0000 0.0000
vn 0.0000 0.0000 -1.0000
vn 0.0000 0.0000 1.0000
usemtl m_7
s 1
f 9/24/7 10/25/7 11/26/7 12/27/7
f 13/28/8 9/29/8 12/30/8 14/31/8
f 15/32/9 13/33/9 14/34/9 16/35/9
f 10/36/10 15/37/10 16/38/10 11/39/10
f 16/40/11 14/41/11 12/42/11 11/43/11
f 10/44/12 9/45/12 13/46/12 15/47/12
o cube.001
v 0.125000 -0.125000 0.375000
v -0.125000 -0.125000 0.375000
v -0.125000 -0.125000 -1.375000
v 0.125000 -0.125000 -1.375000
v 0.125000 0.125000 0.375000
v 0.125000 0.125000 -1.375000
v -0.125000 0.125000 0.375000
v -0.125000 0.125000 -1.375000
vt 0.125000 0.354167
vt 0.208333 0.354167
vt 0.208333 0.979167
vt 0.125000 0.979167
vt 0.125000 0.354167
vt 0.208333 0.354167
vt 0.208333 0.979167
vt 0.125000 0.979167
vt 0.125000 0.354167
vt 0.208333 0.354167
vt 0.208333 0.979167
vt 0.125000 0.979167
vt 0.125000 0.354167
vt 0.208333 0.354167
vt 0.208333 0.979167
vt 0.125000 0.979167
vt 0.458333 0.130208
vt 0.541667 0.130208
vt 0.541667 0.213542
vt 0.458333 0.213542
vt 0.791667 0.463542
vt 0.875000 0.463542
vt 0.875000 0.546875
vt 0.791667 0.546875
vn 0.0000 -1.0000 -0.0000
vn 1.0000 0.0000 0.0000
vn 0.0000 1.0000 0.0000
vn -1.0000 0.0000 0.0000
vn 0.0000 0.0000 -1.0000
vn 0.0000 0.0000 1.0000
usemtl m_7
s 1
f 17/48/13 18/49/13 19/50/13 20/51/13
f 21/52/14 17/53/14 20/54/14 22/55/14
f 23/56/15 21/57/15 22/58/15 24/59/15
f 18/60/16 23/61/16 24/62/16 19/63/16
f 24/64/17 22/65/17 20/66/17 19/67/17
f 18/68/18 17/69/18 21/70/18 23/71/18

143
models/piston_normal_2.obj Normal file
View File

@@ -0,0 +1,143 @@
# Blender v2.82 (sub 7) OBJ File: ''
# www.blender.org
mtllib piston_normal_2.mtl
o cube.011
v 0.500000 -0.500000 0.500000
v -0.500000 -0.500000 0.500000
v -0.500000 -0.500000 -0.312500
v 0.500000 -0.500000 -0.312500
v 0.500000 0.500000 0.500000
v 0.500000 0.500000 -0.312500
v -0.500000 0.500000 0.500000
v -0.500000 0.500000 -0.312500
vt 0.666667 0.666667
vt 1.000000 0.666667
vt 1.000000 0.937500
vt 0.666667 0.937500
vt 0.666667 0.666667
vt 1.000000 0.666667
vt 1.000000 0.937500
vt 0.666667 0.937500
vt 0.666667 0.666667
vt 1.000000 0.666667
vt 1.000000 0.937500
vt 0.666667 0.937500
vt 0.666667 0.666667
vt 1.000000 0.666667
vt 1.000000 0.937500
vt 0.666667 0.937500
vt 0.333333 0.333333
vt 0.666667 0.333333
vt 0.666667 0.666667
vt 0.333333 0.666667
vt 0.333333 0.666667
vt 0.666667 1.000000
vt 0.333333 1.000000
vn 0.0000 -1.0000 0.0000
vn 1.0000 -0.0000 0.0000
vn 0.0000 1.0000 0.0000
vn -1.0000 -0.0000 0.0000
vn 0.0000 0.0000 -1.0000
vn 0.0000 -0.0000 1.0000
usemtl m_0.001
s 1
f 1/1/1 2/2/1 3/3/1 4/4/1
f 5/5/2 1/6/2 4/7/2 6/8/2
f 7/9/3 5/10/3 6/11/3 8/12/3
f 2/13/4 7/14/4 8/15/4 3/16/4
f 8/17/5 6/18/5 4/19/5 3/20/5
f 2/21/6 1/1/6 5/22/6 7/23/6
o cube.012
v 0.500000 -0.500000 -2.312500
v -0.500000 -0.500000 -2.312500
v -0.500000 -0.500000 -2.500000
v 0.500000 -0.500000 -2.500000
v 0.500000 0.500000 -2.312500
v 0.500000 0.500000 -2.500000
v -0.500000 0.500000 -2.312500
v -0.500000 0.500000 -2.500000
vt 0.666667 0.937500
vt 1.000000 0.937500
vt 1.000000 1.000000
vt 0.666667 1.000000
vt 0.666667 0.937500
vt 1.000000 0.937500
vt 1.000000 1.000000
vt 0.666667 1.000000
vt 0.666667 0.937500
vt 1.000000 0.937500
vt 1.000000 1.000000
vt 0.666667 1.000000
vt 0.666667 0.937500
vt 1.000000 0.937500
vt 1.000000 1.000000
vt 0.666667 1.000000
vt 0.333333 0.000000
vt 0.666667 0.000000
vt 0.666667 0.333333
vt 0.333333 0.333333
vt 0.666667 0.333333
vt 1.000000 0.333333
vt 1.000000 0.666667
vt 0.666667 0.666667
vn 0.0000 -1.0000 -0.0000
vn 1.0000 0.0000 0.0000
vn 0.0000 1.0000 0.0000
vn -1.0000 0.0000 0.0000
vn 0.0000 0.0000 -1.0000
vn 0.0000 0.0000 1.0000
usemtl m_0.001
s 1
f 9/24/7 10/25/7 11/26/7 12/27/7
f 13/28/8 9/29/8 12/30/8 14/31/8
f 15/32/9 13/33/9 14/34/9 16/35/9
f 10/36/10 15/37/10 16/38/10 11/39/10
f 16/40/11 14/41/11 12/42/11 11/43/11
f 10/44/12 9/45/12 13/46/12 15/47/12
o cube.013
v 0.125000 -0.125000 0.375000
v -0.125000 -0.125000 0.375000
v -0.125000 -0.125000 -2.375000
v 0.125000 -0.125000 -2.375000
v 0.125000 0.125000 0.375000
v 0.125000 0.125000 -2.375000
v -0.125000 0.125000 0.375000
v -0.125000 0.125000 -2.375000
vt 0.125000 0.020833
vt 0.208333 0.020833
vt 0.208333 0.979167
vt 0.125000 0.979167
vt 0.125000 0.020833
vt 0.208333 0.020833
vt 0.208333 0.979167
vt 0.125000 0.979167
vt 0.125000 0.020833
vt 0.208333 0.020833
vt 0.208333 0.979167
vt 0.125000 0.979167
vt 0.125000 0.020833
vt 0.208333 0.020833
vt 0.208333 0.979167
vt 0.125000 0.979167
vt 0.562500 0.229167
vt 0.458333 0.229167
vt 0.458333 0.125000
vt 0.562500 0.125000
vt 0.875000 0.458333
vt 0.791667 0.458333
vt 0.791667 0.541667
vt 0.875000 0.541667
vn 0.0000 -1.0000 -0.0000
vn 1.0000 0.0000 0.0000
vn 0.0000 1.0000 0.0000
vn -1.0000 0.0000 0.0000
vn 0.0000 0.0000 -1.0000
vn 0.0000 0.0000 1.0000
usemtl m_0.001
s 1
f 17/48/13 18/49/13 19/50/13 20/51/13
f 21/52/14 17/53/14 20/54/14 22/55/14
f 23/56/15 21/57/15 22/58/15 24/59/15
f 18/60/16 23/61/16 24/62/16 19/63/16
f 24/64/17 22/65/17 20/66/17 19/67/17
f 18/68/18 17/69/18 21/70/18 23/71/18

143
models/piston_sticky_1.obj Normal file
View File

@@ -0,0 +1,143 @@
# Blender v2.82 (sub 7) OBJ File: ''
# www.blender.org
mtllib piston_sticky_1.mtl
o cube.002
v 0.500000 -0.500000 0.500000
v -0.500000 -0.500000 0.500000
v -0.500000 -0.500000 -0.312500
v 0.500000 -0.500000 -0.312500
v 0.500000 0.500000 0.500000
v 0.500000 0.500000 -0.312500
v -0.500000 0.500000 0.500000
v -0.500000 0.500000 -0.312500
vt 0.666667 0.666667
vt 1.000000 0.666667
vt 1.000000 0.937500
vt 0.666667 0.937500
vt 0.666667 0.666667
vt 1.000000 0.666667
vt 1.000000 0.937500
vt 0.666667 0.937500
vt 0.666667 0.666667
vt 1.000000 0.666667
vt 1.000000 0.937500
vt 0.666667 0.937500
vt 0.666667 0.666667
vt 1.000000 0.666667
vt 1.000000 0.937500
vt 0.666667 0.937500
vt 0.333333 0.333333
vt 0.666667 0.333333
vt 0.666667 0.666667
vt 0.333333 0.666667
vt 0.333333 0.666667
vt 0.666667 1.000000
vt 0.333333 1.000000
vn 0.0000 -1.0000 0.0000
vn 1.0000 -0.0000 0.0000
vn 0.0000 1.0000 0.0000
vn -1.0000 -0.0000 0.0000
vn 0.0000 0.0000 -1.0000
vn 0.0000 -0.0000 1.0000
usemtl m_7.001
s 1
f 1/1/1 2/2/1 3/3/1 4/4/1
f 5/5/2 1/6/2 4/7/2 6/8/2
f 7/9/3 5/10/3 6/11/3 8/12/3
f 2/13/4 7/14/4 8/15/4 3/16/4
f 8/17/5 6/18/5 4/19/5 3/20/5
f 2/21/6 1/1/6 5/22/6 7/23/6
o cube.003
v 0.500000 -0.500000 -1.312500
v -0.500000 -0.500000 -1.312500
v -0.500000 -0.500000 -1.500000
v 0.500000 -0.500000 -1.500000
v 0.500000 0.500000 -1.312500
v 0.500000 0.500000 -1.500000
v -0.500000 0.500000 -1.312500
v -0.500000 0.500000 -1.500000
vt 0.666667 0.937500
vt 1.000000 0.937500
vt 1.000000 1.000000
vt 0.666667 1.000000
vt 0.666667 0.937500
vt 1.000000 0.937500
vt 1.000000 1.000000
vt 0.666667 1.000000
vt 0.666667 0.937500
vt 1.000000 0.937500
vt 1.000000 1.000000
vt 0.666667 1.000000
vt 0.666667 0.937500
vt 1.000000 0.937500
vt 1.000000 1.000000
vt 0.666667 1.000000
vt 0.666667 0.000000
vt 1.000000 0.000000
vt 1.000000 0.333333
vt 0.666667 0.333333
vt 0.666667 0.333333
vt 1.000000 0.333333
vt 1.000000 0.666667
vt 0.666667 0.666667
vn 0.0000 -1.0000 0.0000
vn 1.0000 0.0000 0.0000
vn 0.0000 1.0000 0.0000
vn -1.0000 0.0000 0.0000
vn 0.0000 0.0000 -1.0000
vn 0.0000 0.0000 1.0000
usemtl m_7.001
s 1
f 9/24/7 10/25/7 11/26/7 12/27/7
f 13/28/8 9/29/8 12/30/8 14/31/8
f 15/32/9 13/33/9 14/34/9 16/35/9
f 10/36/10 15/37/10 16/38/10 11/39/10
f 16/40/11 14/41/11 12/42/11 11/43/11
f 10/44/12 9/45/12 13/46/12 15/47/12
o cube.004
v 0.125000 -0.125000 0.375000
v -0.125000 -0.125000 0.375000
v -0.125000 -0.125000 -1.375000
v 0.125000 -0.125000 -1.375000
v 0.125000 0.125000 0.375000
v 0.125000 0.125000 -1.375000
v -0.125000 0.125000 0.375000
v -0.125000 0.125000 -1.375000
vt 0.125000 0.354167
vt 0.208333 0.354167
vt 0.208333 0.979167
vt 0.125000 0.979167
vt 0.125000 0.354167
vt 0.208333 0.354167
vt 0.208333 0.979167
vt 0.125000 0.979167
vt 0.125000 0.354167
vt 0.208333 0.354167
vt 0.208333 0.979167
vt 0.125000 0.979167
vt 0.125000 0.354167
vt 0.208333 0.354167
vt 0.208333 0.979167
vt 0.125000 0.979167
vt 0.458333 0.130208
vt 0.541667 0.130208
vt 0.541667 0.213542
vt 0.458333 0.213542
vt 0.791667 0.463542
vt 0.875000 0.463542
vt 0.875000 0.546875
vt 0.791667 0.546875
vn 0.0000 -1.0000 -0.0000
vn 1.0000 0.0000 0.0000
vn 0.0000 1.0000 0.0000
vn -1.0000 0.0000 0.0000
vn 0.0000 0.0000 -1.0000
vn 0.0000 0.0000 1.0000
usemtl m_7.001
s 1
f 17/48/13 18/49/13 19/50/13 20/51/13
f 21/52/14 17/53/14 20/54/14 22/55/14
f 23/56/15 21/57/15 22/58/15 24/59/15
f 18/60/16 23/61/16 24/62/16 19/63/16
f 24/64/17 22/65/17 20/66/17 19/67/17
f 18/68/18 17/69/18 21/70/18 23/71/18

143
models/piston_sticky_2.obj Normal file
View File

@@ -0,0 +1,143 @@
# Blender v2.82 (sub 7) OBJ File: ''
# www.blender.org
mtllib piston_sticky_2.mtl
o cube.008
v 0.500000 -0.500000 0.500000
v -0.500000 -0.500000 0.500000
v -0.500000 -0.500000 -0.312500
v 0.500000 -0.500000 -0.312500
v 0.500000 0.500000 0.500000
v 0.500000 0.500000 -0.312500
v -0.500000 0.500000 0.500000
v -0.500000 0.500000 -0.312500
vt 0.666667 0.666667
vt 1.000000 0.666667
vt 1.000000 0.937500
vt 0.666667 0.937500
vt 0.666667 0.666667
vt 1.000000 0.666667
vt 1.000000 0.937500
vt 0.666667 0.937500
vt 0.666667 0.666667
vt 1.000000 0.666667
vt 1.000000 0.937500
vt 0.666667 0.937500
vt 0.666667 0.666667
vt 1.000000 0.666667
vt 1.000000 0.937500
vt 0.666667 0.937500
vt 0.333333 0.333333
vt 0.666667 0.333333
vt 0.666667 0.666667
vt 0.333333 0.666667
vt 0.333333 0.666667
vt 0.666667 1.000000
vt 0.333333 1.000000
vn 0.0000 -1.0000 0.0000
vn 1.0000 -0.0000 0.0000
vn 0.0000 1.0000 0.0000
vn -1.0000 -0.0000 0.0000
vn 0.0000 0.0000 -1.0000
vn 0.0000 -0.0000 1.0000
usemtl m_0
s 1
f 1/1/1 2/2/1 3/3/1 4/4/1
f 5/5/2 1/6/2 4/7/2 6/8/2
f 7/9/3 5/10/3 6/11/3 8/12/3
f 2/13/4 7/14/4 8/15/4 3/16/4
f 8/17/5 6/18/5 4/19/5 3/20/5
f 2/21/6 1/1/6 5/22/6 7/23/6
o cube.009
v 0.500000 -0.500000 -2.312500
v -0.500000 -0.500000 -2.312500
v -0.500000 -0.500000 -2.500000
v 0.500000 -0.500000 -2.500000
v 0.500000 0.500000 -2.312500
v 0.500000 0.500000 -2.500000
v -0.500000 0.500000 -2.312500
v -0.500000 0.500000 -2.500000
vt 0.666667 0.937500
vt 1.000000 0.937500
vt 1.000000 1.000000
vt 0.666667 1.000000
vt 0.666667 0.937500
vt 1.000000 0.937500
vt 1.000000 1.000000
vt 0.666667 1.000000
vt 0.666667 0.937500
vt 1.000000 0.937500
vt 1.000000 1.000000
vt 0.666667 1.000000
vt 0.666667 0.937500
vt 1.000000 0.937500
vt 1.000000 1.000000
vt 0.666667 1.000000
vt 0.666667 0.000000
vt 1.000000 0.000000
vt 1.000000 0.333333
vt 0.666667 0.333333
vt 0.666667 0.333333
vt 1.000000 0.333333
vt 1.000000 0.666667
vt 0.666667 0.666667
vn 0.0000 -1.0000 -0.0000
vn 1.0000 0.0000 0.0000
vn 0.0000 1.0000 0.0000
vn -1.0000 0.0000 0.0000
vn 0.0000 0.0000 -1.0000
vn 0.0000 0.0000 1.0000
usemtl m_0
s 1
f 9/24/7 10/25/7 11/26/7 12/27/7
f 13/28/8 9/29/8 12/30/8 14/31/8
f 15/32/9 13/33/9 14/34/9 16/35/9
f 10/36/10 15/37/10 16/38/10 11/39/10
f 16/40/11 14/41/11 12/42/11 11/43/11
f 10/44/12 9/45/12 13/46/12 15/47/12
o cube.010
v 0.125000 -0.125000 0.375000
v -0.125000 -0.125000 0.375000
v -0.125000 -0.125000 -2.375000
v 0.125000 -0.125000 -2.375000
v 0.125000 0.125000 0.375000
v 0.125000 0.125000 -2.375000
v -0.125000 0.125000 0.375000
v -0.125000 0.125000 -2.375000
vt 0.125000 0.020833
vt 0.208333 0.020833
vt 0.208333 0.979167
vt 0.125000 0.979167
vt 0.125000 0.020833
vt 0.208333 0.020833
vt 0.208333 0.979167
vt 0.125000 0.979167
vt 0.125000 0.020833
vt 0.208333 0.020833
vt 0.208333 0.979167
vt 0.125000 0.979167
vt 0.125000 0.020833
vt 0.208333 0.020833
vt 0.208333 0.979167
vt 0.125000 0.979167
vt 0.562500 0.229167
vt 0.458333 0.229167
vt 0.458333 0.125000
vt 0.562500 0.125000
vt 0.875000 0.458333
vt 0.791667 0.458333
vt 0.791667 0.541667
vt 0.875000 0.541667
vn 0.0000 -1.0000 -0.0000
vn 1.0000 0.0000 0.0000
vn 0.0000 1.0000 0.0000
vn -1.0000 0.0000 0.0000
vn 0.0000 0.0000 -1.0000
vn 0.0000 0.0000 1.0000
usemtl m_0
s 1
f 17/48/13 18/49/13 19/50/13 20/51/13
f 21/52/14 17/53/14 20/54/14 22/55/14
f 23/56/15 21/57/15 22/58/15 24/59/15
f 18/60/16 23/61/16 24/62/16 19/63/16
f 24/64/17 22/65/17 20/66/17 19/67/17
f 18/68/18 17/69/18 21/70/18 23/71/18

View File

@@ -3,7 +3,7 @@ local S = utils.S
if utils.mesecon_supported and mesecon.mvps_push then
if utils.mesecon_supported then
@@ -21,14 +21,10 @@ local mesecon_rules =
-- use mesecons movestone settings
local timer_interval = 1 / mesecon.setting ("movestone_speed", 3)
local max_push = 3
local max_pull = 3
-- helper functions:
local function get_movefloor_direction (rulename)
if rulename.y > 0 then
return { x = 0, y = 1, z = 0 }
@@ -38,6 +34,7 @@ local function get_movefloor_direction (rulename)
end
local function add_movefloor_list (pos, list)
for i = 1, #list do
if list[i].x == pos.x and
@@ -76,10 +73,289 @@ end
-- copied from mesecons movestone
local function movefloor_move (pos, node, rulename, is_sticky)
local function get_node_height (node)
local height = 0
local def = minetest.registered_nodes[node.name]
if def and type (def.collision_box) == "table" then
if def.collision_box.type and def.collision_box.type == "regular" then
height = 1
else
for _, box in pairs (def.collision_box) do
if type (box) == "table" then
if type (box[5]) == "number" then
height = box[5]
else
for _, b in ipairs (box) do
if type (b[5]) == "number" and b[5] > height then
height = b[5]
end
end
end
end
end
end
end
return height
end
local function get_affected_nodes (floor_list)
local list = { }
local max_height = 0
local protected = false
for _, fpos in ipairs (floor_list) do
for y = 0, max_push, 1 do
local npos = vector.add (fpos, { x = 0, y = y, z = 0 })
local node = utils.get_far_node (npos)
if node and node.name ~= "air" then
local meta = minetest.get_meta (npos)
local timer = minetest.get_node_timer (npos)
local h = get_node_height (node) + npos.y - fpos.y - 0.5
list[#list + 1] =
{
pos = npos,
node = node,
meta = (meta and meta:to_table ()),
timeout = (timer and timer:get_timeout ()) or 0,
elapsed = (timer and timer:get_elapsed ()) or 0
}
if h > max_height then
max_height = h
end
if utils.is_protected (npos, nil) then
protected = true
end
end
end
end
return list, math.ceil (max_height), protected
end
local function get_entity_height (obj, base)
local height = 0
if obj.get_pos then
local pos = obj:get_pos ()
if obj.get_luaentity then
local entity = obj:get_luaentity ()
if entity and entity.name then
local def = minetest.registered_entities[entity.name]
if def and type (def.collisionbox) == "table" and
type (def.collisionbox[5]) == "number" then
height = def.collisionbox[5] + pos.y - base
end
end
end
local props = obj:get_properties ()
if props and props.collisionbox and type (props.collisionbox) == "table" and
type (props.collisionbox[5]) == "number" then
if props.collisionbox[5] > height then
height = props.collisionbox[5] + pos.y - base
end
end
end
return height
end
local function get_affected_entities (floor_list)
local list = { }
local max_height = 0
for _, fpos in pairs (floor_list) do
local min_pos = vector.subtract (fpos, { x = 0.4999, y = 0.4999, z = 0.4999 })
local max_pos = vector.add (fpos, { x = 0.4999, y = max_push + 0.4999, z = 0.4999 })
local objects = minetest.get_objects_in_area (min_pos, max_pos)
for _, obj in ipairs (objects) do
local h = get_entity_height (obj, fpos.y + 0.5)
list[#list + 1] =
{
pos = obj:get_pos (),
obj = obj
}
if h > max_height then
max_height = h
end
end
end
return list, math.ceil (max_height)
end
local function is_obstructed (floor_list, height)
for _, fpos in pairs (floor_list) do
local npos = vector.add (fpos, { x = 0, y = height, z = 0 })
if utils.is_protected (npos, nil) then
return true
end
local node = utils.get_far_node (npos)
if node and node.name ~= "air" then
local def = minetest.registered_nodes[node.name]
if not def or not def.buildable_to then
return true
end
end
end
return false
end
local function move_entities (list, move, players)
for _, entry in ipairs (list) do
if entry.obj then
if players or not entry.obj:is_player () then
local pos = nil
if entry.obj:is_player () then
pos = vector.add (entry.pos, { x = move.x, y = move.y + 0.1, z = move.z })
else
pos = vector.add (entry.pos, move)
end
if entry.obj.move_to then
entry.obj:move_to (pos)
elseif entry.set_pos then
entry.obj:set_pos (pos)
end
end
end
end
end
local function update_player_position (list)
for _, entry in ipairs (list) do
local player = minetest.get_player_by_name (entry.name)
if player then
local pos = player:get_pos ()
if pos.y < entry.pos.y then
pos.y = entry.pos.y + 0.1
player:set_pos (pos)
end
end
end
end
local function queue_player_update (list, move)
local players = { }
for _, entry in ipairs (list) do
if entry.obj and entry.obj:is_player () then
players[#players + 1] =
{
pos = vector.add (entry.pos, move),
name = entry.obj:get_player_name ()
}
end
end
if #players > 0 then
minetest.after(0.1, update_player_position, players)
end
end
local function move_nodes (list, move)
if move.y > 0 then
for i = #list, 1, -1 do
local pos = vector.add (list[i].pos, move)
minetest.remove_node (list[i].pos)
minetest.set_node (pos, list[i].node)
if list[i].meta then
local meta = minetest.get_meta (pos)
if meta then
meta:from_table (list[i].meta)
end
end
if list[i].timeout > 0 then
timer = minetest.get_node_timer (pos)
if timer then
timer:set (list[i].timeout, list[i].elapsed)
end
end
end
else
for i = 1, #list, 1 do
local pos = vector.add (list[i].pos, move)
minetest.remove_node (list[i].pos)
minetest.set_node (pos, list[i].node)
if list[i].meta then
local meta = minetest.get_meta (pos)
if meta then
meta:from_table (list[i].meta)
end
end
if list[i].timeout > 0 then
timer = minetest.get_node_timer (pos)
if timer then
timer:set (list[i].timeout, list[i].elapsed)
end
end
end
end
end
local function check_for_falling (list)
for _, pos in ipairs (list) do
minetest.check_for_falling (vector.add (pos, { x = 0, y = max_push + 1, z = 0 }))
end
end
local function movefloor_move (pos, node, rulename)
local direction = get_movefloor_direction (rulename)
local play_sound = false
local list =
{
@@ -88,68 +364,34 @@ local function movefloor_move (pos, node, rulename, is_sticky)
find_adjoining_movefloor (pos, list)
for i = 1, #list do
local frontpos = vector.add (list[i], direction)
local meta = minetest.get_meta (list[i])
local owner = meta:get_string ("owner")
local continue = true
local nodes, height, protected = get_affected_nodes (list)
-- ### Step 1: Push nodes in front ###
local success, stack, oldstack = mesecon.mvps_push (frontpos, direction, max_push, owner)
if not success then
if stack == "protected" then
meta:set_string ("infotext", "Can't move: protected area on the way")
else
minetest.get_node_timer (list[i]):start (timer_interval)
continue = false
end
end
if continue then
mesecon.mvps_move_objects (frontpos, direction, oldstack)
-- ### Step 2: Move the movestone ###
minetest.set_node (frontpos, node)
local meta2 = minetest.get_meta (frontpos)
meta2:set_string ("owner", owner)
minetest.remove_node (list[i])
mesecon.on_dignode (list[i], node)
mesecon.on_placenode (frontpos, node)
minetest.get_node_timer (frontpos):start (timer_interval)
play_sound = true
-- ### Step 3: If sticky, pull stack behind ###
if is_sticky and direction.y < 0 then
local backpos = vector.subtract (list[i], direction)
success, stack, oldstack = mesecon.mvps_pull_all (backpos, direction, max_pull, owner)
if success then
mesecon.mvps_move_objects (backpos, vector.multiply (direction, -1), oldstack, -1)
end
end
-- ### Step 4: Let things fall ###
minetest.check_for_falling (vector.add (list[i], { x = 0, y = 1, z = 0 }))
end
end
if play_sound then
minetest.sound_play("movestone", { pos = list[i], max_hear_distance = 20, gain = 0.5 }, true)
end
end
local function on_timer (pos, elapsed)
local sourcepos = mesecon.is_powered (pos)
if not sourcepos then
if protected then
return
end
local rulename = vector.subtract (sourcepos[1], pos)
local entities, h = get_affected_entities (list)
mesecon.activate (pos, minetest.get_node (pos), rulename, 0)
if h > height then
height = h
end
if is_obstructed (list, (direction.y > 0 and height + 1) or -1) then
return
end
if direction.y > 0 then
move_entities (entities, direction, true)
move_nodes (nodes, direction)
queue_player_update (entities, direction)
else
move_nodes (nodes, direction)
move_entities (entities, direction, false)
check_for_falling (list)
queue_player_update (entities, direction)
end
minetest.sound_play ("lwmovefloor", { pos = pos, max_hear_distance = 10, gain = 1.0 }, true)
end
@@ -164,8 +406,8 @@ local function mesecon_support ()
action_on = function (pos, node, rulename)
-- do something to turn the effector on
if rulename and not minetest.get_node_timer (pos):is_started () then
movefloor_move (pos, node, rulename, true)
if rulename then
movefloor_move (pos, node, rulename)
end
end
}
@@ -190,8 +432,6 @@ minetest.register_node("lwcomponents:movefloor", {
groups = { cracky = 2 },
sounds = default.node_sound_wood_defaults (),
mesecons = mesecon_support (),
on_timer = on_timer,
})

970
pistons.lua Normal file
View File

@@ -0,0 +1,970 @@
local utils = ...
local S = utils.S
if utils.digilines_supported or utils.mesecon_supported then
local piston_interval = 0.2
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 push_entities (pos, vec)
local tpos = vector.add (pos, vec)
local tnode = utils.get_far_node (tpos)
local can_move = false
if tnode then
if tnode.name == "air" then
can_move = true
else
local tdef = utils.find_item_def (tnode.name)
can_move = tdef and not tdef.walkable
end
end
if can_move then
local object = minetest.get_objects_inside_radius (pos, 1.5)
for j = 1, #object do
if object[j].get_pos then
local opos = object[j]:get_pos ()
if opos.x > (pos.x - 0.5) and opos.x < (pos.x + 0.5) and
opos.z > (pos.z - 0.5) and opos.z < (pos.z + 0.5) and
opos.y > (pos.y - 0.5) and opos.y < (pos.y + 0.5) then
object[j]:set_pos (vector.add (opos, vec))
end
end
end
end
end
local function push_nodes (pos, extent)
local node = utils.get_far_node (pos)
if node then
local vec = direction_vector (node)
local last = vector.add (pos, vector.multiply (vec, extent))
local maxnodes = utils.settings.max_piston_nodes + 1
local count = 0
for i = 1, maxnodes do
local tnode = utils.get_far_node (last)
if not tnode then
return false
end
local tdef = utils.find_item_def (tnode.name)
if tnode.name == "air" or (tdef and not tdef.walkable) then
count = i - 1
break
end
if i == maxnodes then
return false
end
last = vector.add (last, vec)
end
push_entities (last, vec)
for i = 1, count, 1 do
local cpos = vector.subtract (last, vec)
local cnode = utils.get_far_node (cpos)
local cmeta = minetest.get_meta (cpos)
if not cnode or not cmeta then
return false
end
local tmeta = cmeta:to_table ()
local ctimer = minetest.get_node_timer (cpos)
local ctimeout = (ctimer and ctimer:get_timeout ()) or 0
local celapsed = (ctimer and ctimer:get_elapsed ()) or 0
push_entities (cpos, vec)
minetest.remove_node (cpos)
minetest.set_node (last, cnode)
if tmeta then
cmeta = minetest.get_meta (last)
if not cmeta then
return false
end
cmeta:from_table (tmeta)
end
if ctimeout > 0 then
ctimer = minetest.get_node_timer (last)
if ctimer then
ctimer:set (ctimeout, celapsed)
end
end
last = cpos
end
end
return true
end
local function pull_node (pos, extent)
local node = utils.get_far_node (pos)
if node then
local vec = direction_vector (node)
local cpos = vector.add (pos, vector.multiply (vec, extent))
local cnode = utils.get_far_node (cpos)
local cdef = cnode and utils.find_item_def (cnode.name)
if cnode and cnode.name ~= "air" and cdef and cdef.walkable then
local cmeta = minetest.get_meta (cpos)
if cmeta then
local tpos = vector.subtract (cpos, vec)
local tmeta = cmeta:to_table ()
local ctimer = minetest.get_node_timer (cpos)
local ctimeout = (ctimer and ctimer:get_timeout ()) or 0
local celapsed = (ctimer and ctimer:get_elapsed ()) or 0
minetest.remove_node (cpos)
minetest.set_node (tpos, cnode)
if tmeta then
cmeta = minetest.get_meta (tpos)
if cmeta then
cmeta:from_table (tmeta)
end
end
if ctimeout > 0 then
ctimer = minetest.get_node_timer (tpos)
if ctimer then
ctimer:set (ctimeout, celapsed)
end
end
end
end
end
end
local function place_blank (pos, extent)
local node = utils.get_far_node (pos)
if node then
local vec = direction_vector (node)
local blank_pos = vector.add (pos, vector.multiply (vec, extent))
local blank_node = utils.get_far_node (blank_pos)
local blank_def = blank_node and utils.find_item_def (blank_node.name)
if blank_node and blank_node.name == "air" or
(blank_def and not blank_def.walkable) then
minetest.set_node (blank_pos,
{
name = "lwcomponents:piston_blank_"..tostring (extent),
param2 = node.param2
})
end
end
end
local function remove_blank (pos, extent)
local node = utils.get_far_node (pos)
if node then
local vec = direction_vector (node)
local blank_pos = vector.add (pos, vector.multiply (vec, extent))
local blank_node = utils.get_far_node (blank_pos)
if blank_node and
blank_node.name == "lwcomponents:piston_blank_"..tostring (extent) then
minetest.remove_node (blank_pos)
end
end
end
local function extend_piston (pos, extent)
local node = utils.get_far_node (pos)
local meta = minetest.get_meta (pos)
if node and meta then
extent = math.max (math.min (tonumber (extent or 2), meta:get_int ("max_extent")), 0)
if node.name == "lwcomponents:piston" then
if extent ~= 0 then
if push_nodes (pos, 1) then
node.name = "lwcomponents:piston_1"
minetest.swap_node (pos, node)
place_blank (pos, 1)
minetest.sound_play ("lwpiston_extend",
{
pos = pos,
max_hear_distance = 20,
gain = 0.3
},
true)
if extent == 2 then
meta:set_int ("extent", 2)
minetest.get_node_timer (pos):start (piston_interval)
return true
end
end
end
elseif node.name == "lwcomponents:piston_1" then
if extent == 0 then
remove_blank (pos, 1)
node.name = "lwcomponents:piston"
minetest.swap_node (pos, node)
minetest.sound_play ("lwpiston_retract",
{
pos = pos,
max_hear_distance = 20,
gain = 0.3
},
true)
elseif extent == 2 then
if push_nodes (pos, 2) then
node.name = "lwcomponents:piston_2"
minetest.swap_node (pos, node)
place_blank (pos, 2)
minetest.sound_play ("lwpiston_extend",
{
pos = pos,
max_hear_distance = 20,
gain = 0.3
},
true)
end
end
elseif node.name == "lwcomponents:piston_2" then
if extent ~= 2 then
remove_blank (pos, 2)
node.name = "lwcomponents:piston_1"
minetest.swap_node (pos, node)
minetest.sound_play ("lwpiston_retract",
{
pos = pos,
max_hear_distance = 20,
gain = 0.3
},
true)
if extent == 0 then
meta:set_int ("extent", 0)
minetest.get_node_timer (pos):start (piston_interval)
return true
end
end
elseif node.name == "lwcomponents:piston_sticky" then
if extent ~= 0 then
if push_nodes (pos, 1) then
node.name = "lwcomponents:piston_sticky_1"
minetest.swap_node (pos, node)
place_blank (pos, 1)
minetest.sound_play ("lwpiston_extend",
{
pos = pos,
max_hear_distance = 20,
gain = 0.3
},
true)
if extent == 2 then
meta:set_int ("extent", 2)
minetest.get_node_timer (pos):start (piston_interval)
return true
end
end
end
elseif node.name == "lwcomponents:piston_sticky_1" then
if extent == 0 then
remove_blank (pos, 1)
node.name = "lwcomponents:piston_sticky"
minetest.swap_node (pos, node)
pull_node (pos, 2)
minetest.sound_play ("lwpiston_retract",
{
pos = pos,
max_hear_distance = 20,
gain = 0.3
},
true)
elseif extent == 2 then
if push_nodes (pos, 2) then
node.name = "lwcomponents:piston_sticky_2"
minetest.swap_node (pos, node)
place_blank (pos, 2)
minetest.sound_play ("lwpiston_extend",
{
pos = pos,
max_hear_distance = 20,
gain = 0.3
},
true)
end
end
elseif node.name == "lwcomponents:piston_sticky_2" then
if extent ~= 2 then
remove_blank (pos, 2)
node.name = "lwcomponents:piston_sticky_1"
minetest.swap_node (pos, node)
pull_node (pos, 3)
minetest.sound_play ("lwpiston_retract",
{
pos = pos,
max_hear_distance = 20,
gain = 0.3
},
true)
if extent == 0 then
meta:set_int ("extent", 0)
minetest.get_node_timer (pos):start (piston_interval)
return true
end
end
end
end
return false
end
local function on_destruct_1 (pos)
remove_blank (pos, 1)
end
local function on_destruct_2 (pos)
remove_blank (pos, 2)
remove_blank (pos, 1)
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,3.3]"..
"field[1,1;4,2;channel;Channel;${channel}]"..
"button_exit[4.6,1.15;1.5,1;submit;Set]"..
"checkbox[1,2;single;Single move;false]"
meta:set_string ("formspec", spec)
meta:set_int ("max_extent", 2)
-- 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 meta then
if fields.submit then
meta:set_string ("channel", fields.channel)
end
if fields.single then
if fields.single == "true" then
local spec =
"size[7,3.3]"..
"field[1,1;4,2;channel;Channel;${channel}]"..
"button_exit[4.6,1.15;1.5,1;submit;Set]"..
"checkbox[1,2;single;Single move;true]"
meta:set_int ("max_extent", 1)
meta:set_string ("formspec", spec)
else
local spec =
"size[7,3.3]"..
"field[1,1;4,2;channel;Channel;${channel}]"..
"button_exit[4.6,1.15;1.5,1;submit;Set]"..
"checkbox[1,2;single;Single move;false]"
meta:set_int ("max_extent", 2)
meta:set_string ("formspec", spec)
end
end
end
end
local function on_blast (pos, intensity)
local meta = minetest.get_meta (pos)
if meta then
if intensity >= 1.0 then
minetest.remove_node (pos)
else -- intensity < 1.0
local node = minetest.get_node_or_nil (pos)
if node then
local items = minetest.get_node_drops (node, nil)
if items and #items > 0 then
local stack = ItemStack (items[1])
if stack then
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)
local meta = minetest.get_meta (pos)
if meta then
return extend_piston (pos, meta:get_int ("extent"))
end
return false
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] == "extend" then
extend_piston (pos, m[2])
elseif m[1] == "retract" then
extend_piston (pos, 0)
elseif m[1] == "single" then
local spec =
"size[7,3.3]"..
"field[1,1;4,2;channel;Channel;${channel}]"..
"button_exit[4.6,1.15;1.5,1;submit;Set]"..
"checkbox[1,2;single;Single move;true]"
meta:set_int ("max_extent", 1)
meta:set_string ("formspec", spec)
elseif m[1] == "double" then
local spec =
"size[7,3.3]"..
"field[1,1;4,2;channel;Channel;${channel}]"..
"button_exit[4.6,1.15;1.5,1;submit;Set]"..
"checkbox[1,2;single;Single move;false]"
meta:set_int ("max_extent", 2)
meta:set_string ("formspec", spec)
end
end
end
end
end,
}
}
end
return nil
end
local function mesecon_support ()
if utils.mesecon_supported then
return
{
effector =
{
rules = function (node)
local dir = vector.multiply (minetest.facedir_to_dir (node.param2), -1)
local rules = table.copy (utils.mesecon_default_rules)
for i = #rules, 1, -1 do
if vector.equals (rules[i], dir) then
table.remove (rules, i)
end
end
return rules
end,
action_on = function (pos, node)
-- do something to turn the effector on
extend_piston (pos, 2)
end,
action_off = function (pos, node)
-- do something to turn the effector off
extend_piston (pos, 0)
end,
}
}
end
return nil
end
minetest.register_node("lwcomponents:piston_blank_1", {
description = S("Piston blank"),
drawtype = "airlike",
light_source = 0,
sunlight_propagates = true,
walkable = false,
pointable = false,
diggable = false,
climbable = false,
buildable_to = false,
floodable = false,
is_ground_content = false,
drop = "",
groups = { not_in_creative_inventory = 1 },
paramtype = "light",
-- unaffected by explosions
on_blast = function() end,
})
minetest.register_node("lwcomponents:piston_blank_2", {
description = S("Piston blank"),
drawtype = "airlike",
paramtype = "none",
param1 = 0,
paramtype2 = "facedir",
param2 = 0,
collision_box = {
type = "fixed",
fixed = {
{-0.125, -0.125, -0.4, 0.125, 0.125, 0.4},
{-0.5, -0.5, -0.5, 0.5, 0.5, -0.3125},
},
},
light_source = 0,
sunlight_propagates = true,
walkable = true,
pointable = false,
diggable = false,
climbable = false,
buildable_to = false,
floodable = false,
is_ground_content = false,
drop = "",
groups = { not_in_creative_inventory = 1 },
paramtype = "light",
-- unaffected by explosions
on_blast = function() end,
})
minetest.register_node("lwcomponents:piston", {
description = S("Double Piston"),
tiles = { "lwcomponents_piston_top.png", "lwcomponents_piston_bottom.png",
"lwcomponents_piston_right.png", "lwcomponents_piston_left.png",
"lwcomponents_piston_base.png", "lwcomponents_piston_pusher.png" },
is_ground_content = false,
groups = { cracky = 3 },
sounds = default.node_sound_stone_defaults (),
paramtype = "light",
param1 = 0,
paramtype2 = "facedir",
param2 = 0,
floodable = false,
drop = "lwcomponents:piston",
_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,
on_timer = on_timer
})
minetest.register_node("lwcomponents:piston_1", {
description = S("Double Piston"),
drawtype = "mesh",
mesh = "piston_normal_1.obj",
tiles = { "lwcomponents_piston.png" },
visual_scale = 1.0,
selection_box = {
type = "fixed",
fixed = {
{-0.125, -0.125, -1.4, 0.125, 0.125, 0.4},
{-0.5, -0.5, -1.5, 0.5, 0.5, -1.3125},
{-0.5, -0.5, -0.3125, 0.5, 0.5, 0.5},
},
},
collision_box = {
type = "fixed",
fixed = {
{-0.125, -0.125, -1.4, 0.125, 0.125, 0.4},
{-0.5, -0.5, -1.5, 0.5, 0.5, -1.3125},
{-0.5, -0.5, -0.3125, 0.5, 0.5, 0.5},
},
},
is_ground_content = false,
groups = { cracky = 3 , not_in_creative_inventory = 1 },
sounds = default.node_sound_stone_defaults (),
paramtype = "light",
param1 = 0,
paramtype2 = "facedir",
param2 = 0,
floodable = false,
drop = "lwcomponents:piston",
_digistuff_channelcopier_fieldname = "channel",
mesecons = mesecon_support (),
digiline = digilines_support (),
on_destruct = on_destruct_1,
on_receive_fields = on_receive_fields,
can_dig = can_dig,
after_place_node = after_place_node,
on_blast = on_blast,
on_rightclick = on_rightclick,
on_timer = on_timer
})
minetest.register_node("lwcomponents:piston_2", {
description = S("Double Piston"),
drawtype = "mesh",
mesh = "piston_normal_2.obj",
tiles = { "lwcomponents_piston.png" },
visual_scale = 1.0,
selection_box = {
type = "fixed",
fixed = {
{-0.125, -0.125, -2.4, 0.125, 0.125, 0.4},
{-0.5, -0.5, -2.5, 0.5, 0.5, -2.3125},
{-0.5, -0.5, -0.3125, 0.5, 0.5, 0.5},
},
},
collision_box = {
type = "fixed",
fixed = {
{-0.125, -0.125, -2.4, 0.125, 0.125, 0.4},
{-0.5, -0.5, -2.5, 0.5, 0.5, -2.3125},
{-0.5, -0.5, -0.3125, 0.5, 0.5, 0.5},
},
},
is_ground_content = false,
groups = { cracky = 3 , not_in_creative_inventory = 1 },
sounds = default.node_sound_stone_defaults (),
paramtype = "light",
param1 = 0,
paramtype2 = "facedir",
param2 = 0,
floodable = false,
drop = "lwcomponents:piston",
_digistuff_channelcopier_fieldname = "channel",
mesecons = mesecon_support (),
digiline = digilines_support (),
on_destruct = on_destruct_2,
on_receive_fields = on_receive_fields,
can_dig = can_dig,
after_place_node = after_place_node,
on_blast = on_blast,
on_rightclick = on_rightclick,
on_timer = on_timer
})
minetest.register_node("lwcomponents:piston_sticky", {
description = S("Double Sticky Piston"),
tiles = { "lwcomponents_piston_top.png", "lwcomponents_piston_bottom.png",
"lwcomponents_piston_right.png", "lwcomponents_piston_left.png",
"lwcomponents_piston_base.png", "lwcomponents_piston_pusher_sticky.png" },
is_ground_content = false,
groups = { cracky = 3 },
sounds = default.node_sound_stone_defaults (),
paramtype = "light",
param1 = 0,
paramtype2 = "facedir",
param2 = 0,
floodable = false,
drop = "lwcomponents:piston_sticky",
_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,
on_timer = on_timer
})
minetest.register_node("lwcomponents:piston_sticky_1", {
description = S("Double Sticky Piston"),
drawtype = "mesh",
mesh = "piston_sticky_1.obj",
tiles = { "lwcomponents_piston.png" },
visual_scale = 1.0,
selection_box = {
type = "fixed",
fixed = {
{-0.125, -0.125, -1.4, 0.125, 0.125, 0.4},
{-0.5, -0.5, -1.5, 0.5, 0.5, -1.3125},
{-0.5, -0.5, -0.3125, 0.5, 0.5, 0.5},
},
},
collision_box = {
type = "fixed",
fixed = {
{-0.125, -0.125, -1.4, 0.125, 0.125, 0.4},
{-0.5, -0.5, -1.5, 0.5, 0.5, -1.3125},
{-0.5, -0.5, -0.3125, 0.5, 0.5, 0.5},
},
},
is_ground_content = false,
groups = { cracky = 3 , not_in_creative_inventory = 1 },
sounds = default.node_sound_stone_defaults (),
paramtype = "light",
param1 = 0,
paramtype2 = "facedir",
param2 = 0,
floodable = false,
drop = "lwcomponents:piston_sticky",
_digistuff_channelcopier_fieldname = "channel",
mesecons = mesecon_support (),
digiline = digilines_support (),
on_destruct = on_destruct_1,
on_receive_fields = on_receive_fields,
can_dig = can_dig,
after_place_node = after_place_node,
on_blast = on_blast,
on_rightclick = on_rightclick,
on_timer = on_timer
})
minetest.register_node("lwcomponents:piston_sticky_2", {
description = S("Double Sticky Piston"),
drawtype = "mesh",
mesh = "piston_sticky_2.obj",
tiles = { "lwcomponents_piston.png" },
visual_scale = 1.0,
selection_box = {
type = "fixed",
fixed = {
{-0.125, -0.125, -2.4, 0.125, 0.125, 0.4},
{-0.5, -0.5, -2.5, 0.5, 0.5, -2.3125},
{-0.5, -0.5, -0.3125, 0.5, 0.5, 0.5},
},
},
collision_box = {
type = "fixed",
fixed = {
{-0.125, -0.125, -2.4, 0.125, 0.125, 0.4},
{-0.5, -0.5, -2.5, 0.5, 0.5, -2.3125},
{-0.5, -0.5, -0.3125, 0.5, 0.5, 0.5},
},
},
is_ground_content = false,
groups = { cracky = 3 , not_in_creative_inventory = 1 },
sounds = default.node_sound_stone_defaults (),
paramtype = "light",
param1 = 0,
paramtype2 = "facedir",
param2 = 0,
floodable = false,
drop = "lwcomponents:piston_sticky",
_digistuff_channelcopier_fieldname = "channel",
mesecons = mesecon_support (),
digiline = digilines_support (),
on_destruct = on_destruct_2,
on_receive_fields = on_receive_fields,
can_dig = can_dig,
after_place_node = after_place_node,
on_blast = on_blast,
on_rightclick = on_rightclick,
on_timer = on_timer
})
end -- utils.digilines_supported or utils.mesecon_supported

View File

@@ -95,6 +95,7 @@ minetest.register_node ("lwcomponents:player_button", {
"lwplayer_button_side.png",
"lwplayer_button.png"
},
use_texture_alpha = "clip",
paramtype = "light",
paramtype2 = "facedir",
legacy_wallmounted = true,
@@ -143,6 +144,7 @@ minetest.register_node ("lwcomponents:player_button_off", {
"lwplayer_button_side.png",
"lwplayer_button.png"
},
use_texture_alpha = "clip",
paramtype = "light",
paramtype2 = "facedir",
legacy_wallmounted = true,
@@ -192,6 +194,7 @@ minetest.register_node ("lwcomponents:player_button_on", {
"lwplayer_button_side.png",
"lwplayer_button_on.png"
},
use_texture_alpha = "clip",
paramtype = "light",
paramtype2 = "facedir",
legacy_wallmounted = true,
@@ -223,7 +226,9 @@ minetest.register_node ("lwcomponents:player_button_on", {
},
after_destruct = digistuff.remove_receiver,
-- on_rightclick = player_button_push,
on_rightclick = function (pos, node, clicker, itemstack, pointed_thing)
-- so clicking when depressed doesn't place node
end,
on_timer = player_button_turnoff,
})

View File

@@ -13,7 +13,7 @@ CC BY-SA 3.0
Version
=======
0.1.7
0.1.23
Minetest Version
@@ -28,14 +28,13 @@ default
Optional Dependencies
=====================
lwdrops
mesecons
digilines
unifieddyes
intllib
hopper
mobs
digistuff
pipeworks
Installation
@@ -63,9 +62,19 @@ Various components for mesecons and digilines.
* 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.
* Cannon, shoots an item on command with directional aiming (plus 3 shells).
* Double (optionally single) reach pistons and sticky pistons.
* 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.
* Camera, takes a representative image.
* Storage, indexed storage units.
* Mesecons Through Wire, transmits through 1 to 2 solid blocks.
* Solid color conductor blocks, same as Solid Color Block but also mesecons
and digilines conductor.
To spawn entities from dispensers and cannons include the
lwcomponents_spawners mod.
See the docs folder for details on each item.
@@ -77,16 +86,20 @@ the relevant mod is loaded.
* Panel, full node variant of digistuff:panel.
The mod supports the following settings:
Spawn mobs
Allow dispensers to spawn mobs instead of spawners.
Allow dispensers and cannons to spawn mobs instead of spawners.
Default: true
Alert handler errors
Issue errors when handler's of other mods fail.
Default: true
Maximum piston nodes
Maximum nodes a piston can push.
Default: 15
------------------------------------------------------------------------

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 64 KiB

View File

@@ -9,6 +9,12 @@ utils.settings.spawn_mobs =
utils.settings.alert_handler_errors =
minetest.settings:get_bool ("lwcomponents_alert_handler_errors", true)
utils.settings.max_piston_nodes =
tonumber (minetest.settings:get ("lwcomponents_max_piston_nodes") or 15)
utils.settings.default_stack_max =
tonumber (minetest.settings:get ("default_stack_max")) or 99
--

View File

@@ -1,5 +1,8 @@
# Allow dispensers to spawn mobs instead of spawners.
# Allow dispensers and cannons 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
# Maximum nodes a piston can push.
lwcomponents_max_piston_nodes (Maximum piston nodes) int 15

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
sounds/lwcannon.ogg Normal file

Binary file not shown.

BIN
sounds/lwmovefloor.ogg Normal file

Binary file not shown.

BIN
sounds/lwpiston_extend.ogg Normal file

Binary file not shown.

BIN
sounds/lwpiston_retract.ogg Normal file

Binary file not shown.

1447
storage.lua Normal file

File diff suppressed because it is too large Load Diff

BIN
textures/lwcamera.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 495 B

BIN
textures/lwcamera_lens.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
textures/lwcannon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
textures/lwcannon_face.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

BIN
textures/lwcannon_item.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
textures/lwcannon_shell.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

BIN
textures/lwcannon_top.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 472 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 723 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 873 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 857 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 719 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 698 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 864 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 860 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 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

80
through_wire.lua Normal file
View File

@@ -0,0 +1,80 @@
local utils = ...
local S = utils.S
if utils.mesecon_supported then
local through_wire_get_rules = function (node)
local rules = { {x = -1, y = 0, z = 0},
{x = 2, y = 0, z = 0},
{x = 3, y = 0, z = 0} }
if node.param2 == 2 then
rules = mesecon.rotate_rules_left(rules)
elseif node.param2 == 3 then
rules = mesecon.rotate_rules_right(mesecon.rotate_rules_right(rules))
elseif node.param2 == 0 then
rules = mesecon.rotate_rules_right(rules)
end
return rules
end
mesecon.register_node ("lwcomponents:through_wire", {
description = S("Mesecons Through Wire"),
drawtype = "nodebox",
paramtype = "light",
paramtype2 = "facedir",
is_ground_content = false,
sunlight_propagates = true,
walkable = false,
on_rotate = false,
selection_box = {
type = "fixed",
fixed = { -3/16, -8/16, -8/16, 3/16, 3/16, 8/16 }
},
node_box = {
type = "fixed",
fixed = {
{ -3/16, -3/16, 13/32 , 3/16, 3/16 , 8/16 }, -- the smaller bump
{ -1/32, -1/32, 1/2 , 1/32, 1/32 , 3/2 }, -- the wire through the block
{ -2/32, -1/2 , 0.5002-3/32 , 2/32, 0 , 0.5 }, -- the vertical wire bit
{ -2/32, -1/2 , -16/32+0.001 , 2/32, -14/32, 7/16+0.002 } -- the horizontal wire
}
},
drop = "lwcomponents:through_wire_off",
sounds = default.node_sound_defaults(),
}, {
tiles = { "mesecons_wire_off.png" },
groups = { dig_immediate = 3 },
mesecons = {
conductor = {
state = mesecon.state.off,
rules = through_wire_get_rules,
onstate = "lwcomponents:through_wire_on"
}
}
}, {
tiles = { "mesecons_wire_on.png" },
groups = { dig_immediate = 3, not_in_creative_inventory = 1 },
mesecons = {
conductor = {
state = mesecon.state.on,
rules = through_wire_get_rules,
offstate = "lwcomponents:through_wire_off"
}
}
})
end -- utils.mesecon_supported
--

191
utils.lua
View File

@@ -67,43 +67,6 @@ end
-- check for lwdrops
if minetest.global_exists ("lwdrops") then
utils.lwdrops_supported = true
utils.on_destroy = lwdrops.on_destroy
utils.item_pickup = lwdrops.item_pickup
utils.item_drop = lwdrops.item_drop
else
utils.lwdrops_supported = false
-- dummy
utils.on_destroy = function (itemstack)
end
utils.item_pickup = function (entity, cleanup)
local stack = nil
if entity and entity.name and entity.name == "__builtin:item" and
entity.itemstring and entity.itemstring ~= "" then
stack = ItemStack (entity.itemstring)
if cleanup ~= false then
entity.itemstring = ""
entity.object:remove ()
end
end
return stack
end
utils.item_drop = function (itemstack, dropper, pos)
return minetest.item_drop (itemstack, dropper, pos)
end
end
-- check for unifieddyes
if minetest.global_exists ("unifieddyes") then
utils.unifieddyes_supported = true
@@ -129,15 +92,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
@@ -147,6 +101,68 @@ end
-- check for pipeworks
if minetest.global_exists ("pipeworks") then
utils.pipeworks_supported = true
utils.pipeworks_after_place = pipeworks.after_place
utils.pipeworks_after_dig = pipeworks.after_dig
else
utils.pipeworks_supported = false
utils.pipeworks_after_place = function (pos)
end
utils.pipeworks_after_dig = function (pos)
end
end
function utils.on_destroy (itemstack)
local stack = ItemStack (itemstack)
if stack and stack:get_count () > 0 then
local def = utils.find_item_def (stack:get_name ())
if def and def.on_destroy then
def.on_destroy (stack)
end
end
end
function utils.item_pickup (entity, cleanup)
local stack = nil
if entity and entity.name and entity.name == "__builtin:item" and
entity.itemstring and entity.itemstring ~= "" then
stack = ItemStack (entity.itemstring)
if cleanup ~= false then
entity.itemstring = ""
entity.object:remove ()
end
end
return stack
end
function utils.item_drop (itemstack, dropper, pos)
if itemstack then
local def = utils.find_item_def (itemstack:get_name ())
if def and def.on_drop then
return def.on_drop (itemstack, dropper, pos)
end
end
return minetest.item_drop (itemstack, dropper, pos)
end
function utils.can_interact_with_node (pos, player)
if not player or not player:is_player () then
return false
@@ -209,6 +225,22 @@ end
function utils.is_same_item (item1, item2)
local copy1 = ItemStack (stack1)
local copy2 = ItemStack (stack2)
if copy1 and copy2 then
copy1:set_count (1)
copy2:set_count (1)
return copy1:to_string () == copy2:to_string ()
end
return false
end
function utils.destroy_node (pos)
local node = utils.get_far_node (pos)
@@ -259,17 +291,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
@@ -279,4 +312,62 @@ end
function utils.can_place (pos)
local node = minetest.get_node_or_nil (pos)
if node and node.name ~= "air" then
local def = minetest.registered_nodes[node.name]
if not def or not def.buildable_to then
return false
end
end
return true
end
function utils.is_protected (pos, player)
local name = (player and player:get_player_name ()) or ""
return minetest.is_protected (pos, name)
end
function utils.get_on_rightclick (pos, player)
local node = minetest.get_node_or_nil (pos)
if node then
local def = minetest.registered_nodes[node.name]
if def and def.on_rightclick and
not (player and player:is_player () and
player:get_player_control ().sneak) then
return def.on_rightclick
end
end
return nil
end
function utils.is_creative (player)
if minetest.settings:get_bool ("creative_mode") then
return true
end
if player and player:is_player () then
return minetest.is_creative_enabled (player:get_player_name ()) or
minetest.check_player_privs (player, "creative")
end
return false
end
--