1 local DELAYS
= { 0.1, 0.2, 0.3, 0.4 }
2 local DEFAULT_DELAY
= DELAYS
[1]
4 -- Function that get the input/output rules of the delayer
5 local delayer_get_output_rules
= function(node
)
6 local rules
= {{x
= -1, y
= 0, z
= 0, spread
=true}}
7 for i
= 0, node
.param2
do
8 rules
= mesecon
.rotate_rules_left(rules
)
13 local delayer_get_input_rules
= function(node
)
14 local rules
= {{x
= 1, y
= 0, z
= 0}}
15 for i
= 0, node
.param2
do
16 rules
= mesecon
.rotate_rules_left(rules
)
21 -- Return the sides of a delayer.
22 -- Those are used to toggle the lock state.
23 local delayer_get_sides
= function(node
)
25 {x
= 0, y
= 0, z
= -1},
26 {x
= 0, y
= 0, z
= 1},
28 for i
= 0, node
.param2
do
29 rules
= mesecon
.rotate_rules_left(rules
)
34 -- Make the repeater at pos try to lock any repeater it faces.
35 -- Returns true if a repeater was locked.
36 local check_lock_repeater
= function(pos
, node
)
37 -- Check the repeater at pos and look if it faces
38 -- a repeater placed sideways.
39 -- If yes, lock the second repeater.
40 local r
= delayer_get_output_rules(node
)[1]
41 local lpos
= vector
.add(pos
, r
)
42 local lnode
= minetest
.get_node(lpos
)
43 local ldef
= minetest
.registered_nodes
[lnode
.name
]
44 local g
= minetest
.get_item_group(lnode
.name
, "redstone_repeater")
45 if g
>= 1 and g
<= 4 then
46 local lrs
= delayer_get_input_rules(lnode
)
48 for _
, lr
in pairs(lrs
) do
49 if lr
.x
== r
.x
or lr
.z
== r
.z
then
55 minetest
.set_node(lpos
, {name
=ldef
.delayer_lockstate
, param2
=lnode
.param2
})
56 local meta
= minetest
.get_meta(lpos
)
57 -- Metadata: delay. Used to remember the delay for locked repeaters.
58 -- The number is the torch position (1-4).
59 meta
:set_int("delay", g
)
66 -- Make the repeater at pos try to unlock any repeater it faces.
67 -- Returns true if a repeater was unlocked.
68 local check_unlock_repeater
= function(pos
, node
)
69 -- Check the repeater at pos and look if it faces
70 -- a repeater placed sideways.
71 -- If yes, also check if the second repeater doesn't receive
72 -- a locking signal on the other side. If not, unlock the second repeater.
73 local r
= delayer_get_output_rules(node
)[1]
74 local lpos
= vector
.add(pos
, r
)
75 local lnode
= minetest
.get_node(lpos
)
76 local ldef
= minetest
.registered_nodes
[lnode
.name
]
77 local g
= minetest
.get_item_group(lnode
.name
, "redstone_repeater")
78 -- Are we facing a locked repeater?
80 -- First check the orientation of the faced repeater
81 local lrs
= delayer_get_input_rules(lnode
)
82 for _
, lr
in pairs(lrs
) do
83 if lr
.x
== r
.x
or lr
.z
== r
.z
then
84 -- Invalid orientation. Do nothing
88 -- Now we check if there's a powered repeater on the other side of the
90 -- To get to the other side, we just take another step in the direction which we already face.
91 local other_side
= vector
.add(lpos
, r
)
92 local other_node
= minetest
.get_node(other_side
)
93 if minetest
.get_item_group(other_node
.name
, "redstone_repeater") ~= 0 and mesecon
.is_receptor_on(other_node
.name
) then
94 -- Final check: The other repeater must also face the right way
95 local other_face
= delayer_get_output_rules(other_node
)[1]
96 local other_facing_pos
= vector
.add(other_side
, other_face
)
97 if vector
.equals(other_facing_pos
, lpos
) then
98 -- Powered repeater found AND it's facing the locked repeater. Do NOT unlock!
102 local lmeta
= minetest
.get_meta(lpos
)
103 local ldelay
= lmeta
:get_int("delay")
104 if tonumber(ldelay
) == nil or ldelay
< 1 or ldelay
> 4 then
107 if mesecon
.is_powered(lpos
, delayer_get_input_rules(lnode
)[1]) then
108 minetest
.set_node(lpos
, {name
="mesecons_delayer:delayer_on_"..ldelay
, param2
=lnode
.param2
})
109 mesecon
.queue
:add_action(lpos
, "receptor_on", {delayer_get_output_rules(lnode
)}, ldef
.delayer_time
, nil)
111 minetest
.set_node(lpos
, {name
="mesecons_delayer:delayer_off_"..ldelay
, param2
=lnode
.param2
})
112 mesecon
.queue
:add_action(lpos
, "receptor_off", {delayer_get_output_rules(lnode
)}, ldef
.delayer_time
, nil)
119 -- Functions that are called after the delay time
120 local delayer_activate
= function(pos
, node
)
121 local def
= minetest
.registered_nodes
[node
.name
]
122 local time
= def
.delayer_time
123 minetest
.set_node(pos
, {name
=def
.delayer_onstate
, param2
=node
.param2
})
124 mesecon
.queue
:add_action(pos
, "receptor_on", {delayer_get_output_rules(node
)}, time
, nil)
126 check_lock_repeater(pos
, node
)
129 local delayer_deactivate
= function(pos
, node
)
130 local def
= minetest
.registered_nodes
[node
.name
]
131 local time
= def
.delayer_time
132 minetest
.set_node(pos
, {name
=def
.delayer_offstate
, param2
=node
.param2
})
133 mesecon
.queue
:add_action(pos
, "receptor_off", {delayer_get_output_rules(node
)}, time
, nil)
135 check_unlock_repeater(pos
, node
)
139 if minetest
.get_modpath("screwdriver") then
140 on_rotate
= screwdriver
.disallow
143 -- Register the 2 (states) x 4 (delay times) delayers
148 groups
= {dig_immediate
=3,dig_by_water
=1,destroy_by_lava_flow
=1,dig_by_piston
=1,attached_node
=1,redstone_repeater
=i
}
150 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}
153 local delaytime
= DELAYS
[i
]
158 { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 }, -- the main slab
159 { -1/16, -6/16, 6/16, 1/16, -1/16, 4/16}, -- still torch
160 { -1/16, -6/16, 0/16, 1/16, -1/16, 2/16}, -- moved torch
164 { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 }, -- the main slab
165 { -1/16, -6/16, 6/16, 1/16, -1/16, 4/16}, -- still torch
166 { -1/16, -6/16, -2/16, 1/16, -1/16, 0/16}, -- moved torch
170 { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 }, -- the main slab
171 { -1/16, -6/16, 6/16, 1/16, -1/16, 4/16}, -- still torch
172 { -1/16, -6/16, -4/16, 1/16, -1/16, -2/16}, -- moved torch
176 { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 }, -- the main slab
177 { -1/16, -6/16, 6/16, 1/16, -1/16, 4/16}, -- still torch
178 { -1/16, -6/16, -6/16, 1/16, -1/16, -4/16}, -- moved torch
182 local help
, longdesc
, usagehelp
, icon
, on_construct
185 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."
186 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"..
187 "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."
188 icon
= "mesecons_delayer_item.png"
190 -- Check sides of constructed repeater and lock it, if required
191 on_construct
= function(pos
)
192 local node
= minetest
.get_node(pos
)
193 local sides
= delayer_get_sides(node
)
195 local spos
= vector
.add(pos
, sides
[s
])
196 local snode
= minetest
.get_node(spos
)
197 -- Is there a powered repeater at one of our sides?
198 local g
= minetest
.get_item_group(snode
.name
, "redstone_repeater")
199 if g
~= 0 and mesecon
.is_receptor_on(snode
.name
) then
200 -- The other repeater must also face towards the constructed node
201 local sface
= delayer_get_output_rules(snode
)[1]
202 local sface_pos
= vector
.add(spos
, sface
)
203 if vector
.equals(sface_pos
, pos
) then
204 -- Repeater is facing towards us! Now we just need to lock the costructed node
205 if mesecon
.is_powered(pos
, delayer_get_input_rules(node
)[1]) ~= false then
206 local newnode
= {name
="mesecons_delayer:delayer_on_locked", param2
= node
.param2
}
207 minetest
.set_node(pos
, newnode
)
208 mesecon
.queue
:add_action(pos
, "receptor_on", {delayer_get_output_rules(newnode
)}, DEFAULT_DELAY
, nil)
210 minetest
.set_node(pos
, {name
="mesecons_delayer:delayer_off_locked", param2
= node
.param2
})
221 minetest
.register_node("mesecons_delayer:delayer_off_"..tostring(i
), {
222 description
= "Redstone Repeater",
223 inventory_image
= icon
,
225 _doc_items_create_entry
= help
,
226 _doc_items_longdesc
= longdesc
,
227 _doc_items_usagehelp
= usagehelp
,
228 drawtype
= "nodebox",
230 "mesecons_delayer_off.png",
231 "mcl_stairs_stone_slab_top.png",
232 "mesecons_delayer_sides_off.png",
233 "mesecons_delayer_sides_off.png",
234 "mesecons_delayer_ends_off.png",
235 "mesecons_delayer_ends_off.png",
237 wield_image
= "mesecons_delayer_off.png",
241 fixed
= { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 },
245 fixed
= { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 },
253 paramtype2
= "facedir",
254 sunlight_propagates
= false,
255 is_ground_content
= false,
256 drop
= 'mesecons_delayer:delayer_off_1',
257 on_rightclick
= function (pos
, node
)
258 if node
.name
=="mesecons_delayer:delayer_off_1" then
259 minetest
.set_node(pos
, {name
="mesecons_delayer:delayer_off_2", param2
=node
.param2
})
260 elseif node
.name
=="mesecons_delayer:delayer_off_2" then
261 minetest
.set_node(pos
, {name
="mesecons_delayer:delayer_off_3", param2
=node
.param2
})
262 elseif node
.name
=="mesecons_delayer:delayer_off_3" then
263 minetest
.set_node(pos
, {name
="mesecons_delayer:delayer_off_4", param2
=node
.param2
})
264 elseif node
.name
=="mesecons_delayer:delayer_off_4" then
265 minetest
.set_node(pos
, {name
="mesecons_delayer:delayer_off_1", param2
=node
.param2
})
268 on_construct
= on_construct
,
269 delayer_time
= delaytime
,
270 delayer_onstate
= "mesecons_delayer:delayer_on_"..tostring(i
),
271 delayer_lockstate
= "mesecons_delayer:delayer_off_locked",
272 sounds
= mcl_sounds
.node_sound_stone_defaults(),
276 state
= mesecon
.state
.off
,
277 rules
= delayer_get_output_rules
281 rules
= delayer_get_input_rules
,
282 action_on
= delayer_activate
285 on_rotate
= on_rotate
,
289 minetest
.register_node("mesecons_delayer:delayer_on_"..tostring(i
), {
290 description
= "Redstone Repeater (Powered)",
291 _doc_items_create_entry
= false,
292 drawtype
= "nodebox",
294 "mesecons_delayer_on.png",
295 "mcl_stairs_stone_slab_top.png",
296 "mesecons_delayer_sides_on.png",
297 "mesecons_delayer_sides_on.png",
298 "mesecons_delayer_ends_on.png",
299 "mesecons_delayer_ends_on.png",
304 fixed
= { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 },
308 fixed
= { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 },
314 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},
316 paramtype2
= "facedir",
317 sunlight_propagates
= false,
318 is_ground_content
= false,
319 drop
= 'mesecons_delayer:delayer_off_1',
320 on_rightclick
= function (pos
, node
)
321 if node
.name
=="mesecons_delayer:delayer_on_1" then
322 minetest
.set_node(pos
, {name
="mesecons_delayer:delayer_on_2",param2
=node
.param2
})
323 elseif node
.name
=="mesecons_delayer:delayer_on_2" then
324 minetest
.set_node(pos
, {name
="mesecons_delayer:delayer_on_3",param2
=node
.param2
})
325 elseif node
.name
=="mesecons_delayer:delayer_on_3" then
326 minetest
.set_node(pos
, {name
="mesecons_delayer:delayer_on_4",param2
=node
.param2
})
327 elseif node
.name
=="mesecons_delayer:delayer_on_4" then
328 minetest
.set_node(pos
, {name
="mesecons_delayer:delayer_on_1",param2
=node
.param2
})
331 after_dig_node
= function(pos
, oldnode
)
332 check_unlock_repeater(pos
, oldnode
)
334 delayer_time
= delaytime
,
335 delayer_offstate
= "mesecons_delayer:delayer_off_"..tostring(i
),
336 delayer_lockstate
= "mesecons_delayer:delayer_on_locked",
337 sounds
= mcl_sounds
.node_sound_stone_defaults(),
341 state
= mesecon
.state
.on
,
342 rules
= delayer_get_output_rules
346 rules
= delayer_get_input_rules
,
347 action_off
= delayer_deactivate
350 on_rotate
= on_rotate
,
358 minetest
.register_node("mesecons_delayer:delayer_off_locked", {
359 description
= "Redstone Repeater (Locked)",
360 _doc_items_create_entry
= false,
361 drawtype
= "nodebox",
362 -- FIXME: Textures of torch and the lock bar overlap. Nodeboxes are (sadly) not suitable for this.
363 -- So this needs to be turned into a mesh.
365 "mesecons_delayer_locked_off.png",
366 "mcl_stairs_stone_slab_top.png",
367 "mesecons_delayer_sides_locked_off.png",
368 "mesecons_delayer_sides_locked_off.png",
369 "mesecons_delayer_front_locked_off.png",
370 "mesecons_delayer_end_locked_off.png",
372 wield_image
= "mesecons_delayer_locked_off.png",
376 fixed
= { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 },
380 fixed
= { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 },
385 { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 }, -- the main slab
386 { -1/16, -6/16, 6/16, 1/16, -1/16, 4/16}, -- still torch
387 { -6/16, -6/16, -1/16, 6/16, -4/16, 1/16}, -- lock
390 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},
392 paramtype2
= "facedir",
393 sunlight_propagates
= false,
394 is_ground_content
= false,
395 drop
= 'mesecons_delayer:delayer_off_1',
396 delayer_time
= DEFAULT_DELAY
,
397 sounds
= mcl_sounds
.node_sound_stone_defaults(),
401 state
= mesecon
.state
.off
,
402 rules
= delayer_get_output_rules
406 rules
= delayer_get_input_rules
,
409 on_rotate
= on_rotate
,
412 minetest
.register_node("mesecons_delayer:delayer_on_locked", {
413 description
= "Redstone Repeater (Locked, Powered)",
414 _doc_items_create_entry
= false,
415 drawtype
= "nodebox",
417 "mesecons_delayer_locked_on.png",
418 "mcl_stairs_stone_slab_top.png",
419 "mesecons_delayer_sides_locked_on.png",
420 "mesecons_delayer_sides_locked_on.png",
421 "mesecons_delayer_front_locked_on.png",
422 "mesecons_delayer_end_locked_on.png",
427 fixed
= { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 },
431 fixed
= { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 },
436 { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 }, -- the main slab
437 { -1/16, -6/16, 6/16, 1/16, -1/16, 4/16}, -- still torch
438 { -6/16, -6/16, -1/16, 6/16, -4/16, 1/16}, -- lock
441 after_dig_node
= function(pos
, oldnode
)
442 check_unlock_repeater(pos
, oldnode
)
444 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},
446 paramtype2
= "facedir",
447 sunlight_propagates
= false,
448 is_ground_content
= false,
449 drop
= 'mesecons_delayer:delayer_off_1',
450 delayer_time
= DEFAULT_DELAY
,
451 sounds
= mcl_sounds
.node_sound_stone_defaults(),
455 state
= mesecon
.state
.on
,
456 rules
= delayer_get_output_rules
460 rules
= delayer_get_input_rules
,
463 on_rotate
= on_rotate
,
466 minetest
.register_craft({
467 output
= "mesecons_delayer:delayer_off_1",
469 {"mesecons_torch:mesecon_torch_on", "mesecons:redstone", "mesecons_torch:mesecon_torch_on"},
470 {"mcl_core:stone","mcl_core:stone", "mcl_core:stone"},
474 -- Add entry aliases for the Help
475 if minetest
.get_modpath("doc") then
476 doc
.add_entry_alias("nodes", "mesecons_delayer:delayer_off_1", "nodes", "mesecons_delayer:delayer_off_2")
477 doc
.add_entry_alias("nodes", "mesecons_delayer:delayer_off_1", "nodes", "mesecons_delayer:delayer_off_3")
478 doc
.add_entry_alias("nodes", "mesecons_delayer:delayer_off_1", "nodes", "mesecons_delayer:delayer_off_4")
479 doc
.add_entry_alias("nodes", "mesecons_delayer:delayer_off_1", "nodes", "mesecons_delayer:delayer_off_locked")
480 doc
.add_entry_alias("nodes", "mesecons_delayer:delayer_off_1", "nodes", "mesecons_delayer:delayer_on_1")
481 doc
.add_entry_alias("nodes", "mesecons_delayer:delayer_off_1", "nodes", "mesecons_delayer:delayer_on_2")
482 doc
.add_entry_alias("nodes", "mesecons_delayer:delayer_off_1", "nodes", "mesecons_delayer:delayer_on_3")
483 doc
.add_entry_alias("nodes", "mesecons_delayer:delayer_off_1", "nodes", "mesecons_delayer:delayer_on_4")
484 doc
.add_entry_alias("nodes", "mesecons_delayer:delayer_off_1", "nodes", "mesecons_delayer:delayer_on_locked")