init.lua 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. local specs = {
  2. normal = {
  3. offname = "mesecons_pistons:piston_normal_off",
  4. onname = "mesecons_pistons:piston_normal_on",
  5. pusher = "mesecons_pistons:piston_pusher_normal",
  6. },
  7. sticky = {
  8. offname = "mesecons_pistons:piston_sticky_off",
  9. onname = "mesecons_pistons:piston_sticky_on",
  10. pusher = "mesecons_pistons:piston_pusher_sticky",
  11. sticky = true,
  12. },
  13. }
  14. local function get_pistonspec_name(name, part)
  15. if part then
  16. for spec_name, spec in pairs(specs) do
  17. if name == spec[part] then
  18. return spec_name, part
  19. end
  20. end
  21. return
  22. end
  23. for spec_name, spec in pairs(specs) do
  24. for part, value in pairs(spec) do
  25. if name == value then
  26. return spec_name, part
  27. end
  28. end
  29. end
  30. end
  31. local function get_pistonspec(name, part)
  32. return specs[get_pistonspec_name(name, part)]
  33. end
  34. local max_push = mesecon.setting("piston_max_push", 15)
  35. local max_pull = mesecon.setting("piston_max_pull", 15)
  36. -- Get mesecon rules of pistons
  37. local function piston_get_rules(node)
  38. local dir = minetest.facedir_to_dir(node.param2)
  39. for k, v in pairs(dir) do
  40. if v ~= 0 then
  41. dir = {k, -v}
  42. break
  43. end
  44. end
  45. local rules = table.copy(mesecon.rules.default)
  46. for i, rule in ipairs(rules) do
  47. if rule[dir[1]] == dir[2] then
  48. table.remove(rules, i)
  49. end
  50. end
  51. return rules
  52. end
  53. local function piston_remove_pusher(pos, node)
  54. local pistonspec = get_pistonspec(node.name, "onname")
  55. local dir = vector.multiply(minetest.facedir_to_dir(node.param2), -1)
  56. local pusherpos = vector.add(pos, dir)
  57. local pushername = minetest.get_node(pusherpos).name
  58. -- make sure there actually is a pusher (for compatibility reasons mainly)
  59. if pushername ~= pistonspec.pusher then
  60. return
  61. end
  62. minetest.remove_node(pusherpos)
  63. minetest.sound_play("piston_retract", {
  64. pos = pos,
  65. max_hear_distance = 20,
  66. gain = 0.3,
  67. })
  68. minetest.check_for_falling(pusherpos)
  69. end
  70. local piston_on = function(pos, node)
  71. local pistonspec = get_pistonspec(node.name, "offname")
  72. local dir = vector.multiply(minetest.facedir_to_dir(node.param2), -1)
  73. local pusher_pos = vector.add(pos, dir)
  74. local success, stack, oldstack = mesecon.mvps_push(pusher_pos, dir, max_push)
  75. if not success then
  76. return
  77. end
  78. minetest.set_node(pos, {param2 = node.param2, name = pistonspec.onname})
  79. minetest.set_node(pusher_pos, {param2 = node.param2, name = pistonspec.pusher})
  80. minetest.sound_play("piston_extend", {
  81. pos = pos,
  82. max_hear_distance = 20,
  83. gain = 0.3,
  84. })
  85. mesecon.mvps_process_stack(stack)
  86. mesecon.mvps_move_objects(pusher_pos, dir, oldstack)
  87. end
  88. local function piston_off(pos, node)
  89. local pistonspec = get_pistonspec(node.name, "onname")
  90. minetest.set_node(pos, {param2 = node.param2, name = pistonspec.offname})
  91. piston_remove_pusher(pos, node)
  92. if not pistonspec.sticky then
  93. return
  94. end
  95. local dir = minetest.facedir_to_dir(node.param2)
  96. local pullpos = vector.add(pos, vector.multiply(dir, -2))
  97. local success, stack, oldstack = mesecon.mvps_pull_single(pullpos, dir, max_pull)
  98. if success then
  99. mesecon.mvps_move_objects(pullpos, vector.multiply(dir, -1), oldstack, -1)
  100. end
  101. end
  102. local orientations = {
  103. [0] = { 4, 8},
  104. {13, 17},
  105. {10, 6},
  106. {20, 15},
  107. }
  108. local function piston_orientate(pos, placer)
  109. if not placer then
  110. return
  111. end
  112. local pitch = math.deg(placer:get_look_vertical())
  113. local node = minetest.get_node(pos)
  114. if pitch > 55 then
  115. node.param2 = orientations[node.param2][1]
  116. elseif pitch < -55 then
  117. node.param2 = orientations[node.param2][2]
  118. else
  119. return
  120. end
  121. minetest.swap_node(pos, node)
  122. -- minetest.after, because on_placenode for unoriented piston must be processed first
  123. minetest.after(0, mesecon.on_placenode, pos, node)
  124. end
  125. local rotations = {
  126. {0, 16, 20, 12},
  127. {2, 14, 22, 18},
  128. {1, 5, 23, 9},
  129. {3, 11, 21, 7},
  130. {4, 13, 10, 19},
  131. {6, 15, 8, 17},
  132. }
  133. local function get_rotation(param2)
  134. for a = 1, #rotations do
  135. for f = 1, #rotations[a] do
  136. if rotations[a][f] == param2 then
  137. return a, f
  138. end
  139. end
  140. end
  141. end
  142. local function rotate(param2, mode)
  143. local axis, face = get_rotation(param2)
  144. if mode == screwdriver.ROTATE_FACE then
  145. face = face + 1
  146. if face > 4 then
  147. face = 1
  148. end
  149. elseif mode == screwdriver.ROTATE_AXIS then
  150. axis = axis + 1
  151. if axis > 6 then
  152. axis = 1
  153. end
  154. face = 1
  155. else
  156. return param2
  157. end
  158. return rotations[axis][face]
  159. end
  160. local function piston_rotate(pos, node, _, mode)
  161. node.param2 = rotate(node.param2, mode)
  162. minetest.swap_node(pos, node)
  163. mesecon.execute_autoconnect_hooks_now(pos, node)
  164. return true
  165. end
  166. local function piston_rotate_on(pos, node, player, mode)
  167. local pistonspec = get_pistonspec(node.name, "onname")
  168. local dir = vector.multiply(minetest.facedir_to_dir(node.param2), -1)
  169. local pusher_pos = vector.add(dir, pos)
  170. local pusher_node = minetest.get_node(pusher_pos)
  171. if pusher_node.name ~= pistonspec.pusher then
  172. return piston_rotate(pos, node, nil, mode)
  173. end
  174. if mode == screwdriver.ROTATE_FACE then
  175. piston_rotate(pusher_pos, pusher_node, nil, mode)
  176. return piston_rotate(pos, node, nil, mode)
  177. elseif mode ~= screwdriver.ROTATE_AXIS then
  178. return false
  179. end
  180. local player_name = player and player:is_player() and player:get_player_name() or ""
  181. local ok, dir_after, pusher_pos_after
  182. for i = 1, 5 do
  183. node.param2 = rotate(node.param2, mode)
  184. dir_after = vector.multiply(minetest.facedir_to_dir(node.param2), -1)
  185. pusher_pos_after = vector.add(dir_after, pos)
  186. local pusher_pos_after_node_name = minetest.get_node(pusher_pos_after).name
  187. local pusher_pos_after_node_def = minetest.registered_nodes[pusher_pos_after_node_name]
  188. if pusher_pos_after_node_def and pusher_pos_after_node_def.buildable_to and
  189. not minetest.is_protected(pusher_pos_after, player_name) then
  190. ok = true
  191. break
  192. end
  193. end
  194. if not ok then
  195. return false
  196. end
  197. pusher_node.param2 = node.param2
  198. minetest.remove_node(pusher_pos)
  199. minetest.set_node(pusher_pos_after, pusher_node)
  200. minetest.swap_node(pos, node)
  201. mesecon.execute_autoconnect_hooks_now(pos, node)
  202. return true
  203. end
  204. local function piston_rotate_pusher(pos, node, player, mode)
  205. local pistonspec = get_pistonspec(node.name, "pusher")
  206. local piston_pos = vector.add(pos, minetest.facedir_to_dir(node.param2))
  207. local piston_node = minetest.get_node(piston_pos)
  208. if piston_node.name ~= pistonspec.onname then
  209. minetest.remove_node(pos) -- Make it possible to remove alone pushers.
  210. return false
  211. end
  212. return piston_rotate_on(piston_pos, piston_node, player, mode)
  213. end
  214. -- Boxes:
  215. local pt = 3/16 -- pusher thickness
  216. local piston_pusher_box = {
  217. type = "fixed",
  218. fixed = {
  219. {-2/16, -2/16, -.5 + pt, 2/16, 2/16, .5 + pt},
  220. {-.5 , -.5 , -.5 , .5 , .5 , -.5 + pt},
  221. },
  222. }
  223. local piston_on_box = {
  224. type = "fixed",
  225. fixed = {
  226. {-.5, -.5, -.5 + pt, .5, .5, .5}
  227. },
  228. }
  229. -- Normal (non-sticky) Pistons:
  230. -- offstate
  231. minetest.register_node("mesecons_pistons:piston_normal_off", {
  232. description = "Piston",
  233. tiles = {
  234. "mesecons_piston_top.png",
  235. "mesecons_piston_bottom.png",
  236. "mesecons_piston_left.png",
  237. "mesecons_piston_right.png",
  238. "mesecons_piston_back.png",
  239. "mesecons_piston_pusher_front.png"
  240. },
  241. groups = {cracky = 3},
  242. paramtype2 = "facedir",
  243. is_ground_content = false,
  244. after_place_node = piston_orientate,
  245. sounds = default.node_sound_wood_defaults(),
  246. mesecons = {effector={
  247. action_on = piston_on,
  248. rules = piston_get_rules,
  249. }},
  250. on_rotate = piston_rotate,
  251. on_blast = mesecon.on_blastnode,
  252. })
  253. -- onstate
  254. minetest.register_node("mesecons_pistons:piston_normal_on", {
  255. description = "Activated Piston Base",
  256. drawtype = "nodebox",
  257. tiles = {
  258. "mesecons_piston_top.png",
  259. "mesecons_piston_bottom.png",
  260. "mesecons_piston_left.png",
  261. "mesecons_piston_right.png",
  262. "mesecons_piston_back.png",
  263. "mesecons_piston_on_front.png"
  264. },
  265. groups = {cracky = 3, not_in_creative_inventory = 1},
  266. paramtype = "light",
  267. paramtype2 = "facedir",
  268. is_ground_content = false,
  269. drop = "mesecons_pistons:piston_normal_off",
  270. after_dig_node = piston_remove_pusher,
  271. node_box = piston_on_box,
  272. selection_box = piston_on_box,
  273. sounds = default.node_sound_wood_defaults(),
  274. mesecons = {effector={
  275. action_off = piston_off,
  276. rules = piston_get_rules,
  277. }},
  278. on_rotate = piston_rotate_on,
  279. on_blast = mesecon.on_blastnode,
  280. })
  281. -- pusher
  282. minetest.register_node("mesecons_pistons:piston_pusher_normal", {
  283. description = "Piston Pusher",
  284. drawtype = "nodebox",
  285. tiles = {
  286. "mesecons_piston_pusher_top.png",
  287. "mesecons_piston_pusher_bottom.png",
  288. "mesecons_piston_pusher_left.png",
  289. "mesecons_piston_pusher_right.png",
  290. "mesecons_piston_pusher_back.png",
  291. "mesecons_piston_pusher_front.png"
  292. },
  293. groups = {not_in_creative_inventory = 1},
  294. paramtype = "light",
  295. paramtype2 = "facedir",
  296. is_ground_content = false,
  297. diggable = false,
  298. selection_box = piston_pusher_box,
  299. node_box = piston_pusher_box,
  300. on_rotate = piston_rotate_pusher,
  301. drop = "",
  302. })
  303. -- Sticky ones
  304. -- offstate
  305. minetest.register_node("mesecons_pistons:piston_sticky_off", {
  306. description = "Sticky Piston",
  307. tiles = {
  308. "mesecons_piston_top.png",
  309. "mesecons_piston_bottom.png",
  310. "mesecons_piston_left.png",
  311. "mesecons_piston_right.png",
  312. "mesecons_piston_back.png",
  313. "mesecons_piston_pusher_front_sticky.png"
  314. },
  315. groups = {cracky = 3},
  316. paramtype2 = "facedir",
  317. is_ground_content = false,
  318. after_place_node = piston_orientate,
  319. sounds = default.node_sound_wood_defaults(),
  320. mesecons = {effector={
  321. action_on = piston_on,
  322. rules = piston_get_rules,
  323. }},
  324. on_rotate = piston_rotate,
  325. on_blast = mesecon.on_blastnode,
  326. })
  327. -- onstate
  328. minetest.register_node("mesecons_pistons:piston_sticky_on", {
  329. description = "Activated Sticky Piston Base",
  330. drawtype = "nodebox",
  331. tiles = {
  332. "mesecons_piston_top.png",
  333. "mesecons_piston_bottom.png",
  334. "mesecons_piston_left.png",
  335. "mesecons_piston_right.png",
  336. "mesecons_piston_back.png",
  337. "mesecons_piston_on_front.png"
  338. },
  339. groups = {cracky = 3, not_in_creative_inventory = 1},
  340. paramtype = "light",
  341. paramtype2 = "facedir",
  342. is_ground_content = false,
  343. drop = "mesecons_pistons:piston_sticky_off",
  344. after_dig_node = piston_remove_pusher,
  345. node_box = piston_on_box,
  346. selection_box = piston_on_box,
  347. sounds = default.node_sound_wood_defaults(),
  348. mesecons = {effector={
  349. action_off = piston_off,
  350. rules = piston_get_rules,
  351. }},
  352. on_rotate = piston_rotate_on,
  353. on_blast = mesecon.on_blastnode,
  354. })
  355. -- pusher
  356. minetest.register_node("mesecons_pistons:piston_pusher_sticky", {
  357. description = "Sticky Piston Pusher",
  358. drawtype = "nodebox",
  359. tiles = {
  360. "mesecons_piston_pusher_top.png",
  361. "mesecons_piston_pusher_bottom.png",
  362. "mesecons_piston_pusher_left.png",
  363. "mesecons_piston_pusher_right.png",
  364. "mesecons_piston_pusher_back.png",
  365. "mesecons_piston_pusher_front_sticky.png"
  366. },
  367. groups = {not_in_creative_inventory = 1},
  368. paramtype = "light",
  369. paramtype2 = "facedir",
  370. is_ground_content = false,
  371. diggable = false,
  372. selection_box = piston_pusher_box,
  373. node_box = piston_pusher_box,
  374. on_rotate = piston_rotate_pusher,
  375. drop = "",
  376. })
  377. -- Register pushers as stoppers if they would be seperated from the piston
  378. local function piston_pusher_get_stopper(node, dir, stack, stackid)
  379. if (stack[stackid + 1]
  380. and stack[stackid + 1].node.name == get_pistonspec(node.name, "pusher").onname
  381. and stack[stackid + 1].node.param2 == node.param2)
  382. or (stack[stackid - 1]
  383. and stack[stackid - 1].node.name == get_pistonspec(node.name, "pusher").onname
  384. and stack[stackid - 1].node.param2 == node.param2) then
  385. return false
  386. end
  387. return true
  388. end
  389. local function piston_pusher_up_down_get_stopper(node, dir, stack, stackid)
  390. if (stack[stackid + 1]
  391. and stack[stackid + 1].node.name == get_pistonspec(node.name, "pusher").onname)
  392. or (stack[stackid - 1]
  393. and stack[stackid - 1].node.name == get_pistonspec(node.name, "pusher").onname) then
  394. return false
  395. end
  396. return true
  397. end
  398. mesecon.register_mvps_stopper("mesecons_pistons:piston_pusher_normal", piston_pusher_get_stopper)
  399. mesecon.register_mvps_stopper("mesecons_pistons:piston_pusher_sticky", piston_pusher_get_stopper)
  400. -- Register pistons as stoppers if they would be seperated from the stopper
  401. local piston_up_down_get_stopper = function (node, dir, stack, stackid)
  402. if (stack[stackid + 1]
  403. and stack[stackid + 1].node.name == get_pistonspec(node.name, "onname").pusher)
  404. or (stack[stackid - 1]
  405. and stack[stackid - 1].node.name == get_pistonspec(node.name, "onname").pusher) then
  406. return false
  407. end
  408. return true
  409. end
  410. local function piston_get_stopper(node, dir, stack, stackid)
  411. local pistonspec = get_pistonspec(node.name, "onname")
  412. local dir = vector.multiply(minetest.facedir_to_dir(node.param2), -1)
  413. local pusherpos = vector.add(stack[stackid].pos, dir)
  414. local pushernode = minetest.get_node(pusherpos)
  415. if pistonspec.pusher == pushernode.name then
  416. for _, s in ipairs(stack) do
  417. if vector.equals(s.pos, pusherpos) -- pusher is also to be pushed
  418. and s.node.param2 == node.param2 then
  419. return false
  420. end
  421. end
  422. end
  423. return true
  424. end
  425. mesecon.register_mvps_stopper("mesecons_pistons:piston_normal_on", piston_get_stopper)
  426. mesecon.register_mvps_stopper("mesecons_pistons:piston_sticky_on", piston_get_stopper)
  427. --craft recipes
  428. minetest.register_craft({
  429. output = "mesecons_pistons:piston_normal_off 2",
  430. recipe = {
  431. {"group:wood", "group:wood", "group:wood"},
  432. {"default:cobble", "default:steel_ingot", "default:cobble"},
  433. {"default:cobble", "group:mesecon_conductor_craftable", "default:cobble"},
  434. }
  435. })
  436. minetest.register_craft({
  437. output = "mesecons_pistons:piston_sticky_off",
  438. recipe = {
  439. {"mesecons_materials:glue"},
  440. {"mesecons_pistons:piston_normal_off"},
  441. }
  442. })
  443. -- load legacy code
  444. dofile(minetest.get_modpath("mesecons_pistons")..DIR_DELIM.."legacy.lua")