init.lua 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. --register stoppers for movestones/pistons
  2. mesecon.mvps_stoppers = {}
  3. mesecon.on_mvps_move = {}
  4. mesecon.mvps_unmov = {}
  5. --- Objects (entities) that cannot be moved
  6. function mesecon.register_mvps_unmov(objectname)
  7. mesecon.mvps_unmov[objectname] = true;
  8. end
  9. function mesecon.is_mvps_unmov(objectname)
  10. return mesecon.mvps_unmov[objectname]
  11. end
  12. -- Nodes that cannot be pushed / pulled by movestones, pistons
  13. function mesecon.is_mvps_stopper(node, pushdir, stack, stackid)
  14. local get_stopper = mesecon.mvps_stoppers[node.name]
  15. if type (get_stopper) == "function" then
  16. get_stopper = get_stopper(node, pushdir, stack, stackid)
  17. end
  18. return get_stopper
  19. end
  20. function mesecon.register_mvps_stopper(nodename, get_stopper)
  21. if get_stopper == nil then
  22. get_stopper = true
  23. end
  24. mesecon.mvps_stoppers[nodename] = get_stopper
  25. end
  26. -- Functions to be called on mvps movement
  27. function mesecon.register_on_mvps_move(callback)
  28. mesecon.on_mvps_move[#mesecon.on_mvps_move+1] = callback
  29. end
  30. local function on_mvps_move(moved_nodes)
  31. for _, callback in ipairs(mesecon.on_mvps_move) do
  32. callback(moved_nodes)
  33. end
  34. end
  35. function mesecon.mvps_process_stack(stack)
  36. -- update mesecons for placed nodes ( has to be done after all nodes have been added )
  37. for _, n in ipairs(stack) do
  38. mesecon.on_placenode(n.pos, minetest.get_node(n.pos))
  39. end
  40. end
  41. function mesecon.mvps_get_stack(pos, dir, maximum, all_pull_sticky)
  42. -- determine the number of nodes to be pushed
  43. local nodes = {}
  44. local frontiers = {pos}
  45. while #frontiers > 0 do
  46. local np = frontiers[1]
  47. local nn = minetest.get_node(np)
  48. if nn.name ~= "air"
  49. and minetest.registered_nodes[nn.name]
  50. and minetest.registered_nodes[nn.name].liquidtype == "none" then
  51. table.insert(nodes, {node = nn, pos = np})
  52. if #nodes > maximum then return nil end
  53. -- add connected nodes to frontiers, connected is a vector list
  54. -- the vectors must be absolute positions
  55. local connected = {}
  56. if minetest.registered_nodes[nn.name]
  57. and minetest.registered_nodes[nn.name].mvps_sticky then
  58. connected = minetest.registered_nodes[nn.name].mvps_sticky(np, nn)
  59. end
  60. table.insert(connected, vector.add(np, dir))
  61. -- If adjacent node is sticky block and connects add that
  62. -- position to the connected table
  63. for _, r in ipairs(mesecon.rules.alldirs) do
  64. local adjpos = vector.add(np, r)
  65. local adjnode = minetest.get_node(adjpos)
  66. if minetest.registered_nodes[adjnode.name]
  67. and minetest.registered_nodes[adjnode.name].mvps_sticky then
  68. local sticksto = minetest.registered_nodes[adjnode.name]
  69. .mvps_sticky(adjpos, adjnode)
  70. -- connects to this position?
  71. for _, link in ipairs(sticksto) do
  72. if vector.equals(link, np) then
  73. table.insert(connected, adjpos)
  74. end
  75. end
  76. end
  77. end
  78. if all_pull_sticky then
  79. table.insert(connected, vector.subtract(np, dir))
  80. end
  81. -- Make sure there are no duplicates in frontiers / nodes before
  82. -- adding nodes in "connected" to frontiers
  83. for _, cp in ipairs(connected) do
  84. local duplicate = false
  85. for _, rp in ipairs(nodes) do
  86. if vector.equals(cp, rp.pos) then
  87. duplicate = true
  88. end
  89. end
  90. for _, fp in ipairs(frontiers) do
  91. if vector.equals(cp, fp) then
  92. duplicate = true
  93. end
  94. end
  95. if not duplicate then
  96. table.insert(frontiers, cp)
  97. end
  98. end
  99. end
  100. table.remove(frontiers, 1)
  101. end
  102. return nodes
  103. end
  104. function mesecon.mvps_push(pos, dir, maximum)
  105. return mesecon.mvps_push_or_pull(pos, dir, dir, maximum)
  106. end
  107. function mesecon.mvps_pull_all(pos, dir, maximum)
  108. return mesecon.mvps_push_or_pull(pos, vector.multiply(dir, -1), dir, maximum, true)
  109. end
  110. function mesecon.mvps_pull_single(pos, dir, maximum)
  111. return mesecon.mvps_push_or_pull(pos, vector.multiply(dir, -1), dir, maximum)
  112. end
  113. -- pos: pos of mvps; stackdir: direction of building the stack
  114. -- movedir: direction of actual movement
  115. -- maximum: maximum nodes to be pushed
  116. -- all_pull_sticky: All nodes are sticky in the direction that they are pulled from
  117. function mesecon.mvps_push_or_pull(pos, stackdir, movedir, maximum, all_pull_sticky)
  118. local nodes = mesecon.mvps_get_stack(pos, movedir, maximum, all_pull_sticky)
  119. if not nodes then return end
  120. -- determine if one of the nodes blocks the push / pull
  121. for id, n in ipairs(nodes) do
  122. if mesecon.is_mvps_stopper(n.node, movedir, nodes, id) then
  123. return
  124. end
  125. end
  126. -- remove all nodes
  127. for _, n in ipairs(nodes) do
  128. n.meta = minetest.get_meta(n.pos):to_table()
  129. minetest.remove_node(n.pos)
  130. end
  131. -- update mesecons for removed nodes ( has to be done after all nodes have been removed )
  132. for _, n in ipairs(nodes) do
  133. mesecon.on_dignode(n.pos, n.node)
  134. end
  135. -- add nodes
  136. for _, n in ipairs(nodes) do
  137. local np = mesecon.addPosRule(n.pos, movedir)
  138. minetest.add_node(np, n.node)
  139. minetest.get_meta(np):from_table(n.meta)
  140. end
  141. local moved_nodes = {}
  142. local oldstack = mesecon.tablecopy(nodes)
  143. for i in ipairs(nodes) do
  144. moved_nodes[i] = {}
  145. moved_nodes[i].oldpos = nodes[i].pos
  146. nodes[i].pos = mesecon.addPosRule(nodes[i].pos, movedir)
  147. moved_nodes[i].pos = nodes[i].pos
  148. moved_nodes[i].node = nodes[i].node
  149. moved_nodes[i].meta = nodes[i].meta
  150. end
  151. on_mvps_move(moved_nodes)
  152. return true, nodes, oldstack
  153. end
  154. mesecon.register_on_mvps_move(function(moved_nodes)
  155. for _, n in ipairs(moved_nodes) do
  156. mesecon.on_placenode(n.pos, n.node)
  157. mesecon.update_autoconnect(n.pos)
  158. end
  159. end)
  160. function mesecon.mvps_move_objects(pos, dir, nodestack)
  161. local objects_to_move = {}
  162. -- Move object at tip of stack
  163. local pushpos = mesecon.addPosRule(pos, -- get pos at tip of stack
  164. {x = dir.x * #nodestack,
  165. y = dir.y * #nodestack,
  166. z = dir.z * #nodestack})
  167. local objects = minetest.get_objects_inside_radius(pushpos, 1)
  168. for _, obj in ipairs(objects) do
  169. table.insert(objects_to_move, obj)
  170. end
  171. -- Move objects lying/standing on the stack (before it was pushed - oldstack)
  172. if tonumber(minetest.setting_get("movement_gravity")) > 0 and dir.y == 0 then
  173. -- If gravity positive and dir horizontal, push players standing on the stack
  174. for _, n in ipairs(nodestack) do
  175. local p_above = mesecon.addPosRule(n.pos, {x=0, y=1, z=0})
  176. local objects = minetest.get_objects_inside_radius(p_above, 1)
  177. for _, obj in ipairs(objects) do
  178. table.insert(objects_to_move, obj)
  179. end
  180. end
  181. end
  182. for _, obj in ipairs(objects_to_move) do
  183. local entity = obj:get_luaentity()
  184. if not entity or not mesecon.is_mvps_unmov(entity.name) then
  185. local np = mesecon.addPosRule(obj:getpos(), dir)
  186. --move only if destination is not solid
  187. local nn = minetest.get_node(np)
  188. if not ((not minetest.registered_nodes[nn.name])
  189. or minetest.registered_nodes[nn.name].walkable) then
  190. obj:setpos(np)
  191. end
  192. end
  193. end
  194. end
  195. mesecon.register_mvps_stopper("doors:door_steel_b_1")
  196. mesecon.register_mvps_stopper("doors:door_steel_t_1")
  197. mesecon.register_mvps_stopper("doors:door_steel_b_2")
  198. mesecon.register_mvps_stopper("doors:door_steel_t_2")
  199. mesecon.register_mvps_stopper("default:chest_locked")