portal_defs.lua 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. function meseportals.swap_portal_node(pos,name,dir)
  2. local node = core.get_node(pos)
  3. local meta = core.get_meta(pos)
  4. meta:set_string("dont_destroy","true")
  5. local meta0 = meta:to_table()
  6. node.name = name
  7. node.param2=dir
  8. core.set_node(pos,{name=name, param2=dir})
  9. meta:from_table(meta0)
  10. meta:set_string("dont_destroy","false")
  11. end
  12. minetest.register_node("meseportals:portal_collider",{
  13. drawtype = "airlike",
  14. on_blast = function() end,
  15. drop = "",
  16. groups = {not_in_creative_inventory=1,immovable=2},
  17. sunlight_propagates = true,
  18. can_dig = false,
  19. paramtype = "light",
  20. selection_box = {
  21. type = "fixed",
  22. fixed={0.0,0.0,0.0,0.0,0.0,0.0}},
  23. })
  24. function placeportalCollider(pos, pos1, player)
  25. local placed = false
  26. if minetest.check_player_privs(player, {protection_bypass=true}) or not minetest.is_protected(pos, player:get_player_name()) then
  27. if minetest.registered_nodes[minetest.get_node(pos).name] then
  28. if minetest.get_node(pos).name == "air" or minetest.registered_nodes[minetest.get_node(pos).name].buildable_to then
  29. core.set_node(pos,{name="meseportals:portal_collider"})
  30. local meta = minetest.get_meta(pos)
  31. meta:set_string("portal", minetest.pos_to_string(pos1))
  32. placed = true
  33. end
  34. end
  35. end
  36. return placed
  37. end
  38. local function placeportal(player,pos)
  39. if minetest.check_player_privs(player, {msp_unlimited=true}) or meseportals.maxPlayerPortals > #meseportals_network[player:get_player_name()] then
  40. local dir = minetest.dir_to_facedir(player:get_look_dir())
  41. local pos1 = vector.new(pos)
  42. local hadRoom = true
  43. if dir == 1
  44. or dir == 3 then
  45. pos1.z=pos1.z+2
  46. hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
  47. pos1.y=pos1.y+1
  48. hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
  49. pos1.y=pos1.y+1
  50. hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
  51. pos1.y=pos1.y+1
  52. hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
  53. pos1.z=pos1.z-1
  54. hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
  55. pos1.z=pos1.z-1
  56. hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
  57. pos1.z=pos1.z-1
  58. hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
  59. pos1.z=pos1.z-1
  60. hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
  61. pos1.y=pos1.y-1
  62. hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
  63. pos1.y=pos1.y-1
  64. hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
  65. pos1.y=pos1.y-1
  66. hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
  67. pos1.y=pos1.y-1
  68. placeportalCollider(pos1, pos, player)
  69. pos1.z=pos1.z+1
  70. placeportalCollider(pos1, pos, player)
  71. pos1.z=pos1.z+1
  72. placeportalCollider(pos1, pos, player)
  73. pos1.z=pos1.z+1
  74. placeportalCollider(pos1, pos, player)
  75. pos1.z=pos1.z+1
  76. placeportalCollider(pos1, pos, player)
  77. else
  78. pos1.x=pos1.x+2
  79. hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
  80. pos1.y=pos1.y+1
  81. hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
  82. pos1.y=pos1.y+1
  83. hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
  84. pos1.y=pos1.y+1
  85. hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
  86. pos1.x=pos1.x-1
  87. hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
  88. pos1.x=pos1.x-1
  89. hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
  90. pos1.x=pos1.x-1
  91. hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
  92. pos1.x=pos1.x-1
  93. hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
  94. pos1.y=pos1.y-1
  95. hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
  96. pos1.y=pos1.y-1
  97. hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
  98. pos1.y=pos1.y-1
  99. hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
  100. pos1.y=pos1.y-1
  101. placeportalCollider(pos1, pos, player)
  102. pos1.x=pos1.x+1
  103. placeportalCollider(pos1, pos, player)
  104. pos1.x=pos1.x+1
  105. placeportalCollider(pos1, pos, player)
  106. pos1.x=pos1.x+1
  107. placeportalCollider(pos1, pos, player)
  108. pos1.x=pos1.x+1
  109. placeportalCollider(pos1, pos, player)
  110. end
  111. if hadRoom then
  112. meseportals.swap_portal_node(pos,"meseportals:portalnode_off",dir)
  113. local player_name = player:get_player_name()
  114. meseportals.registerPortal(player_name, pos, dir)
  115. return true
  116. else
  117. minetest.remove_node(pos)
  118. minetest.chat_send_player(player:get_player_name(), "Not enough room!")
  119. end
  120. else
  121. minetest.chat_send_player(player:get_player_name(), "You have reached the maximum allowed number of portals!")
  122. core.remove_node(pos)
  123. end
  124. end
  125. function meseportals.activatePortal(pos)
  126. local portal = meseportals.findPortal(pos)
  127. if meseportals.findPortal(pos) then
  128. portal["updateme"] = true
  129. meseportals.save_data(portal["owner"])
  130. end
  131. end
  132. function meseportals.deactivatePortal(pos)
  133. local portal = meseportals.findPortal(pos)
  134. if portal then
  135. portal["destination"] = nil
  136. portal["destination_description"] = nil
  137. portal["destination_dir"] = nil
  138. portal["updateme"] = true
  139. meseportals.save_data(portal["owner"])
  140. end
  141. end
  142. local function removeportal(pos)
  143. if (meseportals.findPortal(pos) ~= nil) then
  144. local meta = core.get_meta(pos)
  145. if meta:get_string("dont_destroy") == "true" then
  146. -- when swapping it
  147. return
  148. end
  149. if meseportals.findPortal(pos)["destination"] then
  150. meseportals.deactivatePortal(meseportals.findPortal(pos)["destination"])
  151. end
  152. meseportals.unregisterPortal(pos)
  153. end
  154. end
  155. local msp_selection_box = {
  156. type = "fixed",
  157. fixed={{-2.5,-1.5,-0.2,2.5,3.5,0.2},},
  158. }
  159. local msp_groups = {cracky=2,not_in_creative_inventory=1,immovable=2}
  160. local msp_groups1 = {cracky=2,immovabl=2}
  161. local old_pttfp = minetest.pointed_thing_to_face_pos
  162. minetest.pointed_thing_to_face_pos = function(placer, pointed_thing)
  163. if pointed_thing and placer and pointed_thing.above and pointed_thing.under then
  164. if pointed_thing.under.x == pointed_thing.above.x and pointed_thing.under.y == pointed_thing.above.y and pointed_thing.under.z == pointed_thing.above.z then
  165. return placer:get_pos()
  166. else
  167. return old_pttfp(placer, pointed_thing)
  168. end
  169. else
  170. return vector.new(0,0,0)
  171. end
  172. end
  173. minetest.register_node("meseportals:portalnode_on",{
  174. tiles = {
  175. --{name = "gray.png"},
  176. --{
  177. --name = "puddle_animated.png",
  178. --animation = {
  179. -- type = "vertical_frames",
  180. -- aspect_w = 16,
  181. -- aspect_h = 16,
  182. -- length = 2.0,
  183. -- },
  184. --},
  185. {name = "meseportal_vortex.png",--Portal
  186. animation = {
  187. type = "vertical_frames",
  188. },
  189. },
  190. {name = "meseportal_mese_on.png", --Buttons
  191. animation = {
  192. type = "vertical_frames",
  193. },
  194. },
  195. {name = "meseportal_mese_on.png", --Cables
  196. animation = {
  197. type = "vertical_frames",
  198. },
  199. },
  200. {name = "meseportal_mese_on.png", --Coil
  201. animation = {
  202. type = "vertical_frames",
  203. },
  204. },
  205. {name = "meseportal_frame.png"}, --Frame
  206. },
  207. drawtype = "mesh",
  208. mesh = "meseportal.obj",
  209. visual_scale = 5.0,
  210. groups = msp_groups,
  211. drop = "meseportals:portalnode_off",
  212. paramtype2 = "facedir",
  213. paramtype = "light",
  214. light_source = 5,
  215. selection_box = msp_selection_box,
  216. walkable = false,
  217. on_destruct = removeportal,
  218. on_rightclick=meseportals.portalFormspecHandler,
  219. })
  220. minetest.register_node("meseportals:portalnode_off",{
  221. description = "Mese Portal (Sneak+Place = Buried)",
  222. inventory_image = "meseportal.png",
  223. wield_image = "meseportal.png",
  224. tiles = {
  225. {name = "meseportal_null.png"},
  226. {name = "meseportal_mese_off.png"},
  227. {name = "meseportal_mese_off.png"},
  228. {name = "meseportal_mese_off.png"},
  229. {name = "meseportal_frame.png"},
  230. },
  231. groups = msp_groups1,
  232. paramtype2 = "facedir",
  233. paramtype = "light",
  234. drawtype = "mesh",
  235. drop = "meseportals:portalnode_off",
  236. mesh = "meseportal.obj",
  237. visual_scale = 5.0,
  238. selection_box = msp_selection_box,
  239. walkable = false,
  240. on_destruct = removeportal,
  241. on_place = function(itemstack, placer, pointed_thing)
  242. local pos = pointed_thing.above
  243. if minetest.registered_nodes[minetest.get_node(pointed_thing.under).name] then
  244. if minetest.registered_nodes[minetest.get_node(pointed_thing.under).name].on_rightclick and not placer:get_player_control().sneak then
  245. return minetest.registered_nodes[minetest.get_node(pointed_thing.under).name].on_rightclick(pointed_thing.under, minetest.get_node(pointed_thing.under), placer, itemstack, pointed_thing)
  246. end
  247. if minetest.registered_nodes[minetest.get_node(pointed_thing.under).name].buildable_to then
  248. pos = pointed_thing.under
  249. end
  250. end
  251. if minetest.check_player_privs(placer, {protection_bypass=true}) or not minetest.is_protected(pos, placer:get_player_name()) then
  252. minetest.item_place(itemstack, placer, pointed_thing, minetest.dir_to_facedir(placer:get_look_dir()))
  253. local node = minetest.get_node(pos)
  254. local meta = minetest.get_meta(pos)
  255. if placer:get_player_control().sneak then
  256. minetest.set_node(pos, node)
  257. else
  258. minetest.remove_node(pos)
  259. pos.y = pos.y + 1
  260. minetest.set_node(pos, node)
  261. end
  262. if placeportal(placer,pos) then
  263. return itemstack
  264. else
  265. return nil
  266. end
  267. end
  268. end,
  269. on_rightclick=meseportals.portalFormspecHandler,
  270. })
  271. local old_protected = minetest.is_protected
  272. local basecheck = { --f = face (x or z axis)
  273. {x=0, z=0, f=0},
  274. {x=1, z=0, f=1},
  275. {x=2, z=0, f=1},
  276. {x=-1, z=0, f=1},
  277. {x=-2, z=0, f=1},
  278. {x=0, z=1, f=2},
  279. {x=0, z=2, f=2},
  280. {x=0, z=-1, f=2},
  281. {x=0, z=-2, f=2},
  282. }
  283. minetest.is_protected = function(pos, player, ...) --Protect the bottom of the portal
  284. if not pos then return end
  285. local pos1 = vector.new(pos.x, pos.y + 1, pos.z) --Allocate
  286. local portal
  287. for _,pos2 in pairs(basecheck) do
  288. pos1.x = pos.x + pos2.x
  289. pos1.z = pos.z + pos2.z
  290. portal = meseportals.findPortal(pos1)
  291. if portal then
  292. if pos2.f == 0 then return true end --Right under
  293. if (pos2.f == 1) == (portal.dir == 0 or portal.dir == 2) then --Adjacent, XNOR with facedir
  294. return true
  295. end
  296. end
  297. end
  298. portal = meseportals.findPortal(pos)
  299. if portal and not minetest.check_player_privs(player, {msp_admin=true}) then
  300. if portal.owner ~= player then
  301. minetest.chat_send_player(player, "This portal belongs to " ..portal["owner"] .."!")
  302. return true
  303. end
  304. if portal.admin_lock then
  305. minetest.chat_send_player(player, "This portal has been locked by an admin.")
  306. return true
  307. end
  308. end
  309. return old_protected(pos, player, ...)
  310. end
  311. local usePortalController = function(pos, clicker)
  312. if meseportals.findPortal(pos) then
  313. meseportals.portalFormspecHandler(pos, nil, clicker, nil)
  314. else
  315. minetest.chat_send_player(clicker:get_player_name(), "The linked portal was moved or destroyed. Link this controller to a new portal.")
  316. end
  317. end
  318. minetest.register_node("meseportals:linked_portal_controller", {
  319. description = "Linked Portal Controller",
  320. inventory_image = "meseportal_controller_inventory.png",
  321. wield_image = "meseportal_controller_inventory.png",
  322. tiles = {{name = "meseportal_controller.png"}},
  323. drawtype = "mesh",
  324. paramtype = "light",
  325. paramtype2 = "facedir",
  326. mesh = "meseportal_controller.obj",
  327. drop = "meseportals:unlinked_portal_controller",
  328. groups = {cracky=3,oddly_breakable_by_hand=2,not_in_creative_inventory=1},
  329. stack_max = 1,
  330. walkable = true,
  331. light_source = 5,
  332. selection_box = {
  333. type = "fixed",
  334. fixed={{-0.425,-0.325,0.5,0.45,0.325,0.425},},
  335. },
  336. collision_box = {
  337. type = "fixed",
  338. fixed={{-0.425,-0.325,0.5,0.45,0.325,0.425},},
  339. },
  340. on_place = function(itemstack, placer, pointed_thing)
  341. if minetest.check_player_privs(placer, {protection_bypass=true}) or not minetest.is_protected(pointed_thing.above, placer:get_player_name()) then
  342. local rightClicked = minetest.get_node(pointed_thing.under).name
  343. if not placer:get_player_control().sneak then
  344. if rightClicked == "meseportals:portalnode_on" or rightClicked == "meseportals:portalnode_off" then
  345. local portal = meseportals.findPortal(pointed_thing.under)
  346. if portal then
  347. if portal["type"] == "public" or placer:get_player_name() == portal["owner"] or minetest.check_player_privs(placer, {msp_admin=true}) or not meseportals.allowPrivatePortals then
  348. minetest.chat_send_player(placer:get_player_name(), "Controller linked to "..portal["description"])
  349. itemstack:get_meta():set_string("portal", minetest.pos_to_string(pointed_thing.under))
  350. itemstack:get_meta():set_string("description", "Linked Portal Controller ["..portal["description"].."]")
  351. return itemstack
  352. else
  353. minetest.chat_send_player(placer:get_player_name(), portal["owner"] .." has set this portal to private.")
  354. end
  355. else
  356. minetest.chat_send_player(placer:get_player_name(), "This portal is broken.")
  357. end
  358. elseif minetest.registered_nodes[rightClicked] and minetest.registered_nodes[rightClicked].on_rightclick then
  359. return minetest.registered_nodes[rightClicked].on_rightclick(pointed_thing.under, minetest.get_node(pointed_thing.under), placer, itemstack, pointed_thing)
  360. end
  361. end
  362. local p
  363. if minetest.registered_nodes[minetest.get_node(pointed_thing.under).name] and minetest.registered_nodes[minetest.get_node(pointed_thing.under).name].buildable_to then
  364. p = pointed_thing.under
  365. else
  366. p = pointed_thing.above
  367. end
  368. local portalID = itemstack:get_meta():get_string("portal")
  369. minetest.item_place(itemstack, placer, pointed_thing, minetest.dir_to_facedir(placer:get_look_dir()))
  370. local meta = minetest.get_meta(p)
  371. meta:set_string("portal", portalID)
  372. return itemstack
  373. end
  374. end,
  375. on_use = function(itemstack, user)
  376. local pos1 = minetest.string_to_pos(itemstack:get_meta():get_string("portal"))
  377. usePortalController(pos1, user)
  378. end,
  379. on_rightclick = function(pos, node, clicker)
  380. local pos1 = minetest.string_to_pos(minetest.get_meta(pos):get_string("portal"))
  381. usePortalController(pos1, clicker)
  382. end
  383. })
  384. minetest.register_node("meseportals:unlinked_portal_controller", {
  385. description = "Unlinked Portal Controller",
  386. inventory_image = "meseportal_controller_inventory_unlinked.png",
  387. wield_image = "meseportal_controller_inventory_unlinked.png",
  388. tiles = {{name = "meseportal_controller_unlinked.png"}},
  389. drawtype = "mesh",
  390. paramtype = "light",
  391. paramtype2 = "facedir",
  392. mesh = "meseportal_controller.obj",
  393. drop = "meseportals:unlinked_portal_controller",
  394. groups = {cracky=3,oddly_breakable_by_hand=2},
  395. walkable = true,
  396. selection_box = {
  397. type = "fixed",
  398. fixed={{-0.425,-0.325,0.5,0.45,0.325,0.425},},
  399. },
  400. collision_box = {
  401. type = "fixed",
  402. fixed={{-0.425,-0.325,0.5,0.45,0.325,0.425},},
  403. },
  404. on_place = function(itemstack, placer, pointed_thing)
  405. local rightClicked = minetest.get_node(pointed_thing.under).name
  406. if not placer:get_player_control().sneak then
  407. if rightClicked == "meseportals:portalnode_on" or rightClicked == "meseportals:portalnode_off" then
  408. local portal = meseportals.findPortal(pointed_thing.under)
  409. if portal then
  410. if portal["type"] == "public" or placer:get_player_name() == portal["owner"] or minetest.check_player_privs(placer, {msp_admin=true}) then
  411. minetest.chat_send_player(placer:get_player_name(), "Controller linked to "..portal["description"])
  412. itemstack:set_name("meseportals:linked_portal_controller")
  413. itemstack:get_meta():set_string("portal", minetest.pos_to_string(pointed_thing.under))
  414. itemstack:get_meta():set_string("description", "Linked Portal Controller ["..portal["description"].."]")
  415. return itemstack
  416. else
  417. minetest.chat_send_player(placer:get_player_name(), portal["owner"] .." has set this portal to private.")
  418. return
  419. end
  420. else
  421. minetest.chat_send_player(placer:get_player_name(), "This portal is broken.")
  422. end
  423. elseif minetest.registered_nodes[rightClicked] and minetest.registered_nodes[rightClicked].on_rightclick then
  424. return minetest.registered_nodes[rightClicked].on_rightclick(pointed_thing.under, minetest.get_node(pointed_thing.under), placer, itemstack, pointed_thing)
  425. end
  426. end
  427. return minetest.item_place(itemstack, placer, pointed_thing, minetest.dir_to_facedir(placer:get_look_dir()))
  428. end,
  429. on_use = function(_, user)
  430. minetest.chat_send_player(user:get_player_name(), "This controller is not linked. Link this controller to a portal by right-clicking the portal.")
  431. end,
  432. on_rightclick = function(_, __, user)
  433. minetest.chat_send_player(user:get_player_name(), "This controller is not linked. Link this controller to a portal by right-clicking the portal.")
  434. end,
  435. })
  436. minetest.register_craftitem("meseportals:portal_segment", {
  437. description = "Encased Mesenetic Field Coil",
  438. inventory_image = "meseportal_portal_part.png",
  439. wield_image = "meseportal_portal_part.png",
  440. })
  441. minetest.register_craftitem("meseportals:tesseract_crystal", {
  442. description = "Tesseract Crystal",
  443. inventory_image = "meseportal_tesseract.png",
  444. wield_image = "meseportal_tesseract.png",
  445. })