init.lua 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. local GET_COMMAND = "GET"
  2. -- Object detector
  3. -- Detects players in a certain radius
  4. -- The radius can be specified in mesecons/settings.lua
  5. local function object_detector_make_formspec(pos)
  6. local meta = minetest.get_meta(pos)
  7. meta:set_string("formspec", "size[9,2.5]" ..
  8. "field[0.3, 0;9,2;scanname;Name of player to scan for (empty for any):;${scanname}]"..
  9. "field[0.3,1.5;4,2;digiline_channel;Digiline Channel (optional):;${digiline_channel}]"..
  10. "button_exit[7,0.75;2,3;;Save]")
  11. end
  12. local function object_detector_on_receive_fields(pos, formname, fields, sender)
  13. if not fields.scanname or not fields.digiline_channel then return end
  14. if minetest.is_protected(pos, sender:get_player_name()) then return end
  15. local meta = minetest.get_meta(pos)
  16. meta:set_string("scanname", fields.scanname)
  17. meta:set_string("digiline_channel", fields.digiline_channel)
  18. object_detector_make_formspec(pos)
  19. end
  20. -- returns true if player was found, false if not
  21. local function object_detector_scan(pos)
  22. local objs = minetest.get_objects_inside_radius(pos, mesecon.setting("detector_radius", 6))
  23. -- abort if no scan results were found
  24. if next(objs) == nil then return false end
  25. local scanname = minetest.get_meta(pos):get_string("scanname")
  26. local scan_for = {}
  27. for _, str in pairs(string.split(scanname:gsub(" ", ""), ",")) do
  28. scan_for[str] = true
  29. end
  30. local every_player = scanname == ""
  31. for _, obj in pairs(objs) do
  32. -- "" is returned if it is not a player; "" ~= nil; so only handle objects with foundname ~= ""
  33. local foundname = obj:get_player_name()
  34. if foundname ~= "" then
  35. if every_player or scan_for[foundname] then
  36. return true
  37. end
  38. end
  39. end
  40. return false
  41. end
  42. -- set player name when receiving a digiline signal on a specific channel
  43. local object_detector_digiline = {
  44. effector = {
  45. action = function(pos, node, channel, msg)
  46. local meta = minetest.get_meta(pos)
  47. if channel == meta:get_string("digiline_channel") then
  48. meta:set_string("scanname", msg)
  49. object_detector_make_formspec(pos)
  50. end
  51. end,
  52. }
  53. }
  54. minetest.register_node("mesecons_detector:object_detector_off", {
  55. tiles = {"default_steel_block.png", "default_steel_block.png", "jeija_object_detector_off.png", "jeija_object_detector_off.png", "jeija_object_detector_off.png", "jeija_object_detector_off.png"},
  56. paramtype = "light",
  57. is_ground_content = false,
  58. walkable = true,
  59. groups = {cracky=3},
  60. description="Player Detector",
  61. mesecons = {receptor = {
  62. state = mesecon.state.off,
  63. rules = mesecon.rules.pplate
  64. }},
  65. on_construct = object_detector_make_formspec,
  66. on_receive_fields = object_detector_on_receive_fields,
  67. sounds = default.node_sound_stone_defaults(),
  68. digiline = object_detector_digiline,
  69. on_blast = mesecon.on_blastnode,
  70. })
  71. minetest.register_node("mesecons_detector:object_detector_on", {
  72. tiles = {"default_steel_block.png", "default_steel_block.png", "jeija_object_detector_on.png", "jeija_object_detector_on.png", "jeija_object_detector_on.png", "jeija_object_detector_on.png"},
  73. paramtype = "light",
  74. is_ground_content = false,
  75. walkable = true,
  76. groups = {cracky=3,not_in_creative_inventory=1},
  77. drop = 'mesecons_detector:object_detector_off',
  78. mesecons = {receptor = {
  79. state = mesecon.state.on,
  80. rules = mesecon.rules.pplate
  81. }},
  82. on_construct = object_detector_make_formspec,
  83. on_receive_fields = object_detector_on_receive_fields,
  84. sounds = default.node_sound_stone_defaults(),
  85. digiline = object_detector_digiline,
  86. on_blast = mesecon.on_blastnode,
  87. })
  88. minetest.register_craft({
  89. output = 'mesecons_detector:object_detector_off',
  90. recipe = {
  91. {"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"},
  92. {"default:steel_ingot", "mesecons_luacontroller:luacontroller0000", "default:steel_ingot"},
  93. {"default:steel_ingot", "group:mesecon_conductor_craftable", "default:steel_ingot"},
  94. }
  95. })
  96. minetest.register_craft({
  97. output = 'mesecons_detector:object_detector_off',
  98. recipe = {
  99. {"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"},
  100. {"default:steel_ingot", "mesecons_microcontroller:microcontroller0000", "default:steel_ingot"},
  101. {"default:steel_ingot", "group:mesecon_conductor_craftable", "default:steel_ingot"},
  102. }
  103. })
  104. minetest.register_abm({
  105. nodenames = {"mesecons_detector:object_detector_off"},
  106. interval = 1,
  107. chance = 1,
  108. action = function(pos, node)
  109. if not object_detector_scan(pos) then return end
  110. node.name = "mesecons_detector:object_detector_on"
  111. minetest.swap_node(pos, node)
  112. mesecon.receptor_on(pos, mesecon.rules.pplate)
  113. end,
  114. })
  115. minetest.register_abm({
  116. nodenames = {"mesecons_detector:object_detector_on"},
  117. interval = 1,
  118. chance = 1,
  119. action = function(pos, node)
  120. if object_detector_scan(pos) then return end
  121. node.name = "mesecons_detector:object_detector_off"
  122. minetest.swap_node(pos, node)
  123. mesecon.receptor_off(pos, mesecon.rules.pplate)
  124. end,
  125. })
  126. -- Node detector
  127. -- Detects the node in front of it
  128. local function node_detector_make_formspec(pos)
  129. local meta = minetest.get_meta(pos)
  130. if meta:get_string("distance") == "" then meta:set_string("distance", "0") end
  131. meta:set_string("formspec", "size[9,2.5]" ..
  132. "field[0.3, 0;9,2;scanname;Name of node to scan for (empty for any):;${scanname}]"..
  133. "field[0.3,1.5;2.5,2;distance;Distance (0-"..mesecon.setting("node_detector_distance_max", 10).."):;${distance}]"..
  134. "field[3,1.5;4,2;digiline_channel;Digiline Channel (optional):;${digiline_channel}]"..
  135. "button_exit[7,0.75;2,3;;Save]")
  136. end
  137. local function node_detector_on_receive_fields(pos, fieldname, fields, sender)
  138. if not fields.scanname or not fields.digiline_channel then return end
  139. if minetest.is_protected(pos, sender:get_player_name()) then return end
  140. local meta = minetest.get_meta(pos)
  141. meta:set_string("scanname", fields.scanname)
  142. meta:set_string("distance", fields.distance or "0")
  143. meta:set_string("digiline_channel", fields.digiline_channel)
  144. node_detector_make_formspec(pos)
  145. end
  146. -- returns true if node was found, false if not
  147. local function node_detector_scan(pos)
  148. local node = minetest.get_node_or_nil(pos)
  149. if not node then return end
  150. local meta = minetest.get_meta(pos)
  151. local distance = meta:get_int("distance")
  152. local distance_max = mesecon.setting("node_detector_distance_max", 10)
  153. if distance < 0 then distance = 0 end
  154. if distance > distance_max then distance = distance_max end
  155. local frontname = minetest.get_node(
  156. vector.subtract(pos, vector.multiply(minetest.facedir_to_dir(node.param2), distance + 1))
  157. ).name
  158. local scanname = meta:get_string("scanname")
  159. return (frontname == scanname) or
  160. (frontname ~= "air" and frontname ~= "ignore" and scanname == "")
  161. end
  162. -- set player name when receiving a digiline signal on a specific channel
  163. local node_detector_digiline = {
  164. effector = {
  165. action = function(pos, node, channel, msg)
  166. local meta = minetest.get_meta(pos)
  167. local distance = meta:get_int("distance")
  168. local distance_max = mesecon.setting("node_detector_distance_max", 10)
  169. if distance < 0 then distance = 0 end
  170. if distance > distance_max then distance = distance_max end
  171. if channel ~= meta:get_string("digiline_channel") then return end
  172. if msg == GET_COMMAND then
  173. local nodename = minetest.get_node(
  174. vector.subtract(pos, vector.multiply(minetest.facedir_to_dir(node.param2), distance + 1))
  175. ).name
  176. digiline:receptor_send(pos, digiline.rules.default, channel, nodename)
  177. else
  178. meta:set_string("scanname", msg)
  179. node_detector_make_formspec(pos)
  180. end
  181. end,
  182. },
  183. receptor = {}
  184. }
  185. local function after_place_node_detector(pos, placer)
  186. local placer_pos = placer:getpos()
  187. if not placer_pos then
  188. return
  189. end
  190. --correct for the player's height
  191. if placer:is_player() then
  192. placer_pos.y = placer_pos.y + 1.625
  193. end
  194. --correct for 6d facedir
  195. local node = minetest.get_node(pos)
  196. node.param2 = minetest.dir_to_facedir(vector.subtract(pos, placer_pos), true)
  197. minetest.set_node(pos, node)
  198. end
  199. minetest.register_node("mesecons_detector:node_detector_off", {
  200. tiles = {"default_steel_block.png", "default_steel_block.png", "default_steel_block.png", "default_steel_block.png", "default_steel_block.png", "jeija_node_detector_off.png"},
  201. paramtype = "light",
  202. paramtype2 = "facedir",
  203. is_ground_content = false,
  204. walkable = true,
  205. groups = {cracky=3},
  206. description="Node Detector",
  207. mesecons = {receptor = {
  208. state = mesecon.state.off
  209. }},
  210. on_construct = node_detector_make_formspec,
  211. on_receive_fields = node_detector_on_receive_fields,
  212. sounds = default.node_sound_stone_defaults(),
  213. digiline = node_detector_digiline,
  214. on_blast = mesecon.on_blastnode,
  215. })
  216. minetest.register_node("mesecons_detector:node_detector_on", {
  217. tiles = {"default_steel_block.png", "default_steel_block.png", "default_steel_block.png", "default_steel_block.png", "default_steel_block.png", "jeija_node_detector_on.png"},
  218. paramtype = "light",
  219. paramtype2 = "facedir",
  220. is_ground_content = false,
  221. walkable = true,
  222. groups = {cracky=3,not_in_creative_inventory=1},
  223. drop = 'mesecons_detector:node_detector_off',
  224. mesecons = {receptor = {
  225. state = mesecon.state.on
  226. }},
  227. on_construct = node_detector_make_formspec,
  228. on_receive_fields = node_detector_on_receive_fields,
  229. sounds = default.node_sound_stone_defaults(),
  230. digiline = node_detector_digiline,
  231. on_blast = mesecon.on_blastnode,
  232. })
  233. minetest.register_craft({
  234. output = 'mesecons_detector:node_detector_off',
  235. recipe = {
  236. {"default:steel_ingot", "group:mesecon_conductor_craftable", "default:steel_ingot"},
  237. {"default:steel_ingot", "mesecons_luacontroller:luacontroller0000", "default:steel_ingot"},
  238. {"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"},
  239. }
  240. })
  241. minetest.register_craft({
  242. output = 'mesecons_detector:node_detector_off',
  243. recipe = {
  244. {"default:steel_ingot", "group:mesecon_conductor_craftable", "default:steel_ingot"},
  245. {"default:steel_ingot", "mesecons_microcontroller:microcontroller0000", "default:steel_ingot"},
  246. {"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"},
  247. }
  248. })
  249. minetest.register_abm({
  250. nodenames = {"mesecons_detector:node_detector_off"},
  251. interval = 1,
  252. chance = 1,
  253. action = function(pos, node)
  254. if not node_detector_scan(pos) then return end
  255. node.name = "mesecons_detector:node_detector_on"
  256. minetest.swap_node(pos, node)
  257. mesecon.receptor_on(pos)
  258. end,
  259. })
  260. minetest.register_abm({
  261. nodenames = {"mesecons_detector:node_detector_on"},
  262. interval = 1,
  263. chance = 1,
  264. action = function(pos, node)
  265. if node_detector_scan(pos) then return end
  266. node.name = "mesecons_detector:node_detector_off"
  267. minetest.swap_node(pos, node)
  268. mesecon.receptor_off(pos)
  269. end,
  270. })