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 local function push_objects(pos,dir)
52 for _,object in ipairs(minetest.get_objects_inside_radius(pos,2)) do
54 if object:is_player() and object:get_hp() > 0 then
55 local pos2 = object:get_pos()
56 local compare = vector.subtract(pos2,pos)
57 local real_y = compare.y
58 compare = vector.abs(compare)
61 if compare.y <= 0.5 and compare.x < 0.8 and compare.z < 0.8 then
62 object:move_to(vector.add(dir,pos2))
63 object:add_player_velocity(vector.multiply(dir,20))
66 elseif dir.x ~=0 or dir.z ~= 0 then
67 if real_y <= 0.5 and real_y >= -1.6 and compare.x < 0.8 and compare.z < 0.8 then
68 object:move_to(vector.add(dir,pos2))
69 object:add_player_velocity(vector.multiply(dir,19))
72 elseif not object:is_player() and object:get_luaentity().name == "__builtin:falling_node" then
73 local pos2 = object:get_pos()
74 local compare = vector.subtract(pos2,pos)
75 local real_y = compare.y
76 compare = vector.abs(compare)
77 if compare.y <= 1.5 and compare.x <= 1.5 and compare.z <= 1.5 then
78 object:move_to(vector.add(dir,pos2))
79 object:add_velocity(vector.multiply(dir,20))
81 elseif not object:is_player() and object:get_luaentity().name == "__builtin:item" then
82 local pos2 = object:get_pos()
83 local compare = vector.subtract(pos2,pos)
84 local real_y = compare.y
85 compare = vector.abs(compare)
86 if compare.y <= 1 and compare.x <= 1 and compare.z <= 1 then
87 object:move_to(vector.add(dir,pos2))
88 object:add_velocity(vector.multiply(dir,20))
89 object:get_luaentity().poll_timer = 0
95 --this is how the piston pushes nodes
104 local function push_nodes(pos,dir)
108 index_pos = vector.add(vector.multiply(dir,i),pos)
109 node = minetest.get_node(index_pos)
111 def = minetest.registered_nodes[node.name]
113 push = ((excluded_mods[def.mod_origin] ~= true) and (excluded_nodes[name] ~= true))
116 push_objects(index_pos,dir)
118 if push and name ~= "air" then
120 index.pos = index_pos
122 index.param2 = param2
123 table.insert(move_index,index)
124 elseif name == "air" then
133 --check if room to move and objects in log
134 if space == true and next(move_index) then
135 if table.getn(move_index) == 1 and minetest.get_item_group(move_index[1].name, "falling_node") > 0 then
136 for i = 1,table.getn(move_index) do
137 move_index[i].pos = vector.add(move_index[i].pos,dir)
138 minetest.set_node(move_index[i].pos,{name="air"})
140 local obj = minetest.add_entity(vector.add(move_index[i].pos,dir), "__builtin:falling_node")
141 obj:get_luaentity():set_node({name=move_index[i].name})
142 obj:set_velocity(vector.multiply(dir,19))
145 for i = 1,table.getn(move_index) do
146 if move_index[i] then
147 if move_index[i].pos then
148 move_index[i].pos = vector.add(move_index[i].pos,dir)
149 minetest.set_node(move_index[i].pos,move_index[i])
150 minetest.check_for_falling(move_index[i].pos)
151 push_objects(move_index[i].pos,dir)
160 --this is the logic of the piston
163 local piston_location
165 local function actuator_arm_function(pos)
166 --this is where the piston activates
167 facedir = minetest.get_node(pos).param2
168 dir = minetest.facedir_to_dir(facedir)
169 piston_location = vector.add(pos,dir)
170 worked = push_nodes(pos,dir)
171 local node = minetest.get_node(vector.add(pos,dir)).name
173 if worked == true then
174 minetest.sound_play("piston", {pos=pos,pitch=math.random(85,100)/100})
175 minetest.set_node(piston_location,{name="redstone:actuator",param2=facedir})
176 minetest.swap_node(pos,{name="redstone:piston_on",param2=facedir})
178 redstone.inject(pos,{
179 name = "redstone:piston_on",
188 ██████╗ ███████╗███████╗
189 ██╔═══██╗██╔════╝██╔════╝
197 minetest.register_node("redstone:piston_off", {
198 description = "Piston",
199 tiles = {"redstone_piston.png","redstone_piston.png^[transformR180","redstone_piston.png^[transformR270","redstone_piston.png^[transformR90","wood.png","stone.png"},
200 paramtype2 = "facedir",
201 groups = {stone = 1, hard = 1, pickaxe = 1, hand = 4,pathable = 1,redstone_activation=1},
202 sounds = main.stoneSound(),
203 drop = "redstone:piston_off",
205 sunlight_propagates = true,
206 --reverse the direction to face the player
207 on_construct = function(pos)
208 redstone.inject(pos,{
209 name = "redstone:piston_off",
214 on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
215 local look = clicker: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})
221 after_place_node = function(pos, placer, itemstack, pointed_thing)
222 local look = placer:get_look_dir()
223 look = vector.multiply(look,-1)
224 local dir = minetest.dir_to_facedir(look, true)
225 minetest.swap_node(pos,{name="redstone:piston_off",param2=dir})
227 after_destruct = function(pos, oldnode)
228 redstone.inject(pos,nil)
232 redstone.register_activator({
233 name = "redstone:piston_off",
234 activate = function(pos)
235 minetest.after(0,function()
236 actuator_arm_function(pos)
241 minetest.register_lbm({
242 name = "redstone:piston_off",
243 nodenames = {"redstone:piston_off"},
244 run_at_every_load = true,
245 action = function(pos)
246 redstone.inject(pos,{
247 name = "redstone:piston_off",
250 --redstone needs to warm up
251 minetest.after(0,function()
267 minetest.register_node("redstone:piston_on", {
268 description = "Piston",
269 tiles = {"redstone_piston.png","redstone_piston.png^[transformR180","redstone_piston.png^[transformR270","redstone_piston.png^[transformR90","stone.png","stone.png"},
270 drawtype = "nodebox",
272 paramtype2 = "facedir",
273 groups = {stone = 1, hard = 1, pickaxe = 1, hand = 4,pathable = 1,redstone_activation=1},
274 sounds = main.stoneSound(),
275 drop = "redstone:piston_off",
279 --left front bottom right back top
280 {-0.5, -0.5, -0.5, 0.5, 0.5, 3/16},
283 after_destruct = function(pos, oldnode)
284 local facedir = oldnode.param2
285 local dir = minetest.facedir_to_dir(facedir)
286 local piston_location = vector.add(pos,dir)
287 minetest.remove_node(piston_location)
288 redstone.inject(pos,nil)
292 minetest.register_lbm({
293 name = "redstone:piston_on",
294 nodenames = {"redstone:piston_on"},
295 run_at_every_load = true,
296 action = function(pos)
297 redstone.inject(pos,{
298 name = "redstone:piston_on",
301 --redstone needs to warm up
302 minetest.after(0,function()
308 redstone.register_activator({
309 name = "redstone:piston_on",
310 deactivate = function(pos)
311 --this is where the piston deactivates
312 local facedir = minetest.get_node(pos).param2
313 local dir = minetest.facedir_to_dir(facedir)
314 local piston_location = vector.add(pos,dir)
315 minetest.remove_node(piston_location)
317 minetest.check_for_falling(piston_location)
319 minetest.swap_node(pos,{name="redstone:piston_off",param2=facedir})
320 piston_location.y = piston_location.y + 1
321 minetest.sound_play("piston", {pos=pos,pitch=math.random(85,100)/100})
322 redstone.inject(pos,{
323 name = "redstone:piston_off",
331 █████╗ ██████╗ ███╗ ███╗
332 ██╔══██╗██╔══██╗████╗ ████║
333 ███████║██████╔╝██╔████╔██║
334 ██╔══██║██╔══██╗██║╚██╔╝██║
335 ██║ ██║██║ ██║██║ ╚═╝ ██║
336 ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝
341 minetest.register_node("redstone:actuator", {
342 description = "Piston Actuator",
343 tiles = {"wood.png"},
344 drawtype = "nodebox",
346 paramtype2 = "facedir",
347 groups = {stone = 1, hard = 1, pickaxe = 1, hand = 4,pathable = 1},
348 sounds = main.stoneSound(),
349 drop = "redstone:piston_off",
353 --left front bottom right back top
354 {-0.5, -0.5, 0.2, 0.5, 0.5, 0.5}, --mover
355 {-0.15, -0.15, -0.9, 0.15, 0.15, 0.5}, --actuator
358 after_destruct = function(pos, oldnode)
359 local facedir = oldnode.param2
360 local dir = minetest.facedir_to_dir(facedir)
361 dir = vector.multiply(dir,-1)
362 local piston_location = vector.add(pos,dir)
363 minetest.remove_node(piston_location)
372 ███████╗████████╗██╗ ██████╗██╗ ██╗██╗ ██╗ ██████╗ ██╗███████╗████████╗ ██████╗ ███╗ ██╗ ██████╗ ███████╗ ██████╗ ██╗███╗ ██╗███████╗
373 ██╔════╝╚══██╔══╝██║██╔════╝██║ ██╔╝╚██╗ ██╔╝ ██╔══██╗██║██╔════╝╚══██╔══╝██╔═══██╗████╗ ██║ ██╔══██╗██╔════╝██╔════╝ ██║████╗ ██║██╔════╝
374 ███████╗ ██║ ██║██║ █████╔╝ ╚████╔╝ ██████╔╝██║███████╗ ██║ ██║ ██║██╔██╗ ██║ ██████╔╝█████╗ ██║ ███╗██║██╔██╗ ██║███████╗
375 ╚════██║ ██║ ██║██║ ██╔═██╗ ╚██╔╝ ██╔═══╝ ██║╚════██║ ██║ ██║ ██║██║╚██╗██║ ██╔══██╗██╔══╝ ██║ ██║██║██║╚██╗██║╚════██║
376 ███████║ ██║ ██║╚██████╗██║ ██╗ ██║ ██║ ██║███████║ ██║ ╚██████╔╝██║ ╚████║ ██████╔╝███████╗╚██████╔╝██║██║ ╚████║███████║
377 ╚══════╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚══════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═════╝ ╚══════╝ ╚═════╝ ╚═╝╚═╝ ╚═══╝╚══════╝
387 ███████╗██╗ ██╗███╗ ██╗ ██████╗████████╗██╗ ██████╗ ███╗ ██╗
388 ██╔════╝██║ ██║████╗ ██║██╔════╝╚══██╔══╝██║██╔═══██╗████╗ ██║
389 █████╗ ██║ ██║██╔██╗ ██║██║ ██║ ██║██║ ██║██╔██╗ ██║
390 ██╔══╝ ██║ ██║██║╚██╗██║██║ ██║ ██║██║ ██║██║╚██╗██║
391 ██║ ╚██████╔╝██║ ╚████║╚██████╗ ██║ ██║╚██████╔╝██║ ╚████║
392 ╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝
397 local function sticky_push_objects(pos,dir)
399 for _,object in ipairs(minetest.get_objects_inside_radius(pos, 2)) do
400 if object:is_player() and object:get_hp() > 0 then
401 local pos2 = object:get_pos()
402 local compare = vector.subtract(pos2,pos)
403 local real_y = compare.y
404 compare = vector.abs(compare)
407 if compare.y <= 0.5 and compare.x < 0.8 and compare.z < 0.8 then
408 object:move_to(vector.add(dir,pos2))
411 elseif dir.x ~=0 or dir.z ~= 0 then
412 if real_y <= 0.5 and real_y >= -1.6 and compare.x < 0.8 and compare.z < 0.8 then
413 object:move_to(vector.add(dir,pos2))
416 elseif not object:is_player() and object:get_luaentity().name == "__builtin:falling_node" then
417 local pos2 = object:get_pos()
418 local compare = vector.subtract(pos2,pos)
419 local real_y = compare.y
420 compare = vector.abs(compare)
421 if compare.y <= 1.5 and compare.x <= 1.5 and compare.z <= 1.5 then
422 object:move_to(vector.add(dir,pos2))
424 elseif not object:is_player() and object:get_luaentity().name == "__builtin:item" then
425 local pos2 = object:get_pos()
426 local compare = vector.subtract(pos2,pos)
427 local real_y = compare.y
428 compare = vector.abs(compare)
429 if compare.y <= 1 and compare.x <= 1 and compare.z <= 1 then
430 object:move_to(vector.add(dir,pos2))
431 object:get_luaentity().poll_timer = 0
438 --this is how the piston pushes nodes
447 local function sticky_push_nodes(pos,dir)
451 index_pos = vector.add(vector.multiply(dir,i),pos)
452 node = minetest.get_node(index_pos)
454 def = minetest.registered_nodes[node.name]
456 push = ((excluded_mods[def.mod_origin] ~= true) and (excluded_nodes[name] ~= true))
458 sticky_push_objects(index_pos,dir)
460 if push and name ~= "air" then
462 index.pos = index_pos
464 index.param2 = param2
465 table.insert(move_index,index)
466 elseif name == "air" then
475 --check if room to move and objects in log
476 if space == true and next(move_index) then
478 for i = 1,table.getn(move_index) do
479 move_index[i].pos = vector.add(move_index[i].pos,dir)
480 minetest.set_node(move_index[i].pos,move_index[i])
481 minetest.check_for_falling(move_index[i].pos)
482 sticky_push_objects(move_index[i].pos,dir)
488 --this is the logic of the piston
491 local piston_location
493 local function sticky_actuator_arm_function(pos)
494 --this is where the piston activates
495 facedir = minetest.get_node(pos).param2
496 dir = minetest.facedir_to_dir(facedir)
497 piston_location = vector.add(pos,dir)
498 worked = sticky_push_nodes(pos,dir)
499 local node = minetest.get_node(vector.add(pos,dir)).name
501 if worked == true then
503 minetest.sound_play("piston", {pos=pos,pitch=math.random(85,100)/100})
504 minetest.set_node(piston_location,{name="redstone:sticky_actuator",param2=facedir})
505 minetest.swap_node(pos,{name="redstone:sticky_piston_on",param2=facedir})
507 redstone.inject(pos,{
508 name = "redstone:sticky_piston_on",
518 ██████╗ ███████╗███████╗
519 ██╔═══██╗██╔════╝██╔════╝
527 minetest.register_node("redstone:sticky_piston_off", {
528 description = "Sticky Piston",
529 tiles = {"redstone_piston.png","redstone_piston.png^[transformR180","redstone_piston.png^[transformR270","redstone_piston.png^[transformR90","sticky_piston.png","stone.png"},
530 paramtype2 = "facedir",
531 groups = {stone = 1, hard = 1, pickaxe = 1, hand = 4,pathable = 1,redstone_activation=1},
532 sounds = main.stoneSound(),
533 drop = "redstone:sticky_piston_off",
535 sunlight_propagates = true,
536 on_construct = function(pos)
537 redstone.inject(pos,{
538 name = "redstone:sticky_piston_off",
543 on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
544 local look = clicker:get_look_dir()
545 look = vector.multiply(look,-1)
546 local dir = minetest.dir_to_facedir(look, true)
547 minetest.swap_node(pos,{name="redstone:sticky_piston_off",param2=dir})
550 --reverse the direction to face the player
551 after_place_node = function(pos, placer, itemstack, pointed_thing)
552 local look = placer:get_look_dir()
553 look = vector.multiply(look,-1)
554 local dir = minetest.dir_to_facedir(look, true)
555 minetest.swap_node(pos,{name="redstone:sticky_piston_off",param2=dir})
557 after_destruct = function(pos, oldnode)
558 redstone.inject(pos,nil)
563 redstone.register_activator({
564 name = "redstone:sticky_piston_off",
565 activate = function(pos)
566 minetest.after(0,function()
567 sticky_actuator_arm_function(pos)
572 minetest.register_lbm({
573 name = "redstone:sticky_piston_off",
574 nodenames = {"redstone:sticky_piston_off"},
575 run_at_every_load = true,
576 action = function(pos)
577 redstone.inject(pos,{
578 name = "redstone:sticky_piston_off",
581 --redstone needs to warm up
582 minetest.after(0,function()
598 local function sticky_piston_pull_nodes(pos,dir)
599 local move_index = {}
600 local index_pos = vector.add(pos,dir)
602 local node = minetest.get_node(index_pos)
603 local param2 = node.param2
604 local def = minetest.registered_nodes[node.name]
605 local name = node.name
606 local pull = ((excluded_mods[def.mod_origin] ~= true) and (excluded_nodes[name] ~= true))
607 --if it can be pulled pull it
608 if pull and name ~= "air" then
609 minetest.remove_node(index_pos)
610 minetest.set_node(pos,{name=name,param2=param2})
611 minetest.check_for_falling(index_pos)
618 minetest.register_node("redstone:sticky_piston_on", {
619 description = "Sticky Piston",
620 tiles = {"redstone_piston.png","redstone_piston.png^[transformR180","redstone_piston.png^[transformR270","redstone_piston.png^[transformR90","stone.png","stone.png"},
621 drawtype = "nodebox",
623 paramtype2 = "facedir",
624 groups = {stone = 1, hard = 1, pickaxe = 1, hand = 4,pathable = 1,redstone_activation=1},
625 sounds = main.stoneSound(),
626 drop = "redstone:sticky_piston_off",
630 --left front bottom right back top
631 {-0.5, -0.5, -0.5, 0.5, 0.5, 3/16},
634 after_destruct = function(pos, oldnode)
635 local facedir = oldnode.param2
636 local dir = minetest.facedir_to_dir(facedir)
637 local piston_location = vector.add(pos,dir)
638 minetest.remove_node(piston_location)
639 redstone.inject(pos,nil)
643 minetest.register_lbm({
644 name = "redstone:sticky_piston_on",
645 nodenames = {"redstone:sticky_piston_on"},
646 run_at_every_load = true,
647 action = function(pos)
648 redstone.inject(pos,{
649 name = "redstone:sticky_piston_on",
652 --redstone needs to warm up
653 minetest.after(0,function()
659 redstone.register_activator({
660 name = "redstone:sticky_piston_on",
661 deactivate = function(pos)
662 --this is where the piston deactivates
663 local facedir = minetest.get_node(pos).param2
664 local dir = minetest.facedir_to_dir(facedir)
665 local piston_location = vector.add(pos,dir)
667 minetest.remove_node(piston_location)
669 sticky_piston_pull_nodes(piston_location,dir)
671 minetest.check_for_falling(piston_location)
673 minetest.swap_node(pos,{name="redstone:sticky_piston_off",param2=facedir})
675 minetest.sound_play("piston", {pos=pos,pitch=math.random(85,100)/100})
676 redstone.inject(pos,{
677 name = "redstone:sticky_piston_off",
685 █████╗ ██████╗ ███╗ ███╗
686 ██╔══██╗██╔══██╗████╗ ████║
687 ███████║██████╔╝██╔████╔██║
688 ██╔══██║██╔══██╗██║╚██╔╝██║
689 ██║ ██║██║ ██║██║ ╚═╝ ██║
690 ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝
695 minetest.register_node("redstone:sticky_actuator", {
696 description = "Piston Actuator",
697 tiles = {"wood.png","wood.png","wood.png","wood.png","sticky_piston.png","wood.png"},
698 drawtype = "nodebox",
700 paramtype2 = "facedir",
701 groups = {stone = 1, hard = 1, pickaxe = 1, hand = 4,pathable = 1},
702 sounds = main.stoneSound(),
703 drop = "redstone:piston_off",
707 --left front bottom right back top
708 {-0.5, -0.5, 0.2, 0.5, 0.5, 0.5}, --mover
709 {-0.15, -0.15, -0.9, 0.15, 0.15, 0.5}, --actuator
712 after_destruct = function(pos, oldnode)
713 local facedir = oldnode.param2
714 local dir = minetest.facedir_to_dir(facedir)
715 dir = vector.multiply(dir,-1)
716 local piston_location = vector.add(pos,dir)
717 minetest.remove_node(piston_location)