init.lua 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780
  1. -- This mod provides an item which enables players to teleport to registered locations without the need of a teleporter.
  2. -- This item doubles as the means by which the server control scripts decide which playerfiles to delete and which to keep.
  3. passport = passport or {}
  4. passport.recalls = passport.recalls or {}
  5. passport.players = passport.players or {}
  6. passport.player_recalls = passport.player_recalls or {}
  7. passport.registered_players = passport.registered_players or {} -- Cache of registered players.
  8. passport.keyed_players = passport.keyed_players or {}
  9. passport.modpath = minetest.get_modpath("passport")
  10. -- List of players with open keys.
  11. -- On formspec close, playername should be removed and close-sound played.
  12. passport.open_keys = passport.open_keys or {}
  13. -- Localize for performance.
  14. local vector_distance = vector.distance
  15. local vector_round = vector.round
  16. local vector_add = vector.add
  17. local math_floor = math.floor
  18. local math_random = math.random
  19. local PASSPORT_TELEPORT_RANGE = 750
  20. minetest.register_privilege("recall", {
  21. description = "Player can request a teleport to nearby recall beacons.",
  22. give_to_singleplayer = false,
  23. })
  24. function passport.is_passport(name)
  25. if name == "passport:passport" then
  26. return true
  27. end
  28. if name == "passport:passport_adv" then
  29. return true
  30. end
  31. return false
  32. end
  33. -- Public API function. Only used by jail mod.
  34. passport.register_recall = function(recalldef)
  35. local name = recalldef.name
  36. local position = recalldef.position
  37. local min_dist = recalldef.min_dist
  38. local on_success = recalldef.on_success
  39. local on_failure = recalldef.on_failure
  40. local tname = recalldef.codename
  41. local suppress = recalldef.suppress
  42. local idx = #(passport.recalls) + 1
  43. local code = "z" .. idx .. ""
  44. passport.recalls[idx] = {
  45. name = name,
  46. position = position,
  47. code = code,
  48. on_success = on_success,
  49. min_dist = min_dist,
  50. on_failure = on_failure,
  51. tname = tname,
  52. suppress = suppress,
  53. }
  54. end
  55. function passport.beacons_to_recalls(beacons)
  56. local recalls = {}
  57. for k, v in ipairs(beacons) do
  58. local idx = #recalls + 1
  59. local real_label = rc.pos_to_string(v.pos)
  60. if v.name ~= nil and v.name ~= "" then
  61. real_label = v.name
  62. end
  63. recalls[idx] = {
  64. name = real_label,
  65. position = function() return vector_add(v.pos, {x=0, y=1, z=0}) end,
  66. code = "v" .. idx .. "",
  67. min_dist = 30,
  68. }
  69. end
  70. return recalls
  71. end
  72. passport.compose_formspec = function(pname)
  73. local buttons = ""
  74. local i = 1
  75. for k, v in pairs(passport.recalls) do
  76. local n = v.name
  77. local c = v.code
  78. if v.tname == "jail:jail" then
  79. buttons = buttons .. "button_exit[3,5.7;2,1;" .. c .. ";" .. n .. "]"
  80. else
  81. buttons = buttons .. "button_exit[6," .. (i-0.3) .. ";3,1;" .. c .. ";" .. n .. "]"
  82. i = i + 1
  83. end
  84. end
  85. local pref = minetest.get_player_by_name(pname)
  86. local beacons = {}
  87. if pref then
  88. local player_pos = pref:get_pos()
  89. -- Shall return an empty table if there are no beacons.
  90. beacons = teleports.nearest_beacons_to_position(player_pos, 6, 1000)
  91. end
  92. passport.player_recalls[pname] = passport.beacons_to_recalls(beacons)
  93. local h = 1
  94. for k, v in ipairs(passport.player_recalls[pname]) do
  95. local n = v.name
  96. local c = v.code
  97. buttons = buttons .. "button_exit[6," .. (h-0.3) .. ";3,1;" .. c .. ";" .. n .. "]"
  98. h = h + 1
  99. end
  100. local boolecho = 'true'
  101. local echo = chat_echo.get_echo(pname)
  102. if echo == true then boolecho = 'true' end
  103. if echo == false then boolecho = 'false' end
  104. local boolparticle = 'true'
  105. local particle = default.particles_enabled_for(pname)
  106. if particle == true then boolparticle = 'true' end
  107. if particle == false then boolparticle = 'false' end
  108. local formspec = "size[10,7]" ..
  109. default.gui_bg ..
  110. default.gui_bg_img ..
  111. default.gui_slots ..
  112. "label[1,0.0;" ..
  113. minetest.formspec_escape("Key Of Citizenship Interface") .. "]" ..
  114. "label[6,0.0;" ..
  115. minetest.formspec_escape("Recalls Nearby (" .. #beacons .. ")") .. "]" ..
  116. buttons ..
  117. "button_exit[1,5.7;2,1;exit;Close]" ..
  118. "button_exit[1,2.7;2,1;mapfix;Fix Map]" ..
  119. "button[3,0.7;2,1;email;Mail]" ..
  120. "button[1,1.7;2,1;survivalist;Survivalist]" ..
  121. "button[3,1.7;2,1;rename;Nickname]" ..
  122. "button[3,2.7;2,1;chatfilter;Chat Filter]" ..
  123. "button[1,0.7;2,1;marker;Markers]" ..
  124. "tooltip[email;Hold 'E' while using the Key to access directly.]" ..
  125. "tooltip[marker;Hold 'sneak' while using the Key to access directly.]" ..
  126. "checkbox[3,5.0;togglechat;Text Echo;" ..
  127. boolecho .. "]" ..
  128. "checkbox[1,5.0;toggleparticles;Particles;" ..
  129. boolparticle .. "]" ..
  130. "tooltip[togglechat;" ..
  131. minetest.formspec_escape(
  132. "Toggle whether the server should echo your chat back to your client.\n" ..
  133. "Newer clients should keep this checked.") .. "]" ..
  134. "tooltip[toggleparticles;" ..
  135. minetest.formspec_escape(
  136. "Toggle whether the server should send game-enhancing particle effects to your client.\n" ..
  137. "Sometimes these are purely for visual effect, sometimes they have gameplay meaning ...") .. "]"
  138. -- Special abilities are revoked for cheaters.
  139. if not sheriff.is_cheater(pname) then
  140. if survivalist.player_beat_cave_challenge(pname) then
  141. formspec = formspec .. "button[1,3.7;2,1;jaunt;Jaunt]"
  142. end
  143. if survivalist.player_beat_nether_challenge(pname) then
  144. if cloaking.is_cloaked(pname) then
  145. formspec = formspec .. "button[3,3.7;2,1;cloak;Uncloak]"
  146. else
  147. formspec = formspec .. "button[3,3.7;2,1;cloak;Cloak]"
  148. end
  149. end
  150. end
  151. for i=1, 7, 1 do
  152. local name = "xdecor:ivy"
  153. if i == 1 then
  154. name = "passport:passport_adv"
  155. elseif i == 7 then
  156. name = "default:sword_steel"
  157. end
  158. formspec = formspec .. "item_image[0," .. i-1 .. ";1,1;" .. name .. "]"
  159. formspec = formspec .. "item_image[9," .. i-1 .. ";1,1;" .. name .. "]"
  160. end
  161. return formspec
  162. end
  163. passport.show_formspec = function(pname)
  164. local formspec = passport.compose_formspec(pname)
  165. minetest.show_formspec(pname, "passport:passport", formspec)
  166. end
  167. passport.on_use = function(itemstack, user, pointed)
  168. local changed = false
  169. if user and user:is_player() then
  170. local pname = user:get_player_name()
  171. -- Check (and if needed, set) owner.
  172. local meta = itemstack:get_meta()
  173. local owner = meta:get_string("owner")
  174. if owner == "" then
  175. owner = pname
  176. -- Store owner and data of activation.
  177. meta:set_string("owner", owner)
  178. meta:set_int("date", os.time())
  179. minetest.after(3, function()
  180. minetest.chat_send_player(pname, "# Server: A newly initialized Key of Citizenship begins to emit a soft blue glow.")
  181. end)
  182. changed = true
  183. end
  184. -- Initialize data if not set.
  185. if meta:get_int("date") == 0 then
  186. meta:set_int("date", os.time())
  187. changed = true
  188. end
  189. if owner ~= pname then
  190. minetest.chat_send_player(pname, "# Server: This Key was initialized by someone else! You cannot access it.")
  191. easyvend.sound_error(pname)
  192. return
  193. end
  194. -- Record number of uses.
  195. meta:set_int("uses", meta:get_int("uses") + 1)
  196. changed = true
  197. local control = user:get_player_control()
  198. if control.sneak then
  199. marker.show_formspec(pname)
  200. elseif control.aux1 then
  201. mailgui.show_formspec(pname)
  202. else
  203. -- Show KoC interface.
  204. passport.show_formspec(pname)
  205. end
  206. passport.open_keys[pname] = true
  207. local ppos = user:get_pos()
  208. minetest.after(0, ambiance.sound_play, "fancy_chime1", ppos, 1.0, 20, "", false)
  209. end
  210. if changed then
  211. return itemstack
  212. end
  213. end
  214. passport.on_use_simple = function(itemstack, user, pointed)
  215. if user and user:is_player() then
  216. minetest.chat_send_player(user:get_player_name(),
  217. "# Server: This awkward chunk of reflective metal seems to mock you, " ..
  218. "yet remains strangely inert. Perhaps it can be upgraded?")
  219. end
  220. return itemstack
  221. end
  222. passport.on_receive_fields = function(player, formname, fields)
  223. if formname ~= "passport:passport" then return end
  224. local pname = player:get_player_name()
  225. if fields.mapfix then
  226. mapfix.command(pname, "")
  227. return true
  228. end
  229. if fields.email then
  230. mailgui.show_formspec(pname)
  231. return true
  232. end
  233. if fields.chatfilter then
  234. chat_controls.show_formspec(pname)
  235. return true
  236. end
  237. if fields.marker then
  238. marker.show_formspec(pname)
  239. return true
  240. end
  241. if fields.jaunt and survivalist.player_beat_cave_challenge(pname) then
  242. -- Jaunt code performs its own security validation.
  243. jaunt.show_formspec(pname)
  244. return true
  245. end
  246. if fields.cloak and survivalist.player_beat_nether_challenge(pname) then
  247. -- Security check to make sure player can use this feature.
  248. if not passport.player_has_key(pname) then
  249. return true
  250. end
  251. if not survivalist.player_beat_nether_challenge(pname) then
  252. return true
  253. end
  254. -- Cloaking ability is revoked for cheaters.
  255. if sheriff.is_cheater(pname) then
  256. return true
  257. end
  258. cloaking.toggle_cloak(pname)
  259. passport.show_formspec(pname) -- Reshow formspec.
  260. return true
  261. end
  262. if fields.survivalist then
  263. survivalist.show_formspec(pname)
  264. return true
  265. end
  266. if fields.rename then
  267. rename.show_formspec(pname)
  268. return true
  269. end
  270. if fields.togglechat then
  271. if fields.togglechat == 'true' then
  272. chat_echo.set_echo(pname, true)
  273. elseif fields.togglechat == 'false' then
  274. chat_echo.set_echo(pname, false)
  275. end
  276. passport.show_formspec(pname) -- Reshow formspec.
  277. return true
  278. end
  279. if fields.toggleparticles then
  280. if fields.toggleparticles == 'true' then
  281. default.enable_particles_for(pname, true)
  282. elseif fields.toggleparticles == 'false' then
  283. default.enable_particles_for(pname, false)
  284. end
  285. passport.show_formspec(pname) -- Reshow formspec.
  286. return true
  287. end
  288. if passport.player_recalls[pname] then
  289. for k, v in ipairs(passport.player_recalls[pname]) do
  290. local c = v.code
  291. if fields[c] then
  292. if not minetest.check_player_privs(pname, {recall=true}) then
  293. minetest.chat_send_player(pname, "# Server: You are not authorized to request transport.")
  294. easyvend.sound_error(pname)
  295. return true
  296. end
  297. passport.attempt_teleport(player, v)
  298. return true
  299. end
  300. end
  301. end
  302. for k, v in ipairs(passport.recalls) do
  303. local c = v.code
  304. if fields[c] then
  305. if not minetest.check_player_privs(pname, {recall=true}) then
  306. minetest.chat_send_player(pname, "# Server: You are not authorized to request transport.")
  307. easyvend.sound_error(pname)
  308. return true
  309. end
  310. passport.attempt_teleport(player, v)
  311. return true
  312. end
  313. end
  314. return true
  315. end
  316. passport.attempt_teleport = function(player, data)
  317. local pp = player:get_pos()
  318. local nn = player:get_player_name()
  319. local tg = data.position(player) -- May return nil.
  320. local recalls = passport.player_recalls[nn]
  321. if not recalls then
  322. minetest.chat_send_player(nn, "# Server: No data associated with beacon signal.")
  323. return
  324. end
  325. if not tg then
  326. minetest.chat_send_player(nn, "# Server: Beacon does not provide position data. Aborting.")
  327. return
  328. end
  329. if rc.current_realm_at_pos(tg) ~= rc.current_realm_at_pos(pp) then
  330. minetest.chat_send_player(nn, "# Server: Beacon signal is in another dimension!")
  331. -- Wrong realm.
  332. return
  333. end
  334. for k, v in ipairs(recalls) do
  335. if v.suppress then
  336. if v.suppress(nn) then
  337. minetest.chat_send_player(nn, "# Server: Beacon signal is jammed and cannot be triangulated.")
  338. easyvend.sound_error(nn)
  339. return -- Someone suppressed the ability to teleport.
  340. end
  341. end
  342. end
  343. -- Is player too close to custom (player-built) recalls?
  344. for k, v in ipairs(recalls) do
  345. local vpp = v.position(player) -- May return nil.
  346. if vpp then
  347. if vector_distance(pp, vpp) < v.min_dist then
  348. if data.on_failure then data.on_failure(nn, "too_close", v.tname) end
  349. minetest.chat_send_player(nn, "# Server: You are too close to a nearby beacon signal.")
  350. easyvend.sound_error(nn)
  351. return -- Too close to a beacon.
  352. end
  353. end
  354. end
  355. -- Is player too close to builtin (server) recalls?
  356. for k, v in ipairs(passport.recalls) do
  357. local vpp = v.position(player) -- May return nil.
  358. if vpp then
  359. if vector_distance(pp, vpp) < v.min_dist then
  360. if data.on_failure then data.on_failure(nn, "too_close", v.tname) end
  361. minetest.chat_send_player(nn, "# Server: You are too close to a nearby beacon signal.")
  362. easyvend.sound_error(nn)
  363. return -- Too close to a beacon.
  364. end
  365. end
  366. end
  367. if vector_distance(pp, tg) > PASSPORT_TELEPORT_RANGE then
  368. if data.on_failure then data.on_failure(nn, "too_far", data.tname) end
  369. local dist = math_floor(vector_distance(pp, tg))
  370. minetest.chat_send_player(nn, "# Server: Beacon signal is too weak. You are out of range: distance " .. dist/1000 .. " kilometers.")
  371. easyvend.sound_error(nn)
  372. return -- To far from requested beacon.
  373. end
  374. if passport.players[nn] then
  375. if data.on_failure then data.on_failure(nn, "in_progress", data.tname) end
  376. minetest.chat_send_player(nn, "# Server: Signal triangulation already underway; stand by.")
  377. return -- Teleport already in progress.
  378. end
  379. -- Everything satisfied. Let's teleport!
  380. local dist = vector_distance(pp, tg)
  381. local time = math.ceil(math.sqrt(dist / 10))
  382. minetest.chat_send_player(nn, "# Server: Recall beacon signal requires " .. time .. " seconds to triangulate; please hold still.")
  383. passport.players[nn] = true
  384. local pos = vector.add(tg, {x=math_random(-1, 1), y=0, z=math_random(-1, 1)})
  385. minetest.after(time, passport.do_teleport, nn, pp, pos, data.on_success)
  386. end
  387. -- Called from minetest.after() to actually execute a teleport.
  388. passport.do_teleport = function(name, start_pos, target_pos, func)
  389. passport.players[name] = nil
  390. local player = minetest.get_player_by_name(name)
  391. if player and player:is_player() then
  392. if sheriff.is_cheater(name) then
  393. if sheriff.punish_probability(name) then
  394. sheriff.punish_player(name)
  395. return
  396. end
  397. end
  398. if vector_distance(player:getpos(), start_pos) < 0.1 then
  399. preload_tp.execute({
  400. player_name = name,
  401. target_position = target_pos,
  402. emerge_radius = 32,
  403. post_teleport_callback = func,
  404. callback_param = name,
  405. send_blocks = true,
  406. particle_effects = true,
  407. })
  408. else
  409. minetest.chat_send_player(name, "# Server: Unable to accurately triangulate beacon position! Aborted.")
  410. easyvend.sound_error(name)
  411. end
  412. end
  413. end
  414. function passport.exec_spawn(name, param)
  415. local player = minetest.get_player_by_name(name)
  416. if not player then return false end
  417. local pos = vector_round(player:get_pos())
  418. if jail.suppress(name) then
  419. return true
  420. end
  421. local target = randspawn.get_respawn_pos(pos, name)
  422. if vector_distance(pos, target) < 20 then
  423. minetest.chat_send_player(name, "# Server: Too close to the spawnpoint!")
  424. easyvend.sound_error(name)
  425. return true
  426. end
  427. if sheriff.is_cheater(name) then
  428. if sheriff.punish_probability(name) then
  429. sheriff.punish_player(name)
  430. return true
  431. end
  432. end
  433. if vector_distance(pos, target) <= 256 then
  434. randspawn.reposition_player(name, pos)
  435. minetest.after(1, function()
  436. minetest.chat_send_player(name, "# Server: You have been returned to the spawnpoint.")
  437. portal_sickness.on_use_portal(name)
  438. end)
  439. else
  440. minetest.chat_send_player(name, "# Server: You are too far from the spawnpoint!")
  441. easyvend.sound_error(name)
  442. end
  443. return true
  444. end
  445. function passport.award_cash(pname, player)
  446. local inv = player:get_inventory()
  447. if not inv then
  448. return
  449. end
  450. local cash_stack = ItemStack("currency:minegeld_20 10")
  451. local prot_stack = ItemStack("protector:protect3")
  452. local cash_left = inv:add_item("main", cash_stack)
  453. local prot_left = inv:add_item("main", prot_stack)
  454. minetest.chat_send_player(pname,
  455. core.get_color_escape_sequence("#ffff00") ..
  456. "# Server: Bank notice - As this is the first recorded time you have obtained a PoC, the Colony grants you 200 minegeld.")
  457. minetest.chat_send_player(pname,
  458. core.get_color_escape_sequence("#ffff00") ..
  459. "# Server: This is roughly equivalent to 8 gold ingots according to the Guild of Weights and Measures.")
  460. if cash_left:is_empty() and prot_left:is_empty() then
  461. minetest.chat_send_player(pname,
  462. core.get_color_escape_sequence("#ffff00") ..
  463. "# Server: The cash has been directly added to your inventory. Trade wisely and well, Adventurer!")
  464. else
  465. local pos = vector_round(player:get_pos())
  466. pos.y = pos.y + 1
  467. if not cash_left:is_empty() then
  468. minetest.add_item(pos, cash_left)
  469. end
  470. if not prot_left:is_empty() then
  471. minetest.add_item(pos, prot_left)
  472. end
  473. minetest.chat_send_player(pname,
  474. core.get_color_escape_sequence("#ffff00") ..
  475. "# Server: The cash could not be added to your inventory (no space). Check near your position for drops.")
  476. end
  477. end
  478. function passport.on_craft(itemstack, player, old_craft_grid, craft_inv)
  479. local name = itemstack:get_name()
  480. if name == "passport:passport_adv" then
  481. local pname = player:get_player_name()
  482. local meta = itemstack:get_meta()
  483. -- Store owner and data of activation.
  484. meta:set_string("owner", pname)
  485. meta:set_int("date", os.time())
  486. minetest.after(3, function()
  487. minetest.chat_send_player(pname,
  488. "# Server: A newly fashioned Key of Citizenship emits a soft blue glow mere moments after its crafter finishes the device.")
  489. end)
  490. -- Clear cache of player registration.
  491. passport.keyed_players[pname] = nil
  492. passport.registered_players[pname] = nil
  493. elseif name == "passport:passport" then
  494. -- Check if this is the first time this player has crafted a PoC.
  495. local pname = player:get_player_name()
  496. local meta = passport.modstorage
  497. local key = pname .. ":crafted_poc"
  498. if meta:get_int(key) == 0 then
  499. meta:set_int(key, 1)
  500. passport.award_cash(pname, player)
  501. end
  502. -- Clear cache of player registration.
  503. passport.keyed_players[pname] = nil
  504. passport.registered_players[pname] = nil
  505. end
  506. end
  507. if not passport.registered then
  508. -- Obtain modstorage.
  509. passport.modstorage = minetest.get_mod_storage()
  510. -- Keep this in inventory to prevent deletion.
  511. minetest.register_craftitem("passport:passport", {
  512. description = "Proof Of Citizenship\n\n" ..
  513. "Keep this in your MAIN inventory at ALL times!\n" ..
  514. "This preserves your Account during server purge.\n" ..
  515. "It cannot be stolen or lost by dying.",
  516. inventory_image = "default_bronze_block.png^default_tool_steelpick.png",
  517. stack_max = 1,
  518. on_use = function(...) return passport.on_use_simple(...) end,
  519. on_drop = function(itemstack, dropper, pos) return itemstack end,
  520. })
  521. -- Keep this in inventory to prevent deletion.
  522. minetest.register_craftitem("passport:passport_adv", {
  523. description = "Key Of Citizenship\n\n" ..
  524. "Keep this in your MAIN inventory at ALL times!\n" ..
  525. "This preserves your Account during server purge.\n" ..
  526. "It cannot be stolen or lost by dying.",
  527. inventory_image = "adv_passport.png",
  528. stack_max = 1,
  529. on_use = function(...) return passport.on_use(...) end,
  530. on_drop = function(itemstack, dropper, pos) return itemstack end,
  531. })
  532. minetest.register_craft({
  533. output = 'passport:passport 1',
  534. recipe = {
  535. {'default:copper_ingot', 'default:copper_ingot', 'default:copper_ingot'},
  536. },
  537. })
  538. minetest.register_craft({
  539. output = 'passport:passport_adv 1',
  540. recipe = {
  541. {'mese_crystals:zentamine', 'passport:passport', 'mese_crystals:zentamine'},
  542. {'techcrafts:control_logic_unit', 'quartz:quartz_crystal_piece', 'techcrafts:control_logic_unit'},
  543. {'dusts:diamond_shard', 'techcrafts:control_logic_unit', 'default:obsidian_shard'},
  544. },
  545. })
  546. minetest.register_on_player_receive_fields(function(...) return passport.on_receive_fields(...) end)
  547. minetest.register_alias("command_tokens:live_preserver", "passport:passport")
  548. -- It's very common for servers to have a /spawn command. This one is limited.
  549. minetest.register_chatcommand("spawn", {
  550. params = "",
  551. description = "Teleport the player back to the spawnpoint. This only works within 256 meters of spawn.",
  552. privs = {recall=true},
  553. func = function(...)
  554. return passport.exec_spawn(...)
  555. end,
  556. })
  557. -- Let players used to using /recall know that gameplay has changed in this respect.
  558. minetest.register_chatcommand("recall", {
  559. params = "",
  560. description = "Teleport the player back to the spawnpoint. This only works within 256 meters of spawn.",
  561. privs = {recall=true},
  562. func = function(...)
  563. return passport.exec_spawn(...)
  564. end,
  565. })
  566. minetest.register_on_leaveplayer(function(...)
  567. return passport.on_leaveplayer(...)
  568. end)
  569. minetest.register_on_craft(function(...) passport.on_craft(...) end)
  570. passport.registered = true
  571. end
  572. -- This function may be called serveral times on player-login and other times.
  573. -- We cache the result on first call.
  574. passport.player_registered = function(pname)
  575. local all_players = passport.registered_players
  576. -- Read cache if available.
  577. local registered = all_players[pname]
  578. if registered ~= nil then
  579. return registered
  580. end
  581. local player = minetest.get_player_by_name(pname)
  582. if player and player:is_player() then
  583. local inv = player:get_inventory()
  584. if inv then
  585. if inv:contains_item("main", "passport:passport") or inv:contains_item("main", "passport:passport_adv") then
  586. all_players[pname] = true -- Cache for next time.
  587. return true
  588. else
  589. all_players[pname] = false -- Cache for next time.
  590. return false
  591. end
  592. end
  593. end
  594. -- Return false, but don't cache the value -- we could not confirm it!
  595. return false
  596. end
  597. -- This checks (and caches the result!) of whether the player has a KEY OF CITIZENSHIP.
  598. -- Second param is optional, may be nil.
  599. passport.player_has_key = function(pname, player)
  600. local all_players = passport.keyed_players
  601. -- Read cache if available.
  602. local keyed = all_players[pname]
  603. if keyed ~= nil then
  604. return keyed
  605. end
  606. local pref = player or minetest.get_player_by_name(pname)
  607. if pref then
  608. local inv = pref:get_inventory()
  609. if inv then
  610. if inv:contains_item("main", "passport:passport_adv") then
  611. all_players[pname] = true -- Cache for next time.
  612. return true
  613. else
  614. all_players[pname] = false -- Cache for next time.
  615. return false
  616. end
  617. end
  618. end
  619. -- Return false, but don't cache the value -- we could not confirm it!
  620. return false
  621. end
  622. function passport.on_leaveplayer(player, timeout)
  623. local pname = player:get_player_name()
  624. -- Remove cache of player registration.
  625. passport.registered_players[pname] = nil
  626. passport.keyed_players[pname] = nil
  627. end
  628. if minetest.get_modpath("reload") then
  629. local c = "passport:core"
  630. local f = passport.modpath .. "/init.lua"
  631. if not reload.file_registered(c) then
  632. reload.register_file(c, f, false)
  633. end
  634. end