1 --register stoppers for movestones/pistons
3 mesecon
.mvps_stoppers
= {}
4 mesecon
.mvps_unsticky
= {}
5 mesecon
.mvps_droppers
= {}
6 mesecon
.on_mvps_move
= {}
7 mesecon
.mvps_unmov
= {}
9 --- Objects (entities) that cannot be moved
10 function mesecon
.register_mvps_unmov(objectname
)
11 mesecon
.mvps_unmov
[objectname
] = true;
14 function mesecon
.is_mvps_unmov(objectname
)
15 return mesecon
.mvps_unmov
[objectname
]
18 function mesecon
.is_mvps_dropper(node
, pushdir
, stack
, stackid
)
19 local get_dropper
= mesecon
.mvps_droppers
[node
.name
]
20 if type (get_dropper
) == "function" then
21 get_dropper
= get_dropper(node
, pushdir
, stack
, stackid
)
23 if not get_dropper
then
24 get_dropper
= minetest
.get_item_group(node
.name
, "dig_by_piston") == 1
29 function mesecon
.register_mvps_dropper(nodename
, get_dropper
)
30 if get_dropper
== nil then
33 mesecon
.mvps_droppers
[nodename
] = get_dropper
36 -- Nodes that cannot be pushed / pulled by movestones, pistons
37 function mesecon
.is_mvps_stopper(node
, pushdir
, stack
, stackid
)
38 -- unknown nodes are always stoppers
39 if not minetest
.registered_nodes
[node
.name
] then
43 local get_stopper
= mesecon
.mvps_stoppers
[node
.name
]
44 if type (get_stopper
) == "function" then
45 get_stopper
= get_stopper(node
, pushdir
, stack
, stackid
)
51 function mesecon
.register_mvps_stopper(nodename
, get_stopper
)
52 if get_stopper
== nil then
55 mesecon
.mvps_stoppers
[nodename
] = get_stopper
58 -- For nodes which ignore sticky sides.
59 -- They can't be pulled by sticky pistons and don't interact with slime blocks.
60 -- TODO: This has NOT any actual effect so far. The actual functionality
61 -- still needs to be implemented.
62 function mesecon
.register_mvps_unsticky(nodename
, get_unsticky
)
63 if get_unsticky
== nil then
66 mesecon
.mvps_unsticky
[nodename
] = get_unsticky
69 function mesecon
.is_mvps_unsticky(node
, pulldir
, stack
, stackid
)
70 -- unknown nodes are always unsticky
71 if not minetest
.registered_nodes
[node
.name
] then
75 local get_unsticky
= mesecon
.mvps_unsticky
[node
.name
]
76 if type(get_unsticky
) == "function" then
77 get_unsticky
= get_unsticky(node
, pulldir
, stack
, stackid
)
79 if get_unsticky
== nil then
86 -- Functions to be called on mvps movement
87 function mesecon
.register_on_mvps_move(callback
)
88 mesecon
.on_mvps_move
[#mesecon
.on_mvps_move
+1] = callback
91 local function on_mvps_move(moved_nodes
)
92 for _
, callback
in ipairs(mesecon
.on_mvps_move
) do
97 function mesecon
.mvps_process_stack(stack
)
98 -- update mesecons for placed nodes ( has to be done after all nodes have been added )
99 for _
, n
in ipairs(stack
) do
100 mesecon
.on_placenode(n
.pos
, minetest
.get_node(n
.pos
))
104 -- tests if the node can be pushed into, e.g. air, water, grass
105 local function node_replaceable(name
)
106 if name
== "ignore" then return true end
108 if minetest
.registered_nodes
[name
] then
109 return minetest
.registered_nodes
[name
].buildable_to
or false
115 function mesecon
.mvps_get_stack(pos
, dir
, maximum
, all_pull_sticky
)
116 -- determine the number of nodes to be pushed
118 local frontiers
= {pos
}
120 while #frontiers
> 0 do
121 local np
= frontiers
[1]
122 local nn
= minetest
.get_node(np
)
124 if not node_replaceable(nn
.name
) then
126 table.insert(nodes
, {node
= nn
, pos
= np
})
127 if #nodes
> maximum
then return nil end
129 -- add connected nodes to frontiers, connected is a vector list
130 -- the vectors must be absolute positions
132 if minetest
.registered_nodes
[nn
.name
]
133 and minetest
.registered_nodes
[nn
.name
].mvps_sticky
then
134 connected
= minetest
.registered_nodes
[nn
.name
].mvps_sticky(np
, nn
)
137 table.insert(connected
, vector
.add(np
, dir
))
139 -- If adjacent node is sticky block and connects add that
140 -- position to the connected table
141 for _
, r
in ipairs(mesecon
.rules
.alldirs
) do
142 local adjpos
= vector
.add(np
, r
)
143 local adjnode
= minetest
.get_node(adjpos
)
144 if minetest
.registered_nodes
[adjnode
.name
]
145 and minetest
.registered_nodes
[adjnode
.name
].mvps_sticky
then
146 local sticksto
= minetest
.registered_nodes
[adjnode
.name
]
147 .mvps_sticky(adjpos
, adjnode
)
149 -- connects to this position?
150 for _
, link
in ipairs(sticksto
) do
151 if vector
.equals(link
, np
) then
152 table.insert(connected
, adjpos
)
158 if all_pull_sticky
then
159 table.insert(connected
, vector
.subtract(np
, dir
))
162 -- Make sure there are no duplicates in frontiers / nodes before
163 -- adding nodes in "connected" to frontiers
164 for _
, cp
in ipairs(connected
) do
165 local duplicate
= false
166 for _
, rp
in ipairs(nodes
) do
167 if vector
.equals(cp
, rp
.pos
) then
171 for _
, fp
in ipairs(frontiers
) do
172 if vector
.equals(cp
, fp
) then
176 if not duplicate
then
177 table.insert(frontiers
, cp
)
181 table.remove(frontiers
, 1)
187 function mesecon
.mvps_push(pos
, dir
, maximum
)
188 return mesecon
.mvps_push_or_pull(pos
, dir
, dir
, maximum
, nil, false)
191 function mesecon
.mvps_pull_all(pos
, dir
, maximum
)
192 return mesecon
.mvps_push_or_pull(pos
, vector
.multiply(dir
, -1), dir
, maximum
, true, true)
195 function mesecon
.mvps_pull_single(pos
, dir
, maximum
)
196 return mesecon
.mvps_push_or_pull(pos
, vector
.multiply(dir
, -1), dir
, maximum
, nil, true)
199 -- pos: pos of mvps; stackdir: direction of building the stack
200 -- movedir: direction of actual movement
201 -- maximum: maximum nodes to be pushed
202 -- all_pull_sticky: All nodes are sticky in the direction that they are pulled from
203 function mesecon
.mvps_push_or_pull(pos
, stackdir
, movedir
, maximum
, all_pull_sticky
)
204 local nodes
= mesecon
.mvps_get_stack(pos
, movedir
, maximum
, all_pull_sticky
)
206 if not nodes
then return end
207 -- determine if one of the nodes blocks the push / pull
208 for id
, n
in ipairs(nodes
) do
209 if mesecon
.is_mvps_stopper(n
.node
, movedir
, nodes
, id
) then
214 local first_dropper
= nil
216 for id
, n
in ipairs(nodes
) do
217 n
.meta
= minetest
.get_meta(n
.pos
):to_table()
218 local is_dropper
= mesecon
.is_mvps_dropper(n
.node
, movedir
, nodes
, id
)
220 local drops
= minetest
.get_node_drops(n
.node
.name
, "")
221 minetest
.dig_node(n
.pos
)
223 minetest
.remove_node(n
.pos
)
231 -- update mesecons for removed nodes ( has to be done after all nodes have been removed )
232 for id
, n
in ipairs(nodes
) do
233 if first_dropper
and id
>= first_dropper
then
236 mesecon
.on_dignode(n
.pos
, n
.node
)
240 for id
, n
in ipairs(nodes
) do
241 if first_dropper
and id
>= first_dropper
then
244 local np
= vector
.add(n
.pos
, movedir
)
245 minetest
.add_node(np
, n
.node
)
246 minetest
.get_meta(np
):from_table(n
.meta
)
249 for i
in ipairs(nodes
) do
250 if first_dropper
and i
>= first_dropper
then
253 nodes
[i
].pos
= vector
.add(nodes
[i
].pos
, movedir
)
256 local moved_nodes
= {}
257 local oldstack
= mesecon
.tablecopy(nodes
)
258 for i
in ipairs(nodes
) do
259 if first_dropper
and i
>= first_dropper
then
263 moved_nodes
[i
].oldpos
= nodes
[i
].pos
264 nodes
[i
].pos
= vector
.add(nodes
[i
].pos
, movedir
)
265 moved_nodes
[i
].pos
= nodes
[i
].pos
266 moved_nodes
[i
].node
= nodes
[i
].node
267 moved_nodes
[i
].meta
= nodes
[i
].meta
270 on_mvps_move(moved_nodes
)
272 return true, nodes
, oldstack
275 mesecon
.register_on_mvps_move(function(moved_nodes
)
276 for _
, n
in ipairs(moved_nodes
) do
277 mesecon
.on_placenode(n
.pos
, n
.node
)
281 function mesecon
.mvps_move_objects(pos
, dir
, nodestack
)
282 local objects_to_move
= {}
284 -- Move object at tip of stack, pushpos is position at tip of stack
285 local pushpos
= vector
.add(pos
, vector
.multiply(dir
, #nodestack
))
287 local objects
= minetest
.get_objects_inside_radius(pushpos
, 1)
288 for _
, obj
in ipairs(objects
) do
289 table.insert(objects_to_move
, obj
)
292 -- Move objects lying/standing on the stack (before it was pushed - oldstack)
293 if tonumber(minetest
.setting_get("movement_gravity")) > 0 and dir
.y
== 0 then
294 -- If gravity positive and dir horizontal, push players standing on the stack
295 for _
, n
in ipairs(nodestack
) do
296 local p_above
= vector
.add(n
.pos
, {x
=0, y
=1, z
=0})
297 local objects
= minetest
.get_objects_inside_radius(p_above
, 1)
298 for _
, obj
in ipairs(objects
) do
299 table.insert(objects_to_move
, obj
)
304 for _
, obj
in ipairs(objects_to_move
) do
305 local entity
= obj
:get_luaentity()
306 if not entity
or not mesecon
.is_mvps_unmov(entity
.name
) then
307 local np
= vector
.add(obj
:getpos(), dir
)
309 --move only if destination is not solid
310 local nn
= minetest
.get_node(np
)
311 if not ((not minetest
.registered_nodes
[nn
.name
])
312 or minetest
.registered_nodes
[nn
.name
].walkable
) then
319 mesecon
.register_mvps_stopper("mcl_core:obsidian")
320 mesecon
.register_mvps_stopper("mcl_core:bedrock")
321 mesecon
.register_mvps_stopper("mcl_core:barrier")
322 mesecon
.register_mvps_stopper("mcl_core:realm_barrier")
323 mesecon
.register_mvps_stopper("mcl_core:void")
324 mesecon
.register_mvps_stopper("mcl_chests:chest")
325 mesecon
.register_mvps_stopper("mcl_chests:chest_left")
326 mesecon
.register_mvps_stopper("mcl_chests:chest_right")
327 mesecon
.register_mvps_stopper("mcl_chests:trapped_chest")
328 mesecon
.register_mvps_stopper("mcl_chests:trapped_chest_left")
329 mesecon
.register_mvps_stopper("mcl_chests:trapped_chest_right")
330 mesecon
.register_mvps_stopper("mcl_chests:trapped_chest_on")
331 mesecon
.register_mvps_stopper("mcl_chests:trapped_chest_on_left")
332 mesecon
.register_mvps_stopper("mcl_chests:trapped_chest_on_right")
333 mesecon
.register_mvps_stopper("mcl_chests:ender_chest")
334 mesecon
.register_mvps_stopper("mcl_furnaces:furnace")
335 mesecon
.register_mvps_stopper("mcl_furnaces:furnace_active")
336 mesecon
.register_mvps_stopper("mcl_hoppers:hopper")
337 mesecon
.register_mvps_stopper("mcl_hoppers:hopper_side")
338 mesecon
.register_mvps_stopper("mcl_droppers:dropper")
339 mesecon
.register_mvps_stopper("mcl_droppers:dropper_up")
340 mesecon
.register_mvps_stopper("mcl_droppers:dropper_down")
341 mesecon
.register_mvps_stopper("mcl_dispensers:dispenser")
342 mesecon
.register_mvps_stopper("mcl_dispensers:dispenser_up")
343 mesecon
.register_mvps_stopper("mcl_dispensers:dispenser_down")
344 mesecon
.register_mvps_stopper("mcl_anvils:anvil")
345 mesecon
.register_mvps_stopper("mcl_anvils:anvil_damage_1")
346 mesecon
.register_mvps_stopper("mcl_anvils:anvil_damage_2")
347 mesecon
.register_mvps_stopper("mcl_jukebox:jukebox")
348 mesecon
.register_mvps_stopper("mcl_mobspawners:spawner")
349 mesecon
.register_mvps_stopper("mcl_signs:standing_sign")
350 mesecon
.register_mvps_stopper("mcl_signs:wall_sign")
351 mesecon
.register_mvps_stopper("mesecons_commandblock:commandblock_off")
352 mesecon
.register_mvps_stopper("mesecons_commandblock:commandblock_on")
353 mesecon
.register_mvps_stopper("mesecons_solarpanel:solar_panel_off")
354 mesecon
.register_mvps_stopper("mesecons_solarpanel:solar_panel_on")
355 mesecon
.register_mvps_stopper("mesecons_solarpanel:solar_panel_inverted_off")
356 mesecon
.register_mvps_stopper("mesecons_solarpanel:solar_panel_inverted_on")
357 mesecon
.register_mvps_stopper("mesecons_noteblock:noteblock")
358 mesecon
.register_mvps_stopper("3d_armor_stand:armor_stand")
359 mesecon
.register_mvps_stopper("mcl_banners:standing_banner")
360 mesecon
.register_mvps_stopper("mcl_banners:hanging_banner")
361 mesecon
.register_mvps_stopper("mcl_portals:portal")
362 mesecon
.register_mvps_stopper("mcl_portals:portal_end")
363 mesecon
.register_mvps_stopper("mcl_portals:end_portal_frame")
364 mesecon
.register_mvps_stopper("mcl_portals:end_portal_frame_eye")
365 mesecon
.register_mvps_unsticky("mcl_colorblocks:glazed_terracotta_red")
366 mesecon
.register_mvps_unsticky("mcl_colorblocks:glazed_terracotta_orange")
367 mesecon
.register_mvps_unsticky("mcl_colorblocks:glazed_terracotta_yellow")
368 mesecon
.register_mvps_unsticky("mcl_colorblocks:glazed_terracotta_green")
369 mesecon
.register_mvps_unsticky("mcl_colorblocks:glazed_terracotta_lime")
370 mesecon
.register_mvps_unsticky("mcl_colorblocks:glazed_terracotta_purple")
371 mesecon
.register_mvps_unsticky("mcl_colorblocks:glazed_terracotta_magenta")
372 mesecon
.register_mvps_unsticky("mcl_colorblocks:glazed_terracotta_blue")
373 mesecon
.register_mvps_unsticky("mcl_colorblocks:glazed_terracotta_cyan")
374 mesecon
.register_mvps_unsticky("mcl_colorblocks:glazed_terracotta_white")
375 mesecon
.register_mvps_unsticky("mcl_colorblocks:glazed_terracotta_grey")
376 mesecon
.register_mvps_unsticky("mcl_colorblocks:glazed_terracotta_silver")
377 mesecon
.register_mvps_unsticky("mcl_colorblocks:glazed_terracotta_black")
378 mesecon
.register_mvps_unsticky("mcl_colorblocks:glazed_terracotta_brown")
379 mesecon
.register_mvps_unsticky("mcl_colorblocks:glazed_terracotta_light_blue")
380 mesecon
.register_mvps_unsticky("mcl_colorblocks:glazed_terracotta_pink")
382 mesecon
.register_on_mvps_move(mesecon
.move_hot_nodes
)
384 -- Check for falling after moving node
385 mesecon
.register_on_mvps_move(function(moved_nodes
)
386 for i
= 1, #moved_nodes
do
387 local moved_node
= moved_nodes
[i
]
388 mesecon
.on_placenode(moved_node
.pos
, moved_node
.node
)
389 minetest
.after(0, function()
390 minetest
.check_for_falling(moved_node
.oldpos
)
391 minetest
.check_for_falling(moved_node
.pos
)
393 local node_def
= minetest
.registered_nodes
[moved_node
.node
.name
]
394 if node_def
and node_def
.mesecon
and node_def
.mesecon
.on_mvps_move
then
395 node_def
.mesecon
.on_mvps_move(moved_node
.pos
, moved_node
.node
,
396 moved_node
.oldpos
, moved_node
.meta
)