Version 0.41.3
[MineClone/MineClone2/MineClone2-Fixes.git] / mods / ITEMS / REDSTONE / mesecons_delayer / init.lua
blobd6c1f95bb0a014d3a47266d1a9b602037066bb13
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)
9 end
10 return rules
11 end
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)
17 end
18 return rules
19 end
21 -- Return the sides of a delayer.
22 -- Those are used to toggle the lock state.
23 local delayer_get_sides = function(node)
24 local rules = {
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)
30 end
31 return rules
32 end
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)
47 local fail = false
48 for _, lr in pairs(lrs) do
49 if lr.x == r.x or lr.z == r.z then
50 fail = true
51 break
52 end
53 end
54 if not fail 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)
60 return true
61 end
62 end
63 return false
64 end
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?
79 if g == 5 then
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
85 return false
86 end
87 end
88 -- Now we check if there's a powered repeater on the other side of the
89 -- locked repeater.
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!
99 return false
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
105 ldelay = 1
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)
110 else
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)
114 return true
116 return false
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)
138 local on_rotate
139 if minetest.get_modpath("screwdriver") then
140 on_rotate = screwdriver.disallow
143 -- Register the 2 (states) x 4 (delay times) delayers
145 for i = 1, 4 do
146 local groups = {}
147 if i == 1 then
148 groups = {dig_immediate=3,dig_by_water=1,destroy_by_lava_flow=1,dig_by_piston=1,attached_node=1,redstone_repeater=i}
149 else
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]
155 local boxes
156 if i == 1 then
157 boxes = {
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
162 elseif i == 2 then
163 boxes = {
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
168 elseif i == 3 then
169 boxes = {
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
174 elseif i == 4 then
175 boxes = {
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
183 if i == 1 then
184 help = true
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)
194 for s=1, #sides do
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)
209 else
210 minetest.set_node(pos, {name="mesecons_delayer:delayer_off_locked", param2 = node.param2})
212 break
217 else
218 help = false
221 minetest.register_node("mesecons_delayer:delayer_off_"..tostring(i), {
222 description = "Redstone Repeater",
223 inventory_image = icon,
224 wield_image = icon,
225 _doc_items_create_entry = help,
226 _doc_items_longdesc = longdesc,
227 _doc_items_usagehelp = usagehelp,
228 drawtype = "nodebox",
229 tiles = {
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",
238 walkable = true,
239 selection_box = {
240 type = "fixed",
241 fixed = { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 },
243 collision_box = {
244 type = "fixed",
245 fixed = { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 },
247 node_box = {
248 type = "fixed",
249 fixed = boxes
251 groups = groups,
252 paramtype = "light",
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})
267 end,
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(),
273 mesecons = {
274 receptor =
276 state = mesecon.state.off,
277 rules = delayer_get_output_rules
279 effector =
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",
293 tiles = {
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",
301 walkable = true,
302 selection_box = {
303 type = "fixed",
304 fixed = { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 },
306 collision_box = {
307 type = "fixed",
308 fixed = { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 },
310 node_box = {
311 type = "fixed",
312 fixed = boxes
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},
315 paramtype = "light",
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})
330 end,
331 after_dig_node = function(pos, oldnode)
332 check_unlock_repeater(pos, oldnode)
333 end,
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(),
338 mesecons = {
339 receptor =
341 state = mesecon.state.on,
342 rules = delayer_get_output_rules
344 effector =
346 rules = delayer_get_input_rules,
347 action_off = delayer_deactivate
350 on_rotate = on_rotate,
356 -- Locked repeater
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.
364 tiles = {
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",
373 walkable = true,
374 selection_box = {
375 type = "fixed",
376 fixed = { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 },
378 collision_box = {
379 type = "fixed",
380 fixed = { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 },
382 node_box = {
383 type = "fixed",
384 fixed = {
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},
391 paramtype = "light",
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(),
398 mesecons = {
399 receptor =
401 state = mesecon.state.off,
402 rules = delayer_get_output_rules
404 effector =
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",
416 tiles = {
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",
424 walkable = true,
425 selection_box = {
426 type = "fixed",
427 fixed = { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 },
429 collision_box = {
430 type = "fixed",
431 fixed = { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 },
433 node_box = {
434 type = "fixed",
435 fixed = {
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)
443 end,
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},
445 paramtype = "light",
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(),
452 mesecons = {
453 receptor =
455 state = mesecon.state.on,
456 rules = delayer_get_output_rules
458 effector =
460 rules = delayer_get_input_rules,
463 on_rotate = on_rotate,
466 minetest.register_craft({
467 output = "mesecons_delayer:delayer_off_1",
468 recipe = {
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")