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",
182 ██████╗ ███████╗███████╗
183 ██╔═══██╗██╔════╝██╔════╝
191 minetest.register_node("redstone:piston_off", {
192 description = "Piston",
193 tiles = {"redstone_piston.png","redstone_piston.png^[transformR180","redstone_piston.png^[transformR270","redstone_piston.png^[transformR90","wood.png","stone.png"},
194 paramtype2 = "facedir",
195 groups = {stone = 1, hard = 1, pickaxe = 1, hand = 4,pathable = 1,redstone_activation=1},
196 sounds = main.stoneSound(),
197 drop = "redstone:piston_off",
199 sunlight_propagates = true,
200 --reverse the direction to face the player
201 on_construct = function(pos)
202 redstone.inject(pos,{
203 name = "redstone:piston_off",
208 on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
209 local look = clicker:get_look_dir()
210 look = vector.multiply(look,-1)
211 local dir = minetest.dir_to_facedir(look, true)
212 minetest.swap_node(pos,{name="redstone:piston_off",param2=dir})
214 after_place_node = function(pos, placer, itemstack, pointed_thing)
215 local look = placer:get_look_dir()
216 look = vector.multiply(look,-1)
217 local dir = minetest.dir_to_facedir(look, true)
218 minetest.swap_node(pos,{name="redstone:piston_off",param2=dir})
220 after_destruct = function(pos, oldnode)
221 redstone.inject(pos,nil)
226 redstone.register_activator({
227 name = "redstone:piston_off",
228 activate = function(pos)
229 minetest.after(0,function()
230 actuator_arm_function(pos)
235 minetest.register_lbm({
236 name = "redstone:piston_off",
237 nodenames = {"redstone:piston_off"},
238 run_at_every_load = true,
239 action = function(pos)
240 redstone.inject(pos,{
241 name = "redstone:piston_off",
244 --redstone needs to warm up
245 minetest.after(0,function()
261 minetest.register_node("redstone:piston_on", {
262 description = "Piston",
263 tiles = {"redstone_piston.png","redstone_piston.png^[transformR180","redstone_piston.png^[transformR270","redstone_piston.png^[transformR90","stone.png","stone.png"},
264 drawtype = "nodebox",
266 paramtype2 = "facedir",
267 groups = {stone = 1, hard = 1, pickaxe = 1, hand = 4,pathable = 1,redstone_activation=1},
268 sounds = main.stoneSound(),
269 drop = "redstone:piston_off",
273 --left front bottom right back top
274 {-0.5, -0.5, -0.5, 0.5, 0.5, 3/16},
277 after_destruct = function(pos, oldnode)
278 local facedir = oldnode.param2
279 local dir = minetest.facedir_to_dir(facedir)
280 local piston_location = vector.add(pos,dir)
281 minetest.remove_node(piston_location)
282 redstone.inject(pos,nil)
286 minetest.register_lbm({
287 name = "redstone:piston_on",
288 nodenames = {"redstone:piston_on"},
289 run_at_every_load = true,
290 action = function(pos)
291 redstone.inject(pos,{
292 name = "redstone:piston_on",
295 --redstone needs to warm up
296 minetest.after(0,function()
302 redstone.register_activator({
303 name = "redstone:piston_on",
304 deactivate = function(pos)
305 --this is where the piston deactivates
306 local facedir = minetest.get_node(pos).param2
307 local dir = minetest.facedir_to_dir(facedir)
308 local piston_location = vector.add(pos,dir)
309 minetest.remove_node(piston_location)
310 minetest.swap_node(pos,{name="redstone:piston_off",param2=facedir})
311 piston_location.y = piston_location.y + 1
312 minetest.sound_play("piston", {pos=pos,pitch=math.random(85,100)/100})
313 redstone.inject(pos,{
314 name = "redstone:piston_off",
322 █████╗ ██████╗ ███╗ ███╗
323 ██╔══██╗██╔══██╗████╗ ████║
324 ███████║██████╔╝██╔████╔██║
325 ██╔══██║██╔══██╗██║╚██╔╝██║
326 ██║ ██║██║ ██║██║ ╚═╝ ██║
327 ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝
332 minetest.register_node("redstone:actuator", {
333 description = "Piston Actuator",
334 tiles = {"wood.png"},
335 drawtype = "nodebox",
337 paramtype2 = "facedir",
338 groups = {stone = 1, hard = 1, pickaxe = 1, hand = 4,pathable = 1},
339 sounds = main.stoneSound(),
340 drop = "redstone:piston_off",
344 --left front bottom right back top
345 {-0.5, -0.5, 0.2, 0.5, 0.5, 0.5}, --mover
346 {-0.15, -0.15, -0.9, 0.15, 0.15, 0.5}, --actuator
349 after_destruct = function(pos, oldnode)
350 local facedir = oldnode.param2
351 local dir = minetest.facedir_to_dir(facedir)
352 dir = vector.multiply(dir,-1)
353 local piston_location = vector.add(pos,dir)
354 minetest.remove_node(piston_location)
363 ███████╗████████╗██╗ ██████╗██╗ ██╗██╗ ██╗ ██████╗ ██╗███████╗████████╗ ██████╗ ███╗ ██╗ ██████╗ ███████╗ ██████╗ ██╗███╗ ██╗███████╗
364 ██╔════╝╚══██╔══╝██║██╔════╝██║ ██╔╝╚██╗ ██╔╝ ██╔══██╗██║██╔════╝╚══██╔══╝██╔═══██╗████╗ ██║ ██╔══██╗██╔════╝██╔════╝ ██║████╗ ██║██╔════╝
365 ███████╗ ██║ ██║██║ █████╔╝ ╚████╔╝ ██████╔╝██║███████╗ ██║ ██║ ██║██╔██╗ ██║ ██████╔╝█████╗ ██║ ███╗██║██╔██╗ ██║███████╗
366 ╚════██║ ██║ ██║██║ ██╔═██╗ ╚██╔╝ ██╔═══╝ ██║╚════██║ ██║ ██║ ██║██║╚██╗██║ ██╔══██╗██╔══╝ ██║ ██║██║██║╚██╗██║╚════██║
367 ███████║ ██║ ██║╚██████╗██║ ██╗ ██║ ██║ ██║███████║ ██║ ╚██████╔╝██║ ╚████║ ██████╔╝███████╗╚██████╔╝██║██║ ╚████║███████║
368 ╚══════╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚══════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═════╝ ╚══════╝ ╚═════╝ ╚═╝╚═╝ ╚═══╝╚══════╝
378 ███████╗██╗ ██╗███╗ ██╗ ██████╗████████╗██╗ ██████╗ ███╗ ██╗
379 ██╔════╝██║ ██║████╗ ██║██╔════╝╚══██╔══╝██║██╔═══██╗████╗ ██║
380 █████╗ ██║ ██║██╔██╗ ██║██║ ██║ ██║██║ ██║██╔██╗ ██║
381 ██╔══╝ ██║ ██║██║╚██╗██║██║ ██║ ██║██║ ██║██║╚██╗██║
382 ██║ ╚██████╔╝██║ ╚████║╚██████╗ ██║ ██║╚██████╔╝██║ ╚████║
383 ╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝
387 --this is how the piston pushes nodes
396 local function sticky_push_nodes(pos,dir)
400 index_pos = vector.add(vector.multiply(dir,i),pos)
401 node = minetest.get_node(index_pos)
403 def = minetest.registered_nodes[node.name]
405 push = ((excluded_mods[def.mod_origin] ~= true) and (excluded_nodes[name] ~= true))
406 if push and name ~= "air" then
408 index.pos = index_pos
410 index.param2 = param2
411 table.insert(move_index,index)
412 elseif name == "air" then
421 --check if room to move and objects in log
422 if space == true and next(move_index) then
423 for i = 1,table.getn(move_index) do
424 move_index[i].pos = vector.add(move_index[i].pos,dir)
425 minetest.set_node(move_index[i].pos,move_index[i])
426 minetest.check_for_falling(move_index[i].pos)
432 --this is the logic of the piston
435 local piston_location
437 local function sticky_actuator_arm_function(pos)
438 --this is where the piston activates
439 facedir = minetest.get_node(pos).param2
440 dir = minetest.facedir_to_dir(facedir)
441 piston_location = vector.add(pos,dir)
442 worked = sticky_push_nodes(pos,dir)
443 local node = minetest.get_node(vector.add(pos,dir)).name
445 if worked == true then
447 if node == "air" then
448 for _,object in ipairs(minetest.get_objects_inside_radius(piston_location, 2)) do
450 if object:is_player() and object:get_hp() > 0 then
451 local pos2 = object:get_pos()
452 local compare = vector.subtract(pos2,piston_location)
453 local real_y = compare.y
454 compare = vector.abs(compare)
457 if compare.y <= 0.5 and compare.x < 0.8 and compare.z < 0.8 then
458 object:move_to(vector.add(dir,pos2))
461 elseif dir.x ~=0 or dir.z ~= 0 then
462 if real_y <= 0.5 and real_y >= -1.6 and compare.x < 0.8 and compare.z < 0.8 then
463 object:move_to(vector.add(dir,pos2))
466 elseif not object:is_player() and object:get_luaentity().name == "__builtin:falling_node" then
467 local pos2 = object:get_pos()
468 local compare = vector.subtract(pos2,piston_location)
469 local real_y = compare.y
470 compare = vector.abs(compare)
471 if compare.y <= 1.5 and compare.x <= 1.5 and compare.z <= 1.5 then
472 object:move_to(vector.add(dir,pos2))
474 elseif not object:is_player() and object:get_luaentity().name == "__builtin:item" then
475 local pos2 = object:get_pos()
476 local compare = vector.subtract(pos2,piston_location)
477 local real_y = compare.y
478 compare = vector.abs(compare)
479 if compare.y <= 1 and compare.x <= 1 and compare.z <= 1 then
480 object:move_to(vector.add(dir,pos2))
481 object:get_luaentity().poll_timer = 0
486 minetest.sound_play("piston", {pos=pos,pitch=math.random(85,100)/100})
487 minetest.set_node(piston_location,{name="redstone:sticky_actuator",param2=facedir})
488 minetest.swap_node(pos,{name="redstone:sticky_piston_on",param2=facedir})
490 redstone.inject(pos,{
491 name = "redstone:sticky_piston_on",
501 ██████╗ ███████╗███████╗
502 ██╔═══██╗██╔════╝██╔════╝
510 minetest.register_node("redstone:sticky_piston_off", {
511 description = "Sticky Piston",
512 tiles = {"redstone_piston.png","redstone_piston.png^[transformR180","redstone_piston.png^[transformR270","redstone_piston.png^[transformR90","sticky_piston.png","stone.png"},
513 paramtype2 = "facedir",
514 groups = {stone = 1, hard = 1, pickaxe = 1, hand = 4,pathable = 1,redstone_activation=1},
515 sounds = main.stoneSound(),
516 drop = "redstone:sticky_piston_off",
518 sunlight_propagates = true,
519 on_construct = function(pos)
520 redstone.inject(pos,{
521 name = "redstone:sticky_piston_off",
526 on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
527 local look = clicker:get_look_dir()
528 look = vector.multiply(look,-1)
529 local dir = minetest.dir_to_facedir(look, true)
530 minetest.swap_node(pos,{name="redstone:sticky_piston_off",param2=dir})
532 --reverse the direction to face the player
533 after_place_node = function(pos, placer, itemstack, pointed_thing)
534 local look = placer:get_look_dir()
535 look = vector.multiply(look,-1)
536 local dir = minetest.dir_to_facedir(look, true)
537 minetest.swap_node(pos,{name="redstone:sticky_piston_off",param2=dir})
539 after_destruct = function(pos, oldnode)
540 redstone.inject(pos,nil)
545 redstone.register_activator({
546 name = "redstone:sticky_piston_off",
547 activate = function(pos)
548 minetest.after(0,function()
549 sticky_actuator_arm_function(pos)
554 minetest.register_lbm({
555 name = "redstone:sticky_piston_off",
556 nodenames = {"redstone:sticky_piston_off"},
557 run_at_every_load = true,
558 action = function(pos)
559 redstone.inject(pos,{
560 name = "redstone:sticky_piston_off",
563 --redstone needs to warm up
564 minetest.after(0,function()
580 local function sticky_piston_pull_nodes(pos,dir)
581 local move_index = {}
582 local index_pos = vector.add(pos,dir)
584 local node = minetest.get_node(index_pos)
585 local param2 = node.param2
586 local def = minetest.registered_nodes[node.name]
587 local name = node.name
588 local pull = ((excluded_mods[def.mod_origin] ~= true) and (excluded_nodes[name] ~= true))
589 --if it can be pulled pull it
590 if pull and name ~= "air" then
591 minetest.remove_node(index_pos)
592 minetest.set_node(pos,{name=name,param2=param2})
593 minetest.check_for_falling(index_pos)
600 minetest.register_node("redstone:sticky_piston_on", {
601 description = "Sticky Piston",
602 tiles = {"redstone_piston.png","redstone_piston.png^[transformR180","redstone_piston.png^[transformR270","redstone_piston.png^[transformR90","stone.png","stone.png"},
603 drawtype = "nodebox",
605 paramtype2 = "facedir",
606 groups = {stone = 1, hard = 1, pickaxe = 1, hand = 4,pathable = 1,redstone_activation=1},
607 sounds = main.stoneSound(),
608 drop = "redstone:sticky_piston_off",
612 --left front bottom right back top
613 {-0.5, -0.5, -0.5, 0.5, 0.5, 3/16},
616 after_destruct = function(pos, oldnode)
617 local facedir = oldnode.param2
618 local dir = minetest.facedir_to_dir(facedir)
619 local piston_location = vector.add(pos,dir)
620 minetest.remove_node(piston_location)
621 redstone.inject(pos,nil)
625 minetest.register_lbm({
626 name = "redstone:sticky_piston_on",
627 nodenames = {"redstone:sticky_piston_on"},
628 run_at_every_load = true,
629 action = function(pos)
630 redstone.inject(pos,{
631 name = "redstone:sticky_piston_on",
634 --redstone needs to warm up
635 minetest.after(0,function()
641 redstone.register_activator({
642 name = "redstone:sticky_piston_on",
643 deactivate = function(pos)
644 --this is where the piston deactivates
645 local facedir = minetest.get_node(pos).param2
646 local dir = minetest.facedir_to_dir(facedir)
647 local piston_location = vector.add(pos,dir)
649 minetest.remove_node(piston_location)
651 sticky_piston_pull_nodes(piston_location,dir)
652 minetest.swap_node(pos,{name="redstone:sticky_piston_off",param2=facedir})
654 minetest.sound_play("piston", {pos=pos,pitch=math.random(85,100)/100})
655 redstone.inject(pos,{
656 name = "redstone:sticky_piston_off",
664 █████╗ ██████╗ ███╗ ███╗
665 ██╔══██╗██╔══██╗████╗ ████║
666 ███████║██████╔╝██╔████╔██║
667 ██╔══██║██╔══██╗██║╚██╔╝██║
668 ██║ ██║██║ ██║██║ ╚═╝ ██║
669 ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝
674 minetest.register_node("redstone:sticky_actuator", {
675 description = "Piston Actuator",
676 tiles = {"wood.png","wood.png","wood.png","wood.png","sticky_piston.png","wood.png"},
677 drawtype = "nodebox",
679 paramtype2 = "facedir",
680 groups = {stone = 1, hard = 1, pickaxe = 1, hand = 4,pathable = 1},
681 sounds = main.stoneSound(),
682 drop = "redstone:piston_off",
686 --left front bottom right back top
687 {-0.5, -0.5, 0.2, 0.5, 0.5, 0.5}, --mover
688 {-0.15, -0.15, -0.9, 0.15, 0.15, 0.5}, --actuator
691 after_destruct = function(pos, oldnode)
692 local facedir = oldnode.param2
693 local dir = minetest.facedir_to_dir(facedir)
694 dir = vector.multiply(dir,-1)
695 local piston_location = vector.add(pos,dir)
696 minetest.remove_node(piston_location)