1 -- Function that get the input/output rules of the delayer
2 local delayer_get_output_rules
= function(node
)
3 local rules
= {{x
= -1, y
= 0, z
= 0, spread
=true}}
4 for i
= 0, node
.param2
do
5 rules
= mesecon
.rotate_rules_left(rules
)
10 local delayer_get_input_rules
= function(node
)
11 local rules
= {{x
= 1, y
= 0, z
= 0}}
12 for i
= 0, node
.param2
do
13 rules
= mesecon
.rotate_rules_left(rules
)
18 -- Return the sides of a delayer.
19 -- Those are used to toggle the lock state.
20 local delayer_get_sides
= function(node
)
22 {x
= 0, y
= 0, z
= -1},
23 {x
= 0, y
= 0, z
= 1},
25 for i
= 0, node
.param2
do
26 rules
= mesecon
.rotate_rules_left(rules
)
31 -- Make the repeater at pos try to lock any repeater it faces.
32 -- Returns true if a repeater was locked.
33 local check_lock_repeater
= function(pos
, node
)
34 -- Check the repeater at pos and look if it faces
35 -- a repeater placed sideways.
36 -- If yes, lock the second repeater.
37 local r
= delayer_get_output_rules(node
)[1]
38 local lpos
= vector
.add(pos
, r
)
39 local lnode
= minetest
.get_node(lpos
)
40 local ldef
= minetest
.registered_nodes
[lnode
.name
]
41 local g
= minetest
.get_item_group(lnode
.name
, "redstone_repeater")
42 if g
>= 1 and g
<= 4 then
43 local lrs
= delayer_get_input_rules(lnode
)
45 for _
, lr
in pairs(lrs
) do
46 if lr
.x
== r
.x
or lr
.z
== r
.z
then
52 minetest
.set_node(lpos
, {name
=ldef
.delayer_lockstate
, param2
=lnode
.param2
})
53 local meta
= minetest
.get_meta(lpos
)
54 meta
:set_int("delay", g
)
61 -- Make the repeater at pos try to unlock any repeater it faces.
62 -- Returns true if a repeater was unlocked.
63 local check_unlock_repeater
= function(pos
, node
)
64 -- Check the repeater at pos and look if it faces
65 -- a repeater placed sideways.
66 -- If yes, also check if the second repeater doesn't receive
67 -- a locking signal on the other side. If not, unlock the second repeater.
68 local r
= delayer_get_output_rules(node
)[1]
69 local lpos
= vector
.add(pos
, r
)
70 local lnode
= minetest
.get_node(lpos
)
71 local ldef
= minetest
.registered_nodes
[lnode
.name
]
72 local g
= minetest
.get_item_group(lnode
.name
, "redstone_repeater")
73 -- Are we facing a locked repeater?
75 -- First check the orientation of the faced repeater
76 local lrs
= delayer_get_input_rules(lnode
)
77 for _
, lr
in pairs(lrs
) do
78 if lr
.x
== r
.x
or lr
.z
== r
.z
then
79 -- Invalid orientation. Do nothing
83 -- Now we check if there's a powered repeater on the other side of the
85 -- To get to the other side, we just take another step in the direction which we already face.
86 local other_side
= vector
.add(lpos
, r
)
87 local other_node
= minetest
.get_node(other_side
)
88 if minetest
.get_item_group(other_node
.name
, "redstone_repeater") ~= 0 and mesecon
.is_receptor_on(other_node
.name
) then
89 -- Final check: The other repeater must also face the right way
90 local other_face
= delayer_get_output_rules(other_node
)[1]
91 local other_facing_pos
= vector
.add(other_side
, other_face
)
92 if vector
.equals(other_facing_pos
, lpos
) then
93 -- Powered repeater found AND it's facing the locked repeater. Do NOT unlock!
97 local lmeta
= minetest
.get_meta(lpos
)
98 local ldelay
= lmeta
:get_int("delay")
99 if tonumber(ldelay
) == nil or ldelay
< 1 or ldelay
> 4 then
102 if mesecon
.is_powered(lpos
, delayer_get_input_rules(lnode
)[1]) then
103 minetest
.set_node(lpos
, {name
="mesecons_delayer:delayer_on_"..ldelay
, param2
=lnode
.param2
})
104 mesecon
.queue
:add_action(lpos
, "receptor_on", {delayer_get_output_rules(lnode
)}, ldef
.delayer_time
, nil)
106 minetest
.set_node(lpos
, {name
="mesecons_delayer:delayer_off_"..ldelay
, param2
=lnode
.param2
})
107 mesecon
.queue
:add_action(lpos
, "receptor_off", {delayer_get_output_rules(lnode
)}, ldef
.delayer_time
, nil)
114 -- Functions that are called after the delay time
115 local delayer_activate
= function(pos
, node
)
116 local def
= minetest
.registered_nodes
[node
.name
]
117 local time
= def
.delayer_time
118 minetest
.set_node(pos
, {name
=def
.delayer_onstate
, param2
=node
.param2
})
119 mesecon
.queue
:add_action(pos
, "receptor_on", {delayer_get_output_rules(node
)}, time
, nil)
121 check_lock_repeater(pos
, node
)
124 local delayer_deactivate
= function(pos
, node
)
125 local def
= minetest
.registered_nodes
[node
.name
]
126 local time
= def
.delayer_time
127 minetest
.set_node(pos
, {name
=def
.delayer_offstate
, param2
=node
.param2
})
128 mesecon
.queue
:add_action(pos
, "receptor_off", {delayer_get_output_rules(node
)}, time
, nil)
130 check_unlock_repeater(pos
, node
)
133 -- Register the 2 (states) x 4 (delay times) delayers
138 groups
= {dig_immediate
=3,dig_by_water
=1,destroy_by_lava_flow
=1,dig_by_piston
=1,attached_node
=1,redstone_repeater
=i
}
140 groups
= {dig_immediate
=3,dig_by_water
=1,destroy_by_lava_flow
=1,dig_by_piston
=1,attached_node
=1,redstone_repeater
=i
,not_in_creative_inventory
=1}
144 if i
== 1 then delaytime
= 0.1
145 elseif i
== 2 then delaytime
= 0.2
146 elseif i
== 3 then delaytime
= 0.3
147 elseif i
== 4 then delaytime
= 0.4
153 { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 }, -- the main slab
154 { -1/16, -6/16, 6/16, 1/16, -1/16, 4/16}, -- still torch
155 { -1/16, -6/16, 0/16, 1/16, -1/16, 2/16}, -- moved torch
159 { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 }, -- the main slab
160 { -1/16, -6/16, 6/16, 1/16, -1/16, 4/16}, -- still torch
161 { -1/16, -6/16, -2/16, 1/16, -1/16, 0/16}, -- moved torch
165 { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 }, -- the main slab
166 { -1/16, -6/16, 6/16, 1/16, -1/16, 4/16}, -- still torch
167 { -1/16, -6/16, -4/16, 1/16, -1/16, -2/16}, -- moved torch
171 { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 }, -- the main slab
172 { -1/16, -6/16, 6/16, 1/16, -1/16, 4/16}, -- still torch
173 { -1/16, -6/16, -6/16, 1/16, -1/16, -4/16}, -- moved torch
177 local help
, longdesc
, usagehelp
, icon
, on_construct
180 longdesc
= "Redstone repeaters are versatile redstone components with multiple purposes: 1. They only allow signals to travel in one direction. 2. They delay the signal. 3. Optionally, they can lock their output in one state."
181 usagehelp
= "To power a redstone repeater, send a signal in “arrow” direction (the input). The signal goes out on the opposite side (the output) with a delay. To change the delay, rightclick the redstone repeater. The delay is between 0.1 and 0.4 seconds long and can be changed in steps of 0.1 seconds. It is indicated by the position of the moving redstone torch.".."\n"..
182 "To lock a repeater, send a signal from an adjacent repeater into one of its sides. While locked, the moving redstone torch disappears, the output doesn't change and the input signal is ignored."
183 icon
= "mesecons_delayer_item.png"
185 -- Check sides of constructed repeater and lock it, if required
186 on_construct
= function(pos
)
187 local node
= minetest
.get_node(pos
)
188 local sides
= delayer_get_sides(node
)
190 local spos
= vector
.add(pos
, sides
[s
])
191 local snode
= minetest
.get_node(spos
)
192 -- Is there a powered repeater at one of our sides?
193 local g
= minetest
.get_item_group(snode
.name
, "redstone_repeater")
194 if g
~= 0 and mesecon
.is_receptor_on(snode
.name
) then
195 -- The other repeater must also face towards the constructed node
196 local sface
= delayer_get_output_rules(snode
)[1]
197 local sface_pos
= vector
.add(spos
, sface
)
198 if vector
.equals(sface_pos
, pos
) then
199 -- Repeater is facing towards us! Now we just need to lock the costructed node
200 if mesecon
.is_powered(pos
, delayer_get_input_rules(node
)[1]) ~= false then
201 minetest
.set_node(pos
, {name
="mesecons_delayer:delayer_on_locked", param2
= node
.param2
})
203 minetest
.set_node(pos
, {name
="mesecons_delayer:delayer_off_locked", param2
= node
.param2
})
215 if minetest
.get_modpath("screwdriver") then
216 on_rotate
= screwdriver
.disallow
220 minetest
.register_node("mesecons_delayer:delayer_off_"..tostring(i
), {
221 description
= "Redstone Repeater",
222 inventory_image
= icon
,
224 _doc_items_create_entry
= help
,
225 _doc_items_longdesc
= longdesc
,
226 _doc_items_usagehelp
= usagehelp
,
227 drawtype
= "nodebox",
229 "mesecons_delayer_off.png",
230 "mcl_stairs_stone_slab_top.png",
231 "mesecons_delayer_sides_off.png",
232 "mesecons_delayer_sides_off.png",
233 "mesecons_delayer_ends_off.png",
234 "mesecons_delayer_ends_off.png",
236 wield_image
= "mesecons_delayer_off.png",
240 fixed
= { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 },
244 fixed
= { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 },
252 paramtype2
= "facedir",
253 sunlight_propagates
= false,
254 is_ground_content
= false,
255 drop
= 'mesecons_delayer:delayer_off_1',
256 on_rightclick
= function (pos
, node
)
257 if node
.name
=="mesecons_delayer:delayer_off_1" then
258 minetest
.set_node(pos
, {name
="mesecons_delayer:delayer_off_2", param2
=node
.param2
})
259 elseif node
.name
=="mesecons_delayer:delayer_off_2" then
260 minetest
.set_node(pos
, {name
="mesecons_delayer:delayer_off_3", param2
=node
.param2
})
261 elseif node
.name
=="mesecons_delayer:delayer_off_3" then
262 minetest
.set_node(pos
, {name
="mesecons_delayer:delayer_off_4", param2
=node
.param2
})
263 elseif node
.name
=="mesecons_delayer:delayer_off_4" then
264 minetest
.set_node(pos
, {name
="mesecons_delayer:delayer_off_1", param2
=node
.param2
})
267 on_construct
= on_construct
,
268 delayer_time
= delaytime
,
269 delayer_onstate
= "mesecons_delayer:delayer_on_"..tostring(i
),
270 delayer_lockstate
= "mesecons_delayer:delayer_off_locked",
271 sounds
= mcl_sounds
.node_sound_stone_defaults(),
275 state
= mesecon
.state
.off
,
276 rules
= delayer_get_output_rules
280 rules
= delayer_get_input_rules
,
281 action_on
= delayer_activate
284 on_rotate
= on_rotate
,
288 minetest
.register_node("mesecons_delayer:delayer_on_"..tostring(i
), {
289 description
= "Redstone Repeater (Powered)",
290 _doc_items_create_entry
= false,
291 drawtype
= "nodebox",
293 "mesecons_delayer_on.png",
294 "mcl_stairs_stone_slab_top.png",
295 "mesecons_delayer_sides_on.png",
296 "mesecons_delayer_sides_on.png",
297 "mesecons_delayer_ends_on.png",
298 "mesecons_delayer_ends_on.png",
303 fixed
= { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 },
307 fixed
= { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 },
313 groups
= {dig_immediate
= 3, dig_by_water
=1,destroy_by_lava_flow
=1, dig_by_piston
=1, attached_node
=1, redstone_repeater
=i
, not_in_creative_inventory
= 1},
315 paramtype2
= "facedir",
316 sunlight_propagates
= false,
317 is_ground_content
= false,
318 drop
= 'mesecons_delayer:delayer_off_1',
319 on_rightclick
= function (pos
, node
)
320 if node
.name
=="mesecons_delayer:delayer_on_1" then
321 minetest
.set_node(pos
, {name
="mesecons_delayer:delayer_on_2",param2
=node
.param2
})
322 elseif node
.name
=="mesecons_delayer:delayer_on_2" then
323 minetest
.set_node(pos
, {name
="mesecons_delayer:delayer_on_3",param2
=node
.param2
})
324 elseif node
.name
=="mesecons_delayer:delayer_on_3" then
325 minetest
.set_node(pos
, {name
="mesecons_delayer:delayer_on_4",param2
=node
.param2
})
326 elseif node
.name
=="mesecons_delayer:delayer_on_4" then
327 minetest
.set_node(pos
, {name
="mesecons_delayer:delayer_on_1",param2
=node
.param2
})
330 after_dig_node
= function(pos
, oldnode
)
331 check_unlock_repeater(pos
, oldnode
)
333 delayer_time
= delaytime
,
334 delayer_offstate
= "mesecons_delayer:delayer_off_"..tostring(i
),
335 delayer_lockstate
= "mesecons_delayer:delayer_on_locked",
336 sounds
= mcl_sounds
.node_sound_stone_defaults(),
340 state
= mesecon
.state
.on
,
341 rules
= delayer_get_output_rules
345 rules
= delayer_get_input_rules
,
346 action_off
= delayer_deactivate
349 on_rotate
= on_rotate
,
357 minetest
.register_node("mesecons_delayer:delayer_off_locked", {
358 description
= "Redstone Repeater (Locked)",
359 inventory_image
= icon
,
361 _doc_items_create_entry
= false,
362 drawtype
= "nodebox",
363 -- FIXME: Textures of torch and the lock bar overlap. Nodeboxes are (sadly) not suitable for this.
364 -- So this needs to be turned into a mesh.
366 "mesecons_delayer_locked_off.png",
367 "mcl_stairs_stone_slab_top.png",
368 "mesecons_delayer_sides_locked_off.png",
369 "mesecons_delayer_sides_locked_off.png",
370 "mesecons_delayer_front_locked_off.png",
371 "mesecons_delayer_end_locked_off.png",
373 wield_image
= "mesecons_delayer_locked_off.png",
377 fixed
= { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 },
381 fixed
= { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 },
386 { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 }, -- the main slab
387 { -1/16, -6/16, 6/16, 1/16, -1/16, 4/16}, -- still torch
388 { -6/16, -6/16, -1/16, 6/16, -4/16, 1/16}, -- lock
391 groups
= {dig_immediate
= 3, dig_by_water
=1,destroy_by_lava_flow
=1, dig_by_piston
=1, attached_node
=1, redstone_repeater
=5, not_in_creative_inventory
= 1},
393 paramtype2
= "facedir",
394 sunlight_propagates
= false,
395 is_ground_content
= false,
396 drop
= 'mesecons_delayer:delayer_off_1',
398 sounds
= mcl_sounds
.node_sound_stone_defaults(),
402 state
= mesecon
.state
.off
,
403 rules
= delayer_get_output_rules
407 rules
= delayer_get_input_rules
,
410 on_rotate
= on_rotate
,
413 minetest
.register_node("mesecons_delayer:delayer_on_locked", {
414 description
= "Redstone Repeater (Locked, Powered)",
415 _doc_items_create_entry
= false,
416 drawtype
= "nodebox",
418 "mesecons_delayer_locked_on.png",
419 "mcl_stairs_stone_slab_top.png",
420 "mesecons_delayer_sides_locked_on.png",
421 "mesecons_delayer_sides_locked_on.png",
422 "mesecons_delayer_front_locked_on.png",
423 "mesecons_delayer_end_locked_on.png",
428 fixed
= { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 },
432 fixed
= { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 },
437 { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 }, -- the main slab
438 { -1/16, -6/16, 6/16, 1/16, -1/16, 4/16}, -- still torch
439 { -6/16, -6/16, -1/16, 6/16, -4/16, 1/16}, -- lock
442 after_dig_node
= function(pos
, oldnode
)
443 check_unlock_repeater(pos
, oldnode
)
445 groups
= {dig_immediate
= 3, dig_by_water
=1,destroy_by_lava_flow
=1, dig_by_piston
=1, attached_node
=1, redstone_repeater
=5, not_in_creative_inventory
= 1},
447 paramtype2
= "facedir",
448 sunlight_propagates
= false,
449 is_ground_content
= false,
450 drop
= 'mesecons_delayer:delayer_off_1',
452 sounds
= mcl_sounds
.node_sound_stone_defaults(),
456 state
= mesecon
.state
.on
,
457 rules
= delayer_get_output_rules
461 rules
= delayer_get_input_rules
,
464 on_rotate
= on_rotate
,
467 minetest
.register_craft({
468 output
= "mesecons_delayer:delayer_off_1",
470 {"mesecons_torch:mesecon_torch_on", "mesecons:redstone", "mesecons_torch:mesecon_torch_on"},
471 {"mcl_core:stone","mcl_core:stone", "mcl_core:stone"},
475 -- Add entry aliases for the Help
476 if minetest
.get_modpath("doc") then
477 doc
.add_entry_alias("nodes", "mesecons_delayer:delayer_off_1", "nodes", "mesecons_delayer:delayer_off_2")
478 doc
.add_entry_alias("nodes", "mesecons_delayer:delayer_off_1", "nodes", "mesecons_delayer:delayer_off_3")
479 doc
.add_entry_alias("nodes", "mesecons_delayer:delayer_off_1", "nodes", "mesecons_delayer:delayer_off_4")
480 doc
.add_entry_alias("nodes", "mesecons_delayer:delayer_off_1", "nodes", "mesecons_delayer:delayer_off_locked")
481 doc
.add_entry_alias("nodes", "mesecons_delayer:delayer_off_1", "nodes", "mesecons_delayer:delayer_on_1")
482 doc
.add_entry_alias("nodes", "mesecons_delayer:delayer_off_1", "nodes", "mesecons_delayer:delayer_on_2")
483 doc
.add_entry_alias("nodes", "mesecons_delayer:delayer_off_1", "nodes", "mesecons_delayer:delayer_on_3")
484 doc
.add_entry_alias("nodes", "mesecons_delayer:delayer_off_1", "nodes", "mesecons_delayer:delayer_on_4")
485 doc
.add_entry_alias("nodes", "mesecons_delayer:delayer_off_1", "nodes", "mesecons_delayer:delayer_on_locked")