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
97 move_index[i].pos = vector.add(move_index[i].pos,dir)
98 minetest.set_node(move_index[i].pos,move_index[i])
99 minetest.check_for_falling(move_index[i].pos)
106 --this is the logic of the piston
109 local piston_location
111 local function actuator_arm_function(pos)
112 --this is where the piston activates
113 facedir = minetest.get_node(pos).param2
114 dir = minetest.facedir_to_dir(facedir)
115 piston_location = vector.add(pos,dir)
116 worked = push_nodes(pos,dir)
117 local node = minetest.get_node(vector.add(pos,dir)).name
119 if worked == true then
121 if node == "air" then
122 for _,object in ipairs(minetest.get_objects_inside_radius(piston_location, 2)) do
124 if object:is_player() and object:get_hp() > 0 then
125 local pos2 = object:get_pos()
126 local compare = vector.subtract(pos2,piston_location)
127 local real_y = compare.y
128 compare = vector.abs(compare)
131 if compare.y <= 0.5 and compare.x < 0.8 and compare.z < 0.8 then
132 object:move_to(vector.add(dir,pos2))
133 object:add_player_velocity(vector.multiply(dir,20))
136 elseif dir.x ~=0 or dir.z ~= 0 then
137 if real_y <= 0.5 and real_y >= -1.6 and compare.x < 0.8 and compare.z < 0.8 then
138 object:move_to(vector.add(dir,pos2))
139 object:add_player_velocity(vector.multiply(dir,19))
142 elseif not object:is_player() and object:get_luaentity().name == "__builtin:falling_node" then
143 local pos2 = object:get_pos()
144 local compare = vector.subtract(pos2,piston_location)
145 local real_y = compare.y
146 compare = vector.abs(compare)
147 if compare.y <= 1.5 and compare.x <= 1.5 and compare.z <= 1.5 then
148 object:move_to(vector.add(dir,pos2))
149 object:add_velocity(vector.multiply(dir,20))
151 elseif not object:is_player() and object:get_luaentity().name == "__builtin:item" then
152 local pos2 = object:get_pos()
153 local compare = vector.subtract(pos2,piston_location)
154 local real_y = compare.y
155 compare = vector.abs(compare)
156 if compare.y <= 1 and compare.x <= 1 and compare.z <= 1 then
157 object:move_to(vector.add(dir,pos2))
158 object:add_velocity(vector.multiply(dir,20))
159 object:get_luaentity().poll_timer = 0
164 minetest.sound_play("piston", {pos=pos,pitch=math.random(85,100)/100})
165 minetest.set_node(piston_location,{name="redstone:actuator",param2=facedir})
166 minetest.swap_node(pos,{name="redstone:piston_on",param2=facedir})
168 redstone.inject(pos,{
169 name = "redstone:piston_on",
172 minetest.after(0,function()
180 ██████╗ ███████╗███████╗
181 ██╔═══██╗██╔════╝██╔════╝
189 minetest.register_node("redstone:piston_off", {
190 description = "Piston",
191 tiles = {"redstone_piston.png","redstone_piston.png^[transformR180","redstone_piston.png^[transformR270","redstone_piston.png^[transformR90","wood.png","stone.png"},
192 paramtype2 = "facedir",
193 groups = {stone = 1, hard = 1, pickaxe = 1, hand = 4,pathable = 1,redstone_activation=1},
194 sounds = main.stoneSound(),
195 drop = "redstone:piston_off",
197 sunlight_propagates = true,
198 --reverse the direction to face the player
199 after_place_node = function(pos, placer, itemstack, pointed_thing)
200 local look = placer:get_look_dir()
201 look = vector.multiply(look,-1)
202 local dir = minetest.dir_to_facedir(look, true)
203 minetest.swap_node(pos,{name="redstone:piston_off",param2=dir})
204 redstone.inject(pos,{
205 name = "redstone:piston_off",
210 after_destruct = function(pos, oldnode)
211 redstone.inject(pos,nil)
216 redstone.register_activator({
217 name = "redstone:piston_off",
218 activate = function(pos)
219 actuator_arm_function(pos)
223 minetest.register_lbm({
224 name = "redstone:piston_off",
225 nodenames = {"redstone:piston_off"},
226 run_at_every_load = true,
227 action = function(pos)
228 redstone.inject(pos,{
229 name = "redstone:piston_off",
232 minetest.after(0,function()
248 minetest.register_node("redstone:piston_on", {
249 description = "Piston",
250 tiles = {"redstone_piston.png","redstone_piston.png^[transformR180","redstone_piston.png^[transformR270","redstone_piston.png^[transformR90","stone.png","stone.png"},
251 drawtype = "nodebox",
253 paramtype2 = "facedir",
254 groups = {stone = 1, hard = 1, pickaxe = 1, hand = 4,pathable = 1,redstone_activation=1},
255 sounds = main.stoneSound(),
256 drop = "redstone:piston_off",
260 --left front bottom right back top
261 {-0.5, -0.5, -0.5, 0.5, 0.5, 3/16},
264 after_destruct = function(pos, oldnode)
265 local facedir = oldnode.param2
266 local dir = minetest.facedir_to_dir(facedir)
267 local piston_location = vector.add(pos,dir)
268 minetest.remove_node(piston_location)
269 redstone.inject(pos,nil)
273 minetest.register_lbm({
274 name = "redstone:piston_on",
275 nodenames = {"redstone:piston_on"},
276 run_at_every_load = true,
277 action = function(pos)
278 redstone.inject(pos,{
279 name = "redstone:piston_on",
282 minetest.after(0,function()
288 redstone.register_activator({
289 name = "redstone:piston_on",
290 deactivate = function(pos)
291 --this is where the piston deactivates
292 local facedir = minetest.get_node(pos).param2
293 local dir = minetest.facedir_to_dir(facedir)
294 local piston_location = vector.add(pos,dir)
295 minetest.remove_node(piston_location)
296 minetest.swap_node(pos,{name="redstone:piston_off",param2=facedir})
297 piston_location.y = piston_location.y + 1
298 minetest.sound_play("piston", {pos=pos,pitch=math.random(85,100)/100})
299 redstone.inject(pos,{
300 name = "redstone:piston_off",
308 █████╗ ██████╗ ███╗ ███╗
309 ██╔══██╗██╔══██╗████╗ ████║
310 ███████║██████╔╝██╔████╔██║
311 ██╔══██║██╔══██╗██║╚██╔╝██║
312 ██║ ██║██║ ██║██║ ╚═╝ ██║
313 ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝
318 minetest.register_node("redstone:actuator", {
319 description = "Piston Actuator",
320 tiles = {"wood.png"},
321 drawtype = "nodebox",
323 paramtype2 = "facedir",
324 groups = {stone = 1, hard = 1, pickaxe = 1, hand = 4,pathable = 1},
325 sounds = main.stoneSound(),
326 drop = "redstone:piston_off",
330 --left front bottom right back top
331 {-0.5, -0.5, 0.2, 0.5, 0.5, 0.5}, --mover
332 {-0.15, -0.15, -0.9, 0.15, 0.15, 0.5}, --actuator
335 after_destruct = function(pos, oldnode)
336 local facedir = oldnode.param2
337 local dir = minetest.facedir_to_dir(facedir)
338 dir = vector.multiply(dir,-1)
339 local piston_location = vector.add(pos,dir)
340 minetest.remove_node(piston_location)
349 ███████╗████████╗██╗ ██████╗██╗ ██╗██╗ ██╗ ██████╗ ██╗███████╗████████╗ ██████╗ ███╗ ██╗ ██████╗ ███████╗ ██████╗ ██╗███╗ ██╗███████╗
350 ██╔════╝╚══██╔══╝██║██╔════╝██║ ██╔╝╚██╗ ██╔╝ ██╔══██╗██║██╔════╝╚══██╔══╝██╔═══██╗████╗ ██║ ██╔══██╗██╔════╝██╔════╝ ██║████╗ ██║██╔════╝
351 ███████╗ ██║ ██║██║ █████╔╝ ╚████╔╝ ██████╔╝██║███████╗ ██║ ██║ ██║██╔██╗ ██║ ██████╔╝█████╗ ██║ ███╗██║██╔██╗ ██║███████╗
352 ╚════██║ ██║ ██║██║ ██╔═██╗ ╚██╔╝ ██╔═══╝ ██║╚════██║ ██║ ██║ ██║██║╚██╗██║ ██╔══██╗██╔══╝ ██║ ██║██║██║╚██╗██║╚════██║
353 ███████║ ██║ ██║╚██████╗██║ ██╗ ██║ ██║ ██║███████║ ██║ ╚██████╔╝██║ ╚████║ ██████╔╝███████╗╚██████╔╝██║██║ ╚████║███████║
354 ╚══════╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚══════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═════╝ ╚══════╝ ╚═════╝ ╚═╝╚═╝ ╚═══╝╚══════╝
364 ███████╗██╗ ██╗███╗ ██╗ ██████╗████████╗██╗ ██████╗ ███╗ ██╗
365 ██╔════╝██║ ██║████╗ ██║██╔════╝╚══██╔══╝██║██╔═══██╗████╗ ██║
366 █████╗ ██║ ██║██╔██╗ ██║██║ ██║ ██║██║ ██║██╔██╗ ██║
367 ██╔══╝ ██║ ██║██║╚██╗██║██║ ██║ ██║██║ ██║██║╚██╗██║
368 ██║ ╚██████╔╝██║ ╚████║╚██████╗ ██║ ██║╚██████╔╝██║ ╚████║
369 ╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝
373 --this is how the piston pushes nodes
382 local function sticky_push_nodes(pos,dir)
386 index_pos = vector.add(vector.multiply(dir,i),pos)
387 node = minetest.get_node(index_pos)
389 def = minetest.registered_nodes[node.name]
391 push = ((excluded_mods[def.mod_origin] ~= true) and (excluded_nodes[name] ~= true))
392 if push and name ~= "air" then
394 index.pos = index_pos
396 index.param2 = param2
397 table.insert(move_index,index)
398 elseif name == "air" then
407 --check if room to move and objects in log
408 if space == true and next(move_index) then
409 for i = 1,table.getn(move_index) do
410 move_index[i].pos = vector.add(move_index[i].pos,dir)
411 minetest.set_node(move_index[i].pos,move_index[i])
412 minetest.check_for_falling(move_index[i].pos)
418 --this is the logic of the piston
421 local piston_location
423 local function sticky_actuator_arm_function(pos)
424 --this is where the piston activates
425 facedir = minetest.get_node(pos).param2
426 dir = minetest.facedir_to_dir(facedir)
427 piston_location = vector.add(pos,dir)
428 worked = sticky_push_nodes(pos,dir)
429 local node = minetest.get_node(vector.add(pos,dir)).name
431 if worked == true then
433 if node == "air" then
434 for _,object in ipairs(minetest.get_objects_inside_radius(piston_location, 2)) do
436 if object:is_player() and object:get_hp() > 0 then
437 local pos2 = object:get_pos()
438 local compare = vector.subtract(pos2,piston_location)
439 local real_y = compare.y
440 compare = vector.abs(compare)
443 if compare.y <= 0.5 and compare.x < 0.8 and compare.z < 0.8 then
444 object:move_to(vector.add(dir,pos2))
447 elseif dir.x ~=0 or dir.z ~= 0 then
448 if real_y <= 0.5 and real_y >= -1.6 and compare.x < 0.8 and compare.z < 0.8 then
449 object:move_to(vector.add(dir,pos2))
452 elseif not object:is_player() and object:get_luaentity().name == "__builtin:falling_node" then
453 local pos2 = object:get_pos()
454 local compare = vector.subtract(pos2,piston_location)
455 local real_y = compare.y
456 compare = vector.abs(compare)
457 if compare.y <= 1.5 and compare.x <= 1.5 and compare.z <= 1.5 then
458 object:move_to(vector.add(dir,pos2))
460 elseif not object:is_player() and object:get_luaentity().name == "__builtin:item" then
461 local pos2 = object:get_pos()
462 local compare = vector.subtract(pos2,piston_location)
463 local real_y = compare.y
464 compare = vector.abs(compare)
465 if compare.y <= 1 and compare.x <= 1 and compare.z <= 1 then
466 object:move_to(vector.add(dir,pos2))
467 object:get_luaentity().poll_timer = 0
472 minetest.sound_play("piston", {pos=pos,pitch=math.random(85,100)/100})
473 minetest.set_node(piston_location,{name="redstone:sticky_actuator",param2=facedir})
474 minetest.swap_node(pos,{name="redstone:sticky_piston_on",param2=facedir})
476 redstone.inject(pos,{
477 name = "redstone:sticky_piston_on",
480 minetest.after(0,function()
488 ██████╗ ███████╗███████╗
489 ██╔═══██╗██╔════╝██╔════╝
497 minetest.register_node("redstone:sticky_piston_off", {
498 description = "Sticky Piston",
499 tiles = {"redstone_piston.png","redstone_piston.png^[transformR180","redstone_piston.png^[transformR270","redstone_piston.png^[transformR90","sticky_piston.png","stone.png"},
500 paramtype2 = "facedir",
501 groups = {stone = 1, hard = 1, pickaxe = 1, hand = 4,pathable = 1,redstone_activation=1},
502 sounds = main.stoneSound(),
503 drop = "redstone:sticky_piston_off",
505 sunlight_propagates = true,
506 --reverse the direction to face the player
507 after_place_node = function(pos, placer, itemstack, pointed_thing)
508 local look = placer:get_look_dir()
509 look = vector.multiply(look,-1)
510 local dir = minetest.dir_to_facedir(look, true)
511 minetest.swap_node(pos,{name="redstone:sticky_piston_off",param2=dir})
512 redstone.inject(pos,{
513 name = "redstone:sticky_piston_off",
518 after_destruct = function(pos, oldnode)
519 redstone.inject(pos,nil)
524 redstone.register_activator({
525 name = "redstone:sticky_piston_off",
526 activate = function(pos)
527 sticky_actuator_arm_function(pos)
531 minetest.register_lbm({
532 name = "redstone:sticky_piston_off",
533 nodenames = {"redstone:sticky_piston_off"},
534 run_at_every_load = true,
535 action = function(pos)
536 redstone.inject(pos,{
537 name = "redstone:sticky_piston_off",
540 minetest.after(0,function()
556 local function sticky_piston_pull_nodes(pos,dir)
557 local move_index = {}
558 local index_pos = vector.add(pos,dir)
560 local node = minetest.get_node(index_pos)
561 local param2 = node.param2
562 local def = minetest.registered_nodes[node.name]
563 local name = node.name
564 local pull = ((excluded_mods[def.mod_origin] ~= true) and (excluded_nodes[name] ~= true))
565 --if it can be pulled pull it
566 if pull and name ~= "air" then
567 minetest.remove_node(index_pos)
568 minetest.set_node(pos,{name=name,param2=param2})
575 minetest.register_node("redstone:sticky_piston_on", {
576 description = "Sticky Piston",
577 tiles = {"redstone_piston.png","redstone_piston.png^[transformR180","redstone_piston.png^[transformR270","redstone_piston.png^[transformR90","stone.png","stone.png"},
578 drawtype = "nodebox",
580 paramtype2 = "facedir",
581 groups = {stone = 1, hard = 1, pickaxe = 1, hand = 4,pathable = 1,redstone_activation=1},
582 sounds = main.stoneSound(),
583 drop = "redstone:sticky_piston_off",
587 --left front bottom right back top
588 {-0.5, -0.5, -0.5, 0.5, 0.5, 3/16},
591 after_destruct = function(pos, oldnode)
592 local facedir = oldnode.param2
593 local dir = minetest.facedir_to_dir(facedir)
594 local piston_location = vector.add(pos,dir)
595 minetest.remove_node(piston_location)
596 redstone.inject(pos,nil)
600 minetest.register_lbm({
601 name = "redstone:sticky_piston_on",
602 nodenames = {"redstone:sticky_piston_on"},
603 run_at_every_load = true,
604 action = function(pos)
605 redstone.inject(pos,{
606 name = "redstone:sticky_piston_on",
609 minetest.after(0,function()
615 redstone.register_activator({
616 name = "redstone:sticky_piston_on",
617 deactivate = function(pos)
618 --this is where the piston deactivates
619 local facedir = minetest.get_node(pos).param2
620 local dir = minetest.facedir_to_dir(facedir)
621 local piston_location = vector.add(pos,dir)
623 minetest.remove_node(piston_location)
625 sticky_piston_pull_nodes(piston_location,dir)
626 minetest.swap_node(pos,{name="redstone:sticky_piston_off",param2=facedir})
628 minetest.sound_play("piston", {pos=pos,pitch=math.random(85,100)/100})
629 redstone.inject(pos,{
630 name = "redstone:sticky_piston_off",
638 █████╗ ██████╗ ███╗ ███╗
639 ██╔══██╗██╔══██╗████╗ ████║
640 ███████║██████╔╝██╔████╔██║
641 ██╔══██║██╔══██╗██║╚██╔╝██║
642 ██║ ██║██║ ██║██║ ╚═╝ ██║
643 ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝
648 minetest.register_node("redstone:sticky_actuator", {
649 description = "Piston Actuator",
650 tiles = {"wood.png","wood.png","wood.png","wood.png","sticky_piston.png","wood.png"},
651 drawtype = "nodebox",
653 paramtype2 = "facedir",
654 groups = {stone = 1, hard = 1, pickaxe = 1, hand = 4,pathable = 1},
655 sounds = main.stoneSound(),
656 drop = "redstone:piston_off",
660 --left front bottom right back top
661 {-0.5, -0.5, 0.2, 0.5, 0.5, 0.5}, --mover
662 {-0.15, -0.15, -0.9, 0.15, 0.15, 0.5}, --actuator
665 after_destruct = function(pos, oldnode)
666 local facedir = oldnode.param2
667 local dir = minetest.facedir_to_dir(facedir)
668 dir = vector.multiply(dir,-1)
669 local piston_location = vector.add(pos,dir)
670 minetest.remove_node(piston_location)