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
89 move_index[i].pos = vector.add(move_index[i].pos,dir)
90 minetest.set_node(move_index[i].pos,{name="air"})
92 local obj = minetest.add_entity(vector.add(move_index[i].pos,dir), "__builtin:falling_node")
93 obj:get_luaentity():set_node({name=move_index[i].name})
94 obj:set_velocity(vector.multiply(dir,19))
97 for i = 1,table.getn(move_index) do
98 move_index[i].pos = vector.add(move_index[i].pos,dir)
99 minetest.set_node(move_index[i].pos,move_index[i])
100 minetest.check_for_falling(move_index[i].pos)
107 --this is the logic of the piston
110 local piston_location
112 local function actuator_arm_function(pos)
113 --this is where the piston activates
114 facedir = minetest.get_node(pos).param2
115 dir = minetest.facedir_to_dir(facedir)
116 piston_location = vector.add(pos,dir)
117 worked = push_nodes(pos,dir)
118 local node = minetest.get_node(vector.add(pos,dir)).name
120 if worked == true then
122 if node == "air" then
123 for _,object in ipairs(minetest.get_objects_inside_radius(piston_location, 2)) do
125 if object:is_player() and object:get_hp() > 0 then
126 local pos2 = object:get_pos()
127 local compare = vector.subtract(pos2,piston_location)
128 local real_y = compare.y
129 compare = vector.abs(compare)
132 if compare.y <= 0.5 and compare.x < 0.8 and compare.z < 0.8 then
133 object:move_to(vector.add(dir,pos2))
134 object:add_player_velocity(vector.multiply(dir,20))
137 elseif dir.x ~=0 or dir.z ~= 0 then
138 if real_y <= 0.5 and real_y >= -1.6 and compare.x < 0.8 and compare.z < 0.8 then
139 object:move_to(vector.add(dir,pos2))
140 object:add_player_velocity(vector.multiply(dir,19))
143 elseif not object:is_player() and object:get_luaentity().name == "__builtin:falling_node" then
144 local pos2 = object:get_pos()
145 local compare = vector.subtract(pos2,piston_location)
146 local real_y = compare.y
147 compare = vector.abs(compare)
148 if compare.y <= 1.5 and compare.x <= 1.5 and compare.z <= 1.5 then
149 object:move_to(vector.add(dir,pos2))
150 object:add_velocity(vector.multiply(dir,20))
152 elseif not object:is_player() and object:get_luaentity().name == "__builtin:item" then
153 local pos2 = object:get_pos()
154 local compare = vector.subtract(pos2,piston_location)
155 local real_y = compare.y
156 compare = vector.abs(compare)
157 if compare.y <= 1 and compare.x <= 1 and compare.z <= 1 then
158 object:move_to(vector.add(dir,pos2))
159 object:add_velocity(vector.multiply(dir,20))
160 object:get_luaentity().poll_timer = 0
165 minetest.sound_play("piston", {pos=pos,pitch=math.random(85,100)/100})
166 minetest.set_node(piston_location,{name="redstone:actuator",param2=facedir})
167 minetest.swap_node(pos,{name="redstone:piston_on",param2=facedir})
169 redstone.inject(pos,{
170 name = "redstone:piston_on",
173 minetest.after(0,function()
181 ██████╗ ███████╗███████╗
182 ██╔═══██╗██╔════╝██╔════╝
190 minetest.register_node("redstone:piston_off", {
191 description = "Piston",
192 tiles = {"redstone_piston.png","redstone_piston.png^[transformR180","redstone_piston.png^[transformR270","redstone_piston.png^[transformR90","wood.png","stone.png"},
193 paramtype2 = "facedir",
194 groups = {stone = 1, hard = 1, pickaxe = 1, hand = 4,pathable = 1,redstone_activation=1},
195 sounds = main.stoneSound(),
196 drop = "redstone:piston_off",
198 sunlight_propagates = true,
199 --reverse the direction to face the player
200 after_place_node = function(pos, placer, itemstack, pointed_thing)
201 local look = placer:get_look_dir()
202 look = vector.multiply(look,-1)
203 local dir = minetest.dir_to_facedir(look, true)
204 minetest.swap_node(pos,{name="redstone:piston_off",param2=dir})
205 redstone.inject(pos,{
206 name = "redstone:piston_off",
211 after_destruct = function(pos, oldnode)
212 redstone.inject(pos,nil)
217 redstone.register_activator({
218 name = "redstone:piston_off",
219 activate = function(pos)
220 actuator_arm_function(pos)
224 minetest.register_lbm({
225 name = "redstone:piston_off",
226 nodenames = {"redstone:piston_off"},
227 run_at_every_load = true,
228 action = function(pos)
229 redstone.inject(pos,{
230 name = "redstone:piston_off",
233 minetest.after(0,function()
249 minetest.register_node("redstone:piston_on", {
250 description = "Piston",
251 tiles = {"redstone_piston.png","redstone_piston.png^[transformR180","redstone_piston.png^[transformR270","redstone_piston.png^[transformR90","stone.png","stone.png"},
252 drawtype = "nodebox",
254 paramtype2 = "facedir",
255 groups = {stone = 1, hard = 1, pickaxe = 1, hand = 4,pathable = 1,redstone_activation=1},
256 sounds = main.stoneSound(),
257 drop = "redstone:piston_off",
261 --left front bottom right back top
262 {-0.5, -0.5, -0.5, 0.5, 0.5, 3/16},
265 after_destruct = function(pos, oldnode)
266 local facedir = oldnode.param2
267 local dir = minetest.facedir_to_dir(facedir)
268 local piston_location = vector.add(pos,dir)
269 minetest.remove_node(piston_location)
270 redstone.inject(pos,nil)
274 minetest.register_lbm({
275 name = "redstone:piston_on",
276 nodenames = {"redstone:piston_on"},
277 run_at_every_load = true,
278 action = function(pos)
279 redstone.inject(pos,{
280 name = "redstone:piston_on",
283 minetest.after(0,function()
289 redstone.register_activator({
290 name = "redstone:piston_on",
291 deactivate = function(pos)
292 --this is where the piston deactivates
293 local facedir = minetest.get_node(pos).param2
294 local dir = minetest.facedir_to_dir(facedir)
295 local piston_location = vector.add(pos,dir)
296 minetest.remove_node(piston_location)
297 minetest.swap_node(pos,{name="redstone:piston_off",param2=facedir})
298 piston_location.y = piston_location.y + 1
299 minetest.sound_play("piston", {pos=pos,pitch=math.random(85,100)/100})
300 redstone.inject(pos,{
301 name = "redstone:piston_off",
309 █████╗ ██████╗ ███╗ ███╗
310 ██╔══██╗██╔══██╗████╗ ████║
311 ███████║██████╔╝██╔████╔██║
312 ██╔══██║██╔══██╗██║╚██╔╝██║
313 ██║ ██║██║ ██║██║ ╚═╝ ██║
314 ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝
319 minetest.register_node("redstone:actuator", {
320 description = "Piston Actuator",
321 tiles = {"wood.png"},
322 drawtype = "nodebox",
324 paramtype2 = "facedir",
325 groups = {stone = 1, hard = 1, pickaxe = 1, hand = 4,pathable = 1},
326 sounds = main.stoneSound(),
327 drop = "redstone:piston_off",
331 --left front bottom right back top
332 {-0.5, -0.5, 0.2, 0.5, 0.5, 0.5}, --mover
333 {-0.15, -0.15, -0.9, 0.15, 0.15, 0.5}, --actuator
336 after_destruct = function(pos, oldnode)
337 local facedir = oldnode.param2
338 local dir = minetest.facedir_to_dir(facedir)
339 dir = vector.multiply(dir,-1)
340 local piston_location = vector.add(pos,dir)
341 minetest.remove_node(piston_location)
350 ███████╗████████╗██╗ ██████╗██╗ ██╗██╗ ██╗ ██████╗ ██╗███████╗████████╗ ██████╗ ███╗ ██╗ ██████╗ ███████╗ ██████╗ ██╗███╗ ██╗███████╗
351 ██╔════╝╚══██╔══╝██║██╔════╝██║ ██╔╝╚██╗ ██╔╝ ██╔══██╗██║██╔════╝╚══██╔══╝██╔═══██╗████╗ ██║ ██╔══██╗██╔════╝██╔════╝ ██║████╗ ██║██╔════╝
352 ███████╗ ██║ ██║██║ █████╔╝ ╚████╔╝ ██████╔╝██║███████╗ ██║ ██║ ██║██╔██╗ ██║ ██████╔╝█████╗ ██║ ███╗██║██╔██╗ ██║███████╗
353 ╚════██║ ██║ ██║██║ ██╔═██╗ ╚██╔╝ ██╔═══╝ ██║╚════██║ ██║ ██║ ██║██║╚██╗██║ ██╔══██╗██╔══╝ ██║ ██║██║██║╚██╗██║╚════██║
354 ███████║ ██║ ██║╚██████╗██║ ██╗ ██║ ██║ ██║███████║ ██║ ╚██████╔╝██║ ╚████║ ██████╔╝███████╗╚██████╔╝██║██║ ╚████║███████║
355 ╚══════╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚══════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═════╝ ╚══════╝ ╚═════╝ ╚═╝╚═╝ ╚═══╝╚══════╝
365 ███████╗██╗ ██╗███╗ ██╗ ██████╗████████╗██╗ ██████╗ ███╗ ██╗
366 ██╔════╝██║ ██║████╗ ██║██╔════╝╚══██╔══╝██║██╔═══██╗████╗ ██║
367 █████╗ ██║ ██║██╔██╗ ██║██║ ██║ ██║██║ ██║██╔██╗ ██║
368 ██╔══╝ ██║ ██║██║╚██╗██║██║ ██║ ██║██║ ██║██║╚██╗██║
369 ██║ ╚██████╔╝██║ ╚████║╚██████╗ ██║ ██║╚██████╔╝██║ ╚████║
370 ╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝
374 --this is how the piston pushes nodes
383 local function sticky_push_nodes(pos,dir)
387 index_pos = vector.add(vector.multiply(dir,i),pos)
388 node = minetest.get_node(index_pos)
390 def = minetest.registered_nodes[node.name]
392 push = ((excluded_mods[def.mod_origin] ~= true) and (excluded_nodes[name] ~= true))
393 if push and name ~= "air" then
395 index.pos = index_pos
397 index.param2 = param2
398 table.insert(move_index,index)
399 elseif name == "air" then
408 --check if room to move and objects in log
409 if space == true and next(move_index) then
410 for i = 1,table.getn(move_index) do
411 move_index[i].pos = vector.add(move_index[i].pos,dir)
412 minetest.set_node(move_index[i].pos,move_index[i])
413 minetest.check_for_falling(move_index[i].pos)
419 --this is the logic of the piston
422 local piston_location
424 local function sticky_actuator_arm_function(pos)
425 --this is where the piston activates
426 facedir = minetest.get_node(pos).param2
427 dir = minetest.facedir_to_dir(facedir)
428 piston_location = vector.add(pos,dir)
429 worked = sticky_push_nodes(pos,dir)
430 local node = minetest.get_node(vector.add(pos,dir)).name
432 if worked == true then
434 if node == "air" then
435 for _,object in ipairs(minetest.get_objects_inside_radius(piston_location, 2)) do
437 if object:is_player() and object:get_hp() > 0 then
438 local pos2 = object:get_pos()
439 local compare = vector.subtract(pos2,piston_location)
440 local real_y = compare.y
441 compare = vector.abs(compare)
444 if compare.y <= 0.5 and compare.x < 0.8 and compare.z < 0.8 then
445 object:move_to(vector.add(dir,pos2))
448 elseif dir.x ~=0 or dir.z ~= 0 then
449 if real_y <= 0.5 and real_y >= -1.6 and compare.x < 0.8 and compare.z < 0.8 then
450 object:move_to(vector.add(dir,pos2))
453 elseif not object:is_player() and object:get_luaentity().name == "__builtin:falling_node" then
454 local pos2 = object:get_pos()
455 local compare = vector.subtract(pos2,piston_location)
456 local real_y = compare.y
457 compare = vector.abs(compare)
458 if compare.y <= 1.5 and compare.x <= 1.5 and compare.z <= 1.5 then
459 object:move_to(vector.add(dir,pos2))
461 elseif not object:is_player() and object:get_luaentity().name == "__builtin:item" then
462 local pos2 = object:get_pos()
463 local compare = vector.subtract(pos2,piston_location)
464 local real_y = compare.y
465 compare = vector.abs(compare)
466 if compare.y <= 1 and compare.x <= 1 and compare.z <= 1 then
467 object:move_to(vector.add(dir,pos2))
468 object:get_luaentity().poll_timer = 0
473 minetest.sound_play("piston", {pos=pos,pitch=math.random(85,100)/100})
474 minetest.set_node(piston_location,{name="redstone:sticky_actuator",param2=facedir})
475 minetest.swap_node(pos,{name="redstone:sticky_piston_on",param2=facedir})
477 redstone.inject(pos,{
478 name = "redstone:sticky_piston_on",
481 minetest.after(0,function()
489 ██████╗ ███████╗███████╗
490 ██╔═══██╗██╔════╝██╔════╝
498 minetest.register_node("redstone:sticky_piston_off", {
499 description = "Sticky Piston",
500 tiles = {"redstone_piston.png","redstone_piston.png^[transformR180","redstone_piston.png^[transformR270","redstone_piston.png^[transformR90","wood.png","stone.png"},
501 paramtype2 = "facedir",
502 groups = {stone = 1, hard = 1, pickaxe = 1, hand = 4,pathable = 1,redstone_activation=1},
503 sounds = main.stoneSound(),
504 drop = "redstone:sticky_piston_off",
506 sunlight_propagates = true,
507 --reverse the direction to face the player
508 after_place_node = function(pos, placer, itemstack, pointed_thing)
509 local look = placer:get_look_dir()
510 look = vector.multiply(look,-1)
511 local dir = minetest.dir_to_facedir(look, true)
512 minetest.swap_node(pos,{name="redstone:sticky_piston_off",param2=dir})
513 redstone.inject(pos,{
514 name = "redstone:sticky_piston_off",
519 after_destruct = function(pos, oldnode)
520 redstone.inject(pos,nil)
525 redstone.register_activator({
526 name = "redstone:sticky_piston_off",
527 activate = function(pos)
528 sticky_actuator_arm_function(pos)
532 minetest.register_lbm({
533 name = "redstone:sticky_piston_off",
534 nodenames = {"redstone:sticky_piston_off"},
535 run_at_every_load = true,
536 action = function(pos)
537 redstone.inject(pos,{
538 name = "redstone:sticky_piston_off",
541 minetest.after(0,function()
557 minetest.register_node("redstone:sticky_piston_on", {
558 description = "Sticky Piston",
559 tiles = {"redstone_piston.png","redstone_piston.png^[transformR180","redstone_piston.png^[transformR270","redstone_piston.png^[transformR90","stone.png","stone.png"},
560 drawtype = "nodebox",
562 paramtype2 = "facedir",
563 groups = {stone = 1, hard = 1, pickaxe = 1, hand = 4,pathable = 1,redstone_activation=1},
564 sounds = main.stoneSound(),
565 drop = "redstone:sticky_piston_off",
569 --left front bottom right back top
570 {-0.5, -0.5, -0.5, 0.5, 0.5, 3/16},
573 after_destruct = function(pos, oldnode)
574 local facedir = oldnode.param2
575 local dir = minetest.facedir_to_dir(facedir)
576 local piston_location = vector.add(pos,dir)
577 minetest.remove_node(piston_location)
578 redstone.inject(pos,nil)
582 minetest.register_lbm({
583 name = "redstone:sticky_piston_on",
584 nodenames = {"redstone:sticky_piston_on"},
585 run_at_every_load = true,
586 action = function(pos)
587 redstone.inject(pos,{
588 name = "redstone:sticky_piston_on",
591 minetest.after(0,function()
597 redstone.register_activator({
598 name = "redstone:sticky_piston_on",
599 deactivate = function(pos)
600 --this is where the piston deactivates
601 local facedir = minetest.get_node(pos).param2
602 local dir = minetest.facedir_to_dir(facedir)
603 local piston_location = vector.add(pos,dir)
604 minetest.remove_node(piston_location)
605 minetest.swap_node(pos,{name="redstone:sticky_piston_off",param2=facedir})
606 piston_location.y = piston_location.y + 1
607 minetest.sound_play("piston", {pos=pos,pitch=math.random(85,100)/100})
608 redstone.inject(pos,{
609 name = "redstone:sticky_piston_off",
617 █████╗ ██████╗ ███╗ ███╗
618 ██╔══██╗██╔══██╗████╗ ████║
619 ███████║██████╔╝██╔████╔██║
620 ██╔══██║██╔══██╗██║╚██╔╝██║
621 ██║ ██║██║ ██║██║ ╚═╝ ██║
622 ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝
627 minetest.register_node("redstone:sticky_actuator", {
628 description = "Piston Actuator",
629 tiles = {"wood.png"},
630 drawtype = "nodebox",
632 paramtype2 = "facedir",
633 groups = {stone = 1, hard = 1, pickaxe = 1, hand = 4,pathable = 1},
634 sounds = main.stoneSound(),
635 drop = "redstone:piston_off",
639 --left front bottom right back top
640 {-0.5, -0.5, 0.2, 0.5, 0.5, 0.5}, --mover
641 {-0.15, -0.15, -0.9, 0.15, 0.15, 0.5}, --actuator
644 after_destruct = function(pos, oldnode)
645 local facedir = oldnode.param2
646 local dir = minetest.facedir_to_dir(facedir)
647 dir = vector.multiply(dir,-1)
648 local piston_location = vector.add(pos,dir)
649 minetest.remove_node(piston_location)