Replace getpos() with get_pos()
[MineClone/MineClone2.git] / mods / ITEMS / REDSTONE / mesecons_mvps / init.lua
blob2e2d0fd601f0a7adfbc91594d48629fb56fa948e
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;
12 end
14 function mesecon.is_mvps_unmov(objectname)
15 return mesecon.mvps_unmov[objectname]
16 end
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)
22 end
23 if not get_dropper then
24 get_dropper = minetest.get_item_group(node.name, "dig_by_piston") == 1
25 end
26 return get_dropper
27 end
29 function mesecon.register_mvps_dropper(nodename, get_dropper)
30 if get_dropper == nil then
31 get_dropper = true
32 end
33 mesecon.mvps_droppers[nodename] = get_dropper
34 end
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
40 return true
41 end
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)
46 end
48 return get_stopper
49 end
51 function mesecon.register_mvps_stopper(nodename, get_stopper)
52 if get_stopper == nil then
53 get_stopper = true
54 end
55 mesecon.mvps_stoppers[nodename] = get_stopper
56 end
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
64 get_unsticky = true
65 end
66 mesecon.mvps_unsticky[nodename] = get_unsticky
67 end
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
72 return true
73 end
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)
78 end
79 if get_unsticky == nil then
80 get_unsticky = false
81 end
83 return get_unsticky
84 end
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
89 end
91 local function on_mvps_move(moved_nodes)
92 for _, callback in ipairs(mesecon.on_mvps_move) do
93 callback(moved_nodes)
94 end
95 end
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
112 return false
115 function mesecon.mvps_get_stack(pos, dir, maximum, all_pull_sticky)
116 -- determine the number of nodes to be pushed
117 local nodes = {}
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
131 local connected = {}
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
168 duplicate = true
171 for _, fp in ipairs(frontiers) do
172 if vector.equals(cp, fp) then
173 duplicate = true
176 if not duplicate then
177 table.insert(frontiers, cp)
181 table.remove(frontiers, 1)
184 return nodes
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
210 return
214 local first_dropper = nil
215 -- remove all nodes
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)
219 if is_dropper then
220 local drops = minetest.get_node_drops(n.node.name, "")
221 minetest.dig_node(n.pos)
222 else
223 minetest.remove_node(n.pos)
225 if is_dropper then
226 first_dropper = id
227 break
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
234 break
236 mesecon.on_dignode(n.pos, n.node)
239 -- add nodes
240 for id, n in ipairs(nodes) do
241 if first_dropper and id >= first_dropper then
242 break
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
251 break
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
260 break
262 moved_nodes[i] = {}
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)
279 end)
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:get_pos(), 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
313 obj:setpos(np)
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)
392 end)
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)
399 end)