init.lua 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  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. local function node_detector_send_node_name(pos, node, channel, meta)
  163. local distance = meta:get_int("distance")
  164. local distance_max = mesecon.setting("node_detector_distance_max", 10)
  165. if distance < 0 then distance = 0 end
  166. if distance > distance_max then distance = distance_max end
  167. local nodename = minetest.get_node(
  168. vector.subtract(pos, vector.multiply(minetest.facedir_to_dir(node.param2), distance + 1))
  169. ).name
  170. digiline:receptor_send(pos, digiline.rules.default, channel, nodename)
  171. end
  172. -- set player name when receiving a digiline signal on a specific channel
  173. local node_detector_digiline = {
  174. effector = {
  175. action = function(pos, node, channel, msg)
  176. local meta = minetest.get_meta(pos)
  177. if channel ~= meta:get_string("digiline_channel") then return end
  178. if type(msg) == "table" then
  179. if msg.distance or msg.scanname then
  180. if msg.distance then
  181. meta:set_string("distance", msg.distance)
  182. end
  183. if msg.scanname then
  184. meta:set_string("scanname", msg.scanname)
  185. end
  186. node_detector_make_formspec(pos)
  187. end
  188. if msg.command == "get" then
  189. node_detector_send_node_name(pos, node, channel, meta)
  190. elseif msg.command == "scan" then
  191. local result = node_detector_scan(pos)
  192. digiline:receptor_send(pos, digiline.rules.default, channel, result)
  193. end
  194. else
  195. if msg == GET_COMMAND then
  196. node_detector_send_node_name(pos, node, channel, meta)
  197. else
  198. meta:set_string("scanname", msg)
  199. node_detector_make_formspec(pos)
  200. end
  201. end
  202. end,
  203. },
  204. receptor = {}
  205. }
  206. local function after_place_node_detector(pos, placer)
  207. local placer_pos = placer:getpos()
  208. if not placer_pos then
  209. return
  210. end
  211. --correct for the player's height
  212. if placer:is_player() then
  213. placer_pos.y = placer_pos.y + 1.625
  214. end
  215. --correct for 6d facedir
  216. local node = minetest.get_node(pos)
  217. node.param2 = minetest.dir_to_facedir(vector.subtract(pos, placer_pos), true)
  218. minetest.set_node(pos, node)
  219. end
  220. minetest.register_node("mesecons_detector:node_detector_off", {
  221. 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"},
  222. paramtype = "light",
  223. paramtype2 = "facedir",
  224. is_ground_content = false,
  225. walkable = true,
  226. groups = {cracky=3},
  227. description="Node Detector",
  228. mesecons = {receptor = {
  229. state = mesecon.state.off
  230. }},
  231. on_construct = node_detector_make_formspec,
  232. on_receive_fields = node_detector_on_receive_fields,
  233. sounds = default.node_sound_stone_defaults(),
  234. digiline = node_detector_digiline,
  235. on_blast = mesecon.on_blastnode,
  236. })
  237. minetest.register_node("mesecons_detector:node_detector_on", {
  238. 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"},
  239. paramtype = "light",
  240. paramtype2 = "facedir",
  241. is_ground_content = false,
  242. walkable = true,
  243. groups = {cracky=3,not_in_creative_inventory=1},
  244. drop = 'mesecons_detector:node_detector_off',
  245. mesecons = {receptor = {
  246. state = mesecon.state.on
  247. }},
  248. on_construct = node_detector_make_formspec,
  249. on_receive_fields = node_detector_on_receive_fields,
  250. sounds = default.node_sound_stone_defaults(),
  251. digiline = node_detector_digiline,
  252. on_blast = mesecon.on_blastnode,
  253. })
  254. minetest.register_craft({
  255. output = 'mesecons_detector:node_detector_off',
  256. recipe = {
  257. {"default:steel_ingot", "group:mesecon_conductor_craftable", "default:steel_ingot"},
  258. {"default:steel_ingot", "mesecons_luacontroller:luacontroller0000", "default:steel_ingot"},
  259. {"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"},
  260. }
  261. })
  262. minetest.register_craft({
  263. output = 'mesecons_detector:node_detector_off',
  264. recipe = {
  265. {"default:steel_ingot", "group:mesecon_conductor_craftable", "default:steel_ingot"},
  266. {"default:steel_ingot", "mesecons_microcontroller:microcontroller0000", "default:steel_ingot"},
  267. {"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"},
  268. }
  269. })
  270. minetest.register_abm({
  271. nodenames = {"mesecons_detector:node_detector_off"},
  272. interval = 1,
  273. chance = 1,
  274. action = function(pos, node)
  275. if not node_detector_scan(pos) then return end
  276. node.name = "mesecons_detector:node_detector_on"
  277. minetest.swap_node(pos, node)
  278. mesecon.receptor_on(pos)
  279. end,
  280. })
  281. minetest.register_abm({
  282. nodenames = {"mesecons_detector:node_detector_on"},
  283. interval = 1,
  284. chance = 1,
  285. action = function(pos, node)
  286. if node_detector_scan(pos) then return end
  287. node.name = "mesecons_detector:node_detector_off"
  288. minetest.swap_node(pos, node)
  289. mesecon.receptor_off(pos)
  290. end,
  291. })