1 local minetest,math,ipairs,vector,table = minetest,math,ipairs,vector,table
2 --exclude certain mods and nodes from being pushed and pulled to stop glitches
4 minetest.register_on_mods_loaded(function()
5 registered_nodes = minetest.registered_nodes
8 local excluded_mods = {utility=true,craftingtable=true,buildtest=true,sign=true,bed=true}
9 local excluded_nodes = {
10 ["redstone:piston_on"]=true,
11 ["redstone:sticky_piston_on"]=true,
12 ["redstone:actuator"]=true,
13 ["redstone:sticky_actuator"]=true,
14 ["redstone:inverter_on"]=true,
15 ["redstone:inverter_off"]=true,
16 ["redstone:torch_wall"]=true,
17 ["redstone:torch_floor"]=true,
18 ["redstone:lever_on"]=true,
19 ["redstone:lever_off"]=true,
20 ["redstone:button_on"]=true,
21 ["redstone:button_off"]=true,
24 excluded_nodes["redstone:dust_"..i] = true
27 excluded_nodes["redstone:repeater_on_"..i] = true
28 excluded_nodes["redstone:repeater_off_"..i] = true
31 excluded_nodes["redstone:comparator_"..i] = true
34 excluded_nodes["redstone:pressure_plate_"..i] = true
37 excluded_nodes["redstone:ore_"..i] = true
42 ███████╗██╗ ██╗███╗ ██╗ ██████╗████████╗██╗ ██████╗ ███╗ ██╗
43 ██╔════╝██║ ██║████╗ ██║██╔════╝╚══██╔══╝██║██╔═══██╗████╗ ██║
44 █████╗ ██║ ██║██╔██╗ ██║██║ ██║ ██║██║ ██║██╔██╗ ██║
45 ██╔══╝ ██║ ██║██║╚██╗██║██║ ██║ ██║██║ ██║██║╚██╗██║
46 ██║ ╚██████╔╝██║ ╚████║╚██████╗ ██║ ██║╚██████╔╝██║ ╚████║
47 ╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝
50 --this is how the piston pushes nodes
59 local function push_nodes(pos,dir)
63 index_pos = vector.add(vector.multiply(dir,i),pos)
64 node = minetest.get_node(index_pos)
66 def = minetest.registered_nodes[node.name]
68 push = ((excluded_mods[def.mod_origin] ~= true) and (excluded_nodes[name] ~= true))
69 if push and name ~= "air" then
74 table.insert(move_index,index)
75 elseif name == "air" then
84 --check if room to move and objects in log
85 if space == true and next(move_index) then
86 if table.getn(move_index) == 1 and minetest.get_item_group(move_index[1].name, "falling_node") > 0 then
87 for i = 1,table.getn(move_index) do
88 move_index[i].pos = vector.add(move_index[i].pos,dir)
89 minetest.set_node(move_index[i].pos,{name="air"})
91 local obj = minetest.add_entity(vector.add(move_index[i].pos,dir), "__builtin:falling_node")
92 obj:get_luaentity():set_node({name=move_index[i].name})
93 obj:set_velocity(vector.multiply(dir,19))
96 for i = 1,table.getn(move_index) do
98 if move_index[i].pos then
99 move_index[i].pos = vector.add(move_index[i].pos,dir)
100 minetest.set_node(move_index[i].pos,move_index[i])
101 minetest.check_for_falling(move_index[i].pos)
110 --this is the logic of the piston
113 local piston_location
115 local function actuator_arm_function(pos)
116 --this is where the piston activates
117 facedir = minetest.get_node(pos).param2
118 dir = minetest.facedir_to_dir(facedir)
119 piston_location = vector.add(pos,dir)
120 worked = push_nodes(pos,dir)
121 local node = minetest.get_node(vector.add(pos,dir)).name
123 if worked == true then
125 if node == "air" then
126 for _,object in ipairs(minetest.get_objects_inside_radius(piston_location, 2)) do
128 if object:is_player() and object:get_hp() > 0 then
129 local pos2 = object:get_pos()
130 local compare = vector.subtract(pos2,piston_location)
131 local real_y = compare.y
132 compare = vector.abs(compare)
135 if compare.y <= 0.5 and compare.x < 0.8 and compare.z < 0.8 then
136 object:move_to(vector.add(dir,pos2))
137 object:add_player_velocity(vector.multiply(dir,20))
140 elseif dir.x ~=0 or dir.z ~= 0 then
141 if real_y <= 0.5 and real_y >= -1.6 and compare.x < 0.8 and compare.z < 0.8 then
142 object:move_to(vector.add(dir,pos2))
143 object:add_player_velocity(vector.multiply(dir,19))
146 elseif not object:is_player() and object:get_luaentity().name == "__builtin:falling_node" then
147 local pos2 = object:get_pos()
148 local compare = vector.subtract(pos2,piston_location)
149 local real_y = compare.y
150 compare = vector.abs(compare)
151 if compare.y <= 1.5 and compare.x <= 1.5 and compare.z <= 1.5 then
152 object:move_to(vector.add(dir,pos2))
153 object:add_velocity(vector.multiply(dir,20))
155 elseif not object:is_player() and object:get_luaentity().name == "__builtin:item" then
156 local pos2 = object:get_pos()
157 local compare = vector.subtract(pos2,piston_location)
158 local real_y = compare.y
159 compare = vector.abs(compare)
160 if compare.y <= 1 and compare.x <= 1 and compare.z <= 1 then
161 object:move_to(vector.add(dir,pos2))
162 object:add_velocity(vector.multiply(dir,20))
163 object:get_luaentity().poll_timer = 0
168 minetest.sound_play("piston", {pos=pos,pitch=math.random(85,100)/100})
169 minetest.set_node(piston_location,{name="redstone:actuator",param2=facedir})
170 minetest.swap_node(pos,{name="redstone:piston_on",param2=facedir})
172 redstone.inject(pos,{
173 name = "redstone:piston_on",
176 minetest.after(0,function()
184 ██████╗ ███████╗███████╗
185 ██╔═══██╗██╔════╝██╔════╝
193 minetest.register_node("redstone:piston_off", {
194 description = "Piston",
195 tiles = {"redstone_piston.png","redstone_piston.png^[transformR180","redstone_piston.png^[transformR270","redstone_piston.png^[transformR90","wood.png","stone.png"},
196 paramtype2 = "facedir",
197 groups = {stone = 1, hard = 1, pickaxe = 1, hand = 4,pathable = 1,redstone_activation=1},
198 sounds = main.stoneSound(),
199 drop = "redstone:piston_off",
201 sunlight_propagates = true,
202 --reverse the direction to face the player
203 after_place_node = function(pos, placer, itemstack, pointed_thing)
204 local look = placer:get_look_dir()
205 look = vector.multiply(look,-1)
206 local dir = minetest.dir_to_facedir(look, true)
207 minetest.swap_node(pos,{name="redstone:piston_off",param2=dir})
208 redstone.inject(pos,{
209 name = "redstone:piston_off",
214 after_destruct = function(pos, oldnode)
215 redstone.inject(pos,nil)
220 redstone.register_activator({
221 name = "redstone:piston_off",
222 activate = function(pos)
223 actuator_arm_function(pos)
227 minetest.register_lbm({
228 name = "redstone:piston_off",
229 nodenames = {"redstone:piston_off"},
230 run_at_every_load = true,
231 action = function(pos)
232 redstone.inject(pos,{
233 name = "redstone:piston_off",
236 minetest.after(0,function()
252 minetest.register_node("redstone:piston_on", {
253 description = "Piston",
254 tiles = {"redstone_piston.png","redstone_piston.png^[transformR180","redstone_piston.png^[transformR270","redstone_piston.png^[transformR90","stone.png","stone.png"},
255 drawtype = "nodebox",
257 paramtype2 = "facedir",
258 groups = {stone = 1, hard = 1, pickaxe = 1, hand = 4,pathable = 1,redstone_activation=1},
259 sounds = main.stoneSound(),
260 drop = "redstone:piston_off",
264 --left front bottom right back top
265 {-0.5, -0.5, -0.5, 0.5, 0.5, 3/16},
268 after_destruct = function(pos, oldnode)
269 local facedir = oldnode.param2
270 local dir = minetest.facedir_to_dir(facedir)
271 local piston_location = vector.add(pos,dir)
272 minetest.remove_node(piston_location)
273 redstone.inject(pos,nil)
277 minetest.register_lbm({
278 name = "redstone:piston_on",
279 nodenames = {"redstone:piston_on"},
280 run_at_every_load = true,
281 action = function(pos)
282 redstone.inject(pos,{
283 name = "redstone:piston_on",
286 minetest.after(0,function()
292 redstone.register_activator({
293 name = "redstone:piston_on",
294 deactivate = function(pos)
295 --this is where the piston deactivates
296 local facedir = minetest.get_node(pos).param2
297 local dir = minetest.facedir_to_dir(facedir)
298 local piston_location = vector.add(pos,dir)
299 minetest.remove_node(piston_location)
300 minetest.swap_node(pos,{name="redstone:piston_off",param2=facedir})
301 piston_location.y = piston_location.y + 1
302 minetest.sound_play("piston", {pos=pos,pitch=math.random(85,100)/100})
303 redstone.inject(pos,{
304 name = "redstone:piston_off",
312 █████╗ ██████╗ ███╗ ███╗
313 ██╔══██╗██╔══██╗████╗ ████║
314 ███████║██████╔╝██╔████╔██║
315 ██╔══██║██╔══██╗██║╚██╔╝██║
316 ██║ ██║██║ ██║██║ ╚═╝ ██║
317 ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝
322 minetest.register_node("redstone:actuator", {
323 description = "Piston Actuator",
324 tiles = {"wood.png"},
325 drawtype = "nodebox",
327 paramtype2 = "facedir",
328 groups = {stone = 1, hard = 1, pickaxe = 1, hand = 4,pathable = 1},
329 sounds = main.stoneSound(),
330 drop = "redstone:piston_off",
334 --left front bottom right back top
335 {-0.5, -0.5, 0.2, 0.5, 0.5, 0.5}, --mover
336 {-0.15, -0.15, -0.9, 0.15, 0.15, 0.5}, --actuator
339 after_destruct = function(pos, oldnode)
340 local facedir = oldnode.param2
341 local dir = minetest.facedir_to_dir(facedir)
342 dir = vector.multiply(dir,-1)
343 local piston_location = vector.add(pos,dir)
344 minetest.remove_node(piston_location)
353 ███████╗████████╗██╗ ██████╗██╗ ██╗██╗ ██╗ ██████╗ ██╗███████╗████████╗ ██████╗ ███╗ ██╗ ██████╗ ███████╗ ██████╗ ██╗███╗ ██╗███████╗
354 ██╔════╝╚══██╔══╝██║██╔════╝██║ ██╔╝╚██╗ ██╔╝ ██╔══██╗██║██╔════╝╚══██╔══╝██╔═══██╗████╗ ██║ ██╔══██╗██╔════╝██╔════╝ ██║████╗ ██║██╔════╝
355 ███████╗ ██║ ██║██║ █████╔╝ ╚████╔╝ ██████╔╝██║███████╗ ██║ ██║ ██║██╔██╗ ██║ ██████╔╝█████╗ ██║ ███╗██║██╔██╗ ██║███████╗
356 ╚════██║ ██║ ██║██║ ██╔═██╗ ╚██╔╝ ██╔═══╝ ██║╚════██║ ██║ ██║ ██║██║╚██╗██║ ██╔══██╗██╔══╝ ██║ ██║██║██║╚██╗██║╚════██║
357 ███████║ ██║ ██║╚██████╗██║ ██╗ ██║ ██║ ██║███████║ ██║ ╚██████╔╝██║ ╚████║ ██████╔╝███████╗╚██████╔╝██║██║ ╚████║███████║
358 ╚══════╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚══════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═════╝ ╚══════╝ ╚═════╝ ╚═╝╚═╝ ╚═══╝╚══════╝
368 ███████╗██╗ ██╗███╗ ██╗ ██████╗████████╗██╗ ██████╗ ███╗ ██╗
369 ██╔════╝██║ ██║████╗ ██║██╔════╝╚══██╔══╝██║██╔═══██╗████╗ ██║
370 █████╗ ██║ ██║██╔██╗ ██║██║ ██║ ██║██║ ██║██╔██╗ ██║
371 ██╔══╝ ██║ ██║██║╚██╗██║██║ ██║ ██║██║ ██║██║╚██╗██║
372 ██║ ╚██████╔╝██║ ╚████║╚██████╗ ██║ ██║╚██████╔╝██║ ╚████║
373 ╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝
377 --this is how the piston pushes nodes
386 local function sticky_push_nodes(pos,dir)
390 index_pos = vector.add(vector.multiply(dir,i),pos)
391 node = minetest.get_node(index_pos)
393 def = minetest.registered_nodes[node.name]
395 push = ((excluded_mods[def.mod_origin] ~= true) and (excluded_nodes[name] ~= true))
396 if push and name ~= "air" then
398 index.pos = index_pos
400 index.param2 = param2
401 table.insert(move_index,index)
402 elseif name == "air" then
411 --check if room to move and objects in log
412 if space == true and next(move_index) then
413 for i = 1,table.getn(move_index) do
414 move_index[i].pos = vector.add(move_index[i].pos,dir)
415 minetest.set_node(move_index[i].pos,move_index[i])
416 minetest.check_for_falling(move_index[i].pos)
422 --this is the logic of the piston
425 local piston_location
427 local function sticky_actuator_arm_function(pos)
428 --this is where the piston activates
429 facedir = minetest.get_node(pos).param2
430 dir = minetest.facedir_to_dir(facedir)
431 piston_location = vector.add(pos,dir)
432 worked = sticky_push_nodes(pos,dir)
433 local node = minetest.get_node(vector.add(pos,dir)).name
435 if worked == true then
437 if node == "air" then
438 for _,object in ipairs(minetest.get_objects_inside_radius(piston_location, 2)) do
440 if object:is_player() and object:get_hp() > 0 then
441 local pos2 = object:get_pos()
442 local compare = vector.subtract(pos2,piston_location)
443 local real_y = compare.y
444 compare = vector.abs(compare)
447 if compare.y <= 0.5 and compare.x < 0.8 and compare.z < 0.8 then
448 object:move_to(vector.add(dir,pos2))
451 elseif dir.x ~=0 or dir.z ~= 0 then
452 if real_y <= 0.5 and real_y >= -1.6 and compare.x < 0.8 and compare.z < 0.8 then
453 object:move_to(vector.add(dir,pos2))
456 elseif not object:is_player() and object:get_luaentity().name == "__builtin:falling_node" then
457 local pos2 = object:get_pos()
458 local compare = vector.subtract(pos2,piston_location)
459 local real_y = compare.y
460 compare = vector.abs(compare)
461 if compare.y <= 1.5 and compare.x <= 1.5 and compare.z <= 1.5 then
462 object:move_to(vector.add(dir,pos2))
464 elseif not object:is_player() and object:get_luaentity().name == "__builtin:item" then
465 local pos2 = object:get_pos()
466 local compare = vector.subtract(pos2,piston_location)
467 local real_y = compare.y
468 compare = vector.abs(compare)
469 if compare.y <= 1 and compare.x <= 1 and compare.z <= 1 then
470 object:move_to(vector.add(dir,pos2))
471 object:get_luaentity().poll_timer = 0
476 minetest.sound_play("piston", {pos=pos,pitch=math.random(85,100)/100})
477 minetest.set_node(piston_location,{name="redstone:sticky_actuator",param2=facedir})
478 minetest.swap_node(pos,{name="redstone:sticky_piston_on",param2=facedir})
480 redstone.inject(pos,{
481 name = "redstone:sticky_piston_on",
484 minetest.after(0,function()
492 ██████╗ ███████╗███████╗
493 ██╔═══██╗██╔════╝██╔════╝
501 minetest.register_node("redstone:sticky_piston_off", {
502 description = "Sticky Piston",
503 tiles = {"redstone_piston.png","redstone_piston.png^[transformR180","redstone_piston.png^[transformR270","redstone_piston.png^[transformR90","sticky_piston.png","stone.png"},
504 paramtype2 = "facedir",
505 groups = {stone = 1, hard = 1, pickaxe = 1, hand = 4,pathable = 1,redstone_activation=1},
506 sounds = main.stoneSound(),
507 drop = "redstone:sticky_piston_off",
509 sunlight_propagates = true,
510 --reverse the direction to face the player
511 after_place_node = function(pos, placer, itemstack, pointed_thing)
512 local look = placer:get_look_dir()
513 look = vector.multiply(look,-1)
514 local dir = minetest.dir_to_facedir(look, true)
515 minetest.swap_node(pos,{name="redstone:sticky_piston_off",param2=dir})
516 redstone.inject(pos,{
517 name = "redstone:sticky_piston_off",
522 after_destruct = function(pos, oldnode)
523 redstone.inject(pos,nil)
528 redstone.register_activator({
529 name = "redstone:sticky_piston_off",
530 activate = function(pos)
531 sticky_actuator_arm_function(pos)
535 minetest.register_lbm({
536 name = "redstone:sticky_piston_off",
537 nodenames = {"redstone:sticky_piston_off"},
538 run_at_every_load = true,
539 action = function(pos)
540 redstone.inject(pos,{
541 name = "redstone:sticky_piston_off",
544 minetest.after(0,function()
560 local function sticky_piston_pull_nodes(pos,dir)
561 local move_index = {}
562 local index_pos = vector.add(pos,dir)
564 local node = minetest.get_node(index_pos)
565 local param2 = node.param2
566 local def = minetest.registered_nodes[node.name]
567 local name = node.name
568 local pull = ((excluded_mods[def.mod_origin] ~= true) and (excluded_nodes[name] ~= true))
569 --if it can be pulled pull it
570 if pull and name ~= "air" then
571 minetest.remove_node(index_pos)
572 minetest.set_node(pos,{name=name,param2=param2})
579 minetest.register_node("redstone:sticky_piston_on", {
580 description = "Sticky Piston",
581 tiles = {"redstone_piston.png","redstone_piston.png^[transformR180","redstone_piston.png^[transformR270","redstone_piston.png^[transformR90","stone.png","stone.png"},
582 drawtype = "nodebox",
584 paramtype2 = "facedir",
585 groups = {stone = 1, hard = 1, pickaxe = 1, hand = 4,pathable = 1,redstone_activation=1},
586 sounds = main.stoneSound(),
587 drop = "redstone:sticky_piston_off",
591 --left front bottom right back top
592 {-0.5, -0.5, -0.5, 0.5, 0.5, 3/16},
595 after_destruct = function(pos, oldnode)
596 local facedir = oldnode.param2
597 local dir = minetest.facedir_to_dir(facedir)
598 local piston_location = vector.add(pos,dir)
599 minetest.remove_node(piston_location)
600 redstone.inject(pos,nil)
604 minetest.register_lbm({
605 name = "redstone:sticky_piston_on",
606 nodenames = {"redstone:sticky_piston_on"},
607 run_at_every_load = true,
608 action = function(pos)
609 redstone.inject(pos,{
610 name = "redstone:sticky_piston_on",
613 minetest.after(0,function()
619 redstone.register_activator({
620 name = "redstone:sticky_piston_on",
621 deactivate = function(pos)
622 --this is where the piston deactivates
623 local facedir = minetest.get_node(pos).param2
624 local dir = minetest.facedir_to_dir(facedir)
625 local piston_location = vector.add(pos,dir)
627 minetest.remove_node(piston_location)
629 sticky_piston_pull_nodes(piston_location,dir)
630 minetest.swap_node(pos,{name="redstone:sticky_piston_off",param2=facedir})
632 minetest.sound_play("piston", {pos=pos,pitch=math.random(85,100)/100})
633 redstone.inject(pos,{
634 name = "redstone:sticky_piston_off",
642 █████╗ ██████╗ ███╗ ███╗
643 ██╔══██╗██╔══██╗████╗ ████║
644 ███████║██████╔╝██╔████╔██║
645 ██╔══██║██╔══██╗██║╚██╔╝██║
646 ██║ ██║██║ ██║██║ ╚═╝ ██║
647 ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝
652 minetest.register_node("redstone:sticky_actuator", {
653 description = "Piston Actuator",
654 tiles = {"wood.png","wood.png","wood.png","wood.png","sticky_piston.png","wood.png"},
655 drawtype = "nodebox",
657 paramtype2 = "facedir",
658 groups = {stone = 1, hard = 1, pickaxe = 1, hand = 4,pathable = 1},
659 sounds = main.stoneSound(),
660 drop = "redstone:piston_off",
664 --left front bottom right back top
665 {-0.5, -0.5, 0.2, 0.5, 0.5, 0.5}, --mover
666 {-0.15, -0.15, -0.9, 0.15, 0.15, 0.5}, --actuator
669 after_destruct = function(pos, oldnode)
670 local facedir = oldnode.param2
671 local dir = minetest.facedir_to_dir(facedir)
672 dir = vector.multiply(dir,-1)
673 local piston_location = vector.add(pos,dir)
674 minetest.remove_node(piston_location)