init.lua 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825
  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. local status_info = {}
  162. if pref then
  163. local player_pos = pref:get_pos()
  164. local city_info = city_block.city_info(player_pos)
  165. if city_info then
  166. status_info[#status_info + 1] = "Lawful Zone"
  167. local count = 0
  168. local targets = minetest.get_connected_players()
  169. for k, v in ipairs(targets) do
  170. -- Ignore admin, don't count self.
  171. if not gdac.player_is_admin(v) and v ~= pref then
  172. local tpos = v:get_pos()
  173. -- Ignore far, ignore dead.
  174. if vector_distance(player_pos, tpos) < 100 and v:get_hp() > 0 then
  175. count = count + 1
  176. end
  177. end
  178. end
  179. status_info[#status_info + 1] = (count .. " nearby")
  180. end
  181. end
  182. if cloaking.is_cloaked(pname) then
  183. status_info[#status_info + 1] = "Cloaked"
  184. elseif player_labels.query_nametag_onoff(pname) == false then
  185. status_info[#status_info + 1] = "Name OFF"
  186. end
  187. status_info[#status_info + 1] = tostring(pref:get_hp() .. " HP")
  188. status_info[#status_info + 1] = tostring("Respawns: " .. beds.get_respawn_count(pname))
  189. -- Status info.
  190. formspec = formspec .. "label[1,6.6;Status: " ..
  191. minetest.formspec_escape(table.concat(status_info, " | ")) .. "]"
  192. return formspec
  193. end
  194. passport.show_formspec = function(pname)
  195. local formspec = passport.compose_formspec(pname)
  196. minetest.show_formspec(pname, "passport:passport", formspec)
  197. end
  198. passport.on_use = function(itemstack, user, pointed)
  199. local changed = false
  200. if user and user:is_player() then
  201. local pname = user:get_player_name()
  202. -- Check (and if needed, set) owner.
  203. local meta = itemstack:get_meta()
  204. local owner = meta:get_string("owner")
  205. if owner == "" then
  206. owner = pname
  207. -- Store owner and data of activation.
  208. meta:set_string("owner", owner)
  209. meta:set_int("date", os.time())
  210. minetest.after(3, function()
  211. minetest.chat_send_player(pname, "# Server: A newly initialized Key of Citizenship begins to emit a soft blue glow.")
  212. end)
  213. changed = true
  214. end
  215. -- Initialize data if not set.
  216. if meta:get_int("date") == 0 then
  217. meta:set_int("date", os.time())
  218. changed = true
  219. end
  220. if owner ~= pname then
  221. minetest.chat_send_player(pname, "# Server: This Key was initialized by someone else! You cannot access it.")
  222. easyvend.sound_error(pname)
  223. return
  224. end
  225. -- Record number of uses.
  226. meta:set_int("uses", meta:get_int("uses") + 1)
  227. changed = true
  228. local control = user:get_player_control()
  229. if control.sneak then
  230. marker.show_formspec(pname)
  231. elseif control.aux1 then
  232. mailgui.show_formspec(pname)
  233. else
  234. -- Show KoC interface.
  235. passport.show_formspec(pname)
  236. end
  237. passport.open_keys[pname] = true
  238. local ppos = user:get_pos()
  239. minetest.after(0, ambiance.sound_play, "fancy_chime1", ppos, 1.0, 20, "", false)
  240. end
  241. if changed then
  242. return itemstack
  243. end
  244. end
  245. passport.on_use_simple = function(itemstack, user, pointed)
  246. if user and user:is_player() then
  247. minetest.chat_send_player(user:get_player_name(),
  248. "# Server: This awkward chunk of reflective metal seems to mock you, " ..
  249. "yet remains strangely inert. Perhaps it can be upgraded?")
  250. end
  251. return itemstack
  252. end
  253. passport.on_receive_fields = function(player, formname, fields)
  254. if formname ~= "passport:passport" then return end
  255. local pname = player:get_player_name()
  256. if fields.mapfix then
  257. mapfix.command(pname, "")
  258. return true
  259. end
  260. if fields.email then
  261. mailgui.show_formspec(pname)
  262. return true
  263. end
  264. if fields.chatfilter then
  265. chat_controls.show_formspec(pname)
  266. return true
  267. end
  268. if fields.marker then
  269. marker.show_formspec(pname)
  270. return true
  271. end
  272. if fields.jaunt and survivalist.player_beat_cave_challenge(pname) then
  273. -- Jaunt code performs its own security validation.
  274. jaunt.show_formspec(pname)
  275. return true
  276. end
  277. if fields.cloak and survivalist.player_beat_nether_challenge(pname) then
  278. -- Security check to make sure player can use this feature.
  279. if not passport.player_has_key(pname) then
  280. return true
  281. end
  282. if not survivalist.player_beat_nether_challenge(pname) then
  283. return true
  284. end
  285. -- Cloaking ability is revoked for cheaters.
  286. if sheriff.is_cheater(pname) then
  287. return true
  288. end
  289. cloaking.toggle_cloak(pname)
  290. passport.show_formspec(pname) -- Reshow formspec.
  291. return true
  292. end
  293. if fields.survivalist then
  294. survivalist.show_formspec(pname)
  295. return true
  296. end
  297. if fields.rename then
  298. rename.show_formspec(pname)
  299. return true
  300. end
  301. if fields.togglechat then
  302. if fields.togglechat == 'true' then
  303. chat_echo.set_echo(pname, true)
  304. elseif fields.togglechat == 'false' then
  305. chat_echo.set_echo(pname, false)
  306. end
  307. passport.show_formspec(pname) -- Reshow formspec.
  308. return true
  309. end
  310. if fields.toggleparticles then
  311. if fields.toggleparticles == 'true' then
  312. default.enable_particles_for(pname, true)
  313. elseif fields.toggleparticles == 'false' then
  314. default.enable_particles_for(pname, false)
  315. end
  316. passport.show_formspec(pname) -- Reshow formspec.
  317. return true
  318. end
  319. if passport.player_recalls[pname] then
  320. for k, v in ipairs(passport.player_recalls[pname]) do
  321. local c = v.code
  322. if fields[c] then
  323. if not minetest.check_player_privs(pname, {recall=true}) then
  324. minetest.chat_send_player(pname, "# Server: You are not authorized to request transport.")
  325. easyvend.sound_error(pname)
  326. return true
  327. end
  328. passport.attempt_teleport(player, v)
  329. return true
  330. end
  331. end
  332. end
  333. for k, v in ipairs(passport.recalls) do
  334. local c = v.code
  335. if fields[c] then
  336. if not minetest.check_player_privs(pname, {recall=true}) then
  337. minetest.chat_send_player(pname, "# Server: You are not authorized to request transport.")
  338. easyvend.sound_error(pname)
  339. return true
  340. end
  341. passport.attempt_teleport(player, v)
  342. return true
  343. end
  344. end
  345. return true
  346. end
  347. passport.attempt_teleport = function(player, data)
  348. local pp = player:get_pos()
  349. local nn = player:get_player_name()
  350. local tg = data.position(player) -- May return nil.
  351. local recalls = passport.player_recalls[nn]
  352. if not recalls then
  353. minetest.chat_send_player(nn, "# Server: No data associated with beacon signal.")
  354. return
  355. end
  356. if not tg then
  357. minetest.chat_send_player(nn, "# Server: Beacon does not provide position data. Aborting.")
  358. return
  359. end
  360. if rc.current_realm_at_pos(tg) ~= rc.current_realm_at_pos(pp) then
  361. minetest.chat_send_player(nn, "# Server: Beacon signal is in another dimension!")
  362. -- Wrong realm.
  363. return
  364. end
  365. for k, v in ipairs(recalls) do
  366. if v.suppress then
  367. if v.suppress(nn) then
  368. minetest.chat_send_player(nn, "# Server: Beacon signal is jammed and cannot be triangulated.")
  369. easyvend.sound_error(nn)
  370. return -- Someone suppressed the ability to teleport.
  371. end
  372. end
  373. end
  374. -- Is player too close to custom (player-built) recalls?
  375. for k, v in ipairs(recalls) do
  376. local vpp = v.position(player) -- May return nil.
  377. if vpp then
  378. if vector_distance(pp, vpp) < v.min_dist then
  379. if data.on_failure then data.on_failure(nn, "too_close", v.tname) end
  380. minetest.chat_send_player(nn, "# Server: You are too close to a nearby beacon signal.")
  381. easyvend.sound_error(nn)
  382. return -- Too close to a beacon.
  383. end
  384. end
  385. end
  386. -- Is player too close to builtin (server) recalls?
  387. for k, v in ipairs(passport.recalls) do
  388. local vpp = v.position(player) -- May return nil.
  389. if vpp then
  390. if vector_distance(pp, vpp) < v.min_dist then
  391. if data.on_failure then data.on_failure(nn, "too_close", v.tname) end
  392. minetest.chat_send_player(nn, "# Server: You are too close to a nearby beacon signal.")
  393. easyvend.sound_error(nn)
  394. return -- Too close to a beacon.
  395. end
  396. end
  397. end
  398. if vector_distance(pp, tg) > PASSPORT_TELEPORT_RANGE then
  399. if data.on_failure then data.on_failure(nn, "too_far", data.tname) end
  400. local dist = math_floor(vector_distance(pp, tg))
  401. minetest.chat_send_player(nn, "# Server: Beacon signal is too weak. You are out of range: distance " .. dist/1000 .. " kilometers.")
  402. easyvend.sound_error(nn)
  403. return -- To far from requested beacon.
  404. end
  405. if passport.players[nn] then
  406. if data.on_failure then data.on_failure(nn, "in_progress", data.tname) end
  407. minetest.chat_send_player(nn, "# Server: Signal triangulation already underway; stand by.")
  408. return -- Teleport already in progress.
  409. end
  410. -- Everything satisfied. Let's teleport!
  411. local dist = vector_distance(pp, tg)
  412. local time = math.ceil(math.sqrt(dist / 10))
  413. minetest.chat_send_player(nn, "# Server: Recall beacon signal requires " .. time .. " seconds to triangulate; please hold still.")
  414. passport.players[nn] = true
  415. local pos = vector.add(tg, {x=math_random(-1, 1), y=0, z=math_random(-1, 1)})
  416. minetest.after(time, passport.do_teleport, nn, pp, pos, data.on_success)
  417. end
  418. -- Called from minetest.after() to actually execute a teleport.
  419. passport.do_teleport = function(name, start_pos, target_pos, func)
  420. passport.players[name] = nil
  421. local player = minetest.get_player_by_name(name)
  422. if player and player:is_player() then
  423. if sheriff.is_cheater(name) then
  424. if sheriff.punish_probability(name) then
  425. sheriff.punish_player(name)
  426. return
  427. end
  428. end
  429. if vector_distance(player:get_pos(), start_pos) < 0.1 then
  430. preload_tp.execute({
  431. player_name = name,
  432. target_position = target_pos,
  433. emerge_radius = 32,
  434. post_teleport_callback = func,
  435. callback_param = name,
  436. send_blocks = true,
  437. particle_effects = true,
  438. })
  439. else
  440. minetest.chat_send_player(name, "# Server: Unable to accurately triangulate beacon position! Aborted.")
  441. easyvend.sound_error(name)
  442. end
  443. end
  444. end
  445. function passport.exec_spawn(name, param)
  446. if passport.player_has_key(name) then
  447. minetest.chat_send_player(name, "# Server: This command is newbies-only.")
  448. easyvend.sound_error(name)
  449. return true
  450. end
  451. local player = minetest.get_player_by_name(name)
  452. if not player then return false end
  453. local pos = vector_round(player:get_pos())
  454. if jail.suppress(name) then
  455. return true
  456. end
  457. local target = randspawn.get_respawn_pos(pos, name)
  458. if vector_distance(pos, target) < 20 then
  459. minetest.chat_send_player(name, "# Server: Too close to the spawnpoint!")
  460. easyvend.sound_error(name)
  461. return true
  462. end
  463. if sheriff.is_cheater(name) then
  464. if sheriff.punish_probability(name) then
  465. sheriff.punish_player(name)
  466. return true
  467. end
  468. end
  469. if vector_distance(pos, target) <= 256 then
  470. randspawn.reposition_player(name, pos)
  471. minetest.after(1, function()
  472. minetest.chat_send_player(name, "# Server: You have been returned to the spawnpoint.")
  473. portal_sickness.on_use_portal(name)
  474. end)
  475. else
  476. minetest.chat_send_player(name, "# Server: You are too far from the spawnpoint!")
  477. easyvend.sound_error(name)
  478. end
  479. return true
  480. end
  481. function passport.award_cash(pname, player)
  482. local inv = player:get_inventory()
  483. if not inv then
  484. return
  485. end
  486. local cash_stack = ItemStack("currency:minegeld_20 10")
  487. local prot_stack = ItemStack("protector:protect3")
  488. local cash_left = inv:add_item("main", cash_stack)
  489. local prot_left = inv:add_item("main", prot_stack)
  490. minetest.chat_send_player(pname,
  491. core.get_color_escape_sequence("#ffff00") ..
  492. "# Server: Bank notice - As this is the first recorded time you have obtained a PoC, the Colony grants you 200 minegeld.")
  493. minetest.chat_send_player(pname,
  494. core.get_color_escape_sequence("#ffff00") ..
  495. "# Server: This is roughly equivalent to 8 gold ingots according to the Guild of Weights and Measures.")
  496. if cash_left:is_empty() and prot_left:is_empty() then
  497. minetest.chat_send_player(pname,
  498. core.get_color_escape_sequence("#ffff00") ..
  499. "# Server: The cash has been directly added to your inventory. Trade wisely and well, Adventurer!")
  500. else
  501. local pos = vector_round(player:get_pos())
  502. pos.y = pos.y + 1
  503. if not cash_left:is_empty() then
  504. minetest.add_item(pos, cash_left)
  505. end
  506. if not prot_left:is_empty() then
  507. minetest.add_item(pos, prot_left)
  508. end
  509. minetest.chat_send_player(pname,
  510. core.get_color_escape_sequence("#ffff00") ..
  511. "# Server: The cash could not be added to your inventory (no space). Check near your position for drops.")
  512. end
  513. end
  514. function passport.on_craft(itemstack, player, old_craft_grid, craft_inv)
  515. local name = itemstack:get_name()
  516. if name == "passport:passport_adv" then
  517. local pname = player:get_player_name()
  518. local meta = itemstack:get_meta()
  519. -- Store owner and data of activation.
  520. meta:set_string("owner", pname)
  521. meta:set_int("date", os.time())
  522. minetest.after(3, function()
  523. minetest.chat_send_player(pname,
  524. "# Server: A newly fashioned Key of Citizenship emits a soft blue glow mere moments after its crafter finishes the device.")
  525. end)
  526. -- Clear cache of player registration.
  527. passport.keyed_players[pname] = nil
  528. passport.registered_players[pname] = nil
  529. elseif name == "passport:passport" then
  530. -- Check if this is the first time this player has crafted a PoC.
  531. local pname = player:get_player_name()
  532. local meta = passport.modstorage
  533. local key = pname .. ":crafted_poc"
  534. if meta:get_int(key) == 0 then
  535. meta:set_int(key, 1)
  536. passport.award_cash(pname, player)
  537. end
  538. -- Clear cache of player registration.
  539. passport.keyed_players[pname] = nil
  540. passport.registered_players[pname] = nil
  541. end
  542. end
  543. if not passport.registered then
  544. -- Obtain modstorage.
  545. passport.modstorage = minetest.get_mod_storage()
  546. -- Keep this in inventory to prevent deletion.
  547. minetest.register_craftitem("passport:passport", {
  548. description = "Proof Of Citizenship\n\n" ..
  549. "Keep this in your MAIN inventory at ALL times!\n" ..
  550. "This preserves your Account during server purge.\n" ..
  551. "It cannot be stolen or lost by dying.",
  552. inventory_image = "default_bronze_block.png^default_tool_steelpick.png",
  553. stack_max = 1,
  554. on_use = function(...) return passport.on_use_simple(...) end,
  555. on_drop = function(itemstack, dropper, pos) return itemstack end,
  556. })
  557. -- Keep this in inventory to prevent deletion.
  558. minetest.register_craftitem("passport:passport_adv", {
  559. description = "Key Of Citizenship\n\n" ..
  560. "Keep this in your MAIN inventory at ALL times!\n" ..
  561. "This preserves your Account during server purge.\n" ..
  562. "It cannot be stolen or lost by dying.",
  563. inventory_image = "adv_passport.png",
  564. stack_max = 1,
  565. on_use = function(...) return passport.on_use(...) end,
  566. on_drop = function(itemstack, dropper, pos) return itemstack end,
  567. })
  568. minetest.register_craft({
  569. output = 'passport:passport 1',
  570. recipe = {
  571. {'default:copper_ingot', 'default:copper_ingot', 'default:copper_ingot'},
  572. },
  573. })
  574. minetest.register_craft({
  575. output = 'passport:passport_adv 1',
  576. recipe = {
  577. {'mese_crystals:zentamine', 'passport:passport', 'mese_crystals:zentamine'},
  578. {'techcrafts:control_logic_unit', 'quartz:quartz_crystal_piece', 'techcrafts:control_logic_unit'},
  579. {'dusts:diamond_shard', 'techcrafts:control_logic_unit', 'default:obsidian_shard'},
  580. },
  581. })
  582. minetest.register_on_player_receive_fields(function(...) return passport.on_receive_fields(...) end)
  583. minetest.register_alias("command_tokens:live_preserver", "passport:passport")
  584. -- It's very common for servers to have a /spawn command. This one is limited.
  585. minetest.register_chatcommand("spawn", {
  586. params = "",
  587. description = "Teleport the player back to the spawnpoint. This only works within 256 meters of spawn.",
  588. privs = {recall=true},
  589. func = function(...)
  590. return passport.exec_spawn(...)
  591. end,
  592. })
  593. -- Let players used to using /recall know that gameplay has changed in this respect.
  594. minetest.register_chatcommand("recall", {
  595. params = "",
  596. description = "Teleport the player back to the spawnpoint. This only works within 256 meters of spawn.",
  597. privs = {recall=true},
  598. func = function(...)
  599. return passport.exec_spawn(...)
  600. end,
  601. })
  602. minetest.register_on_leaveplayer(function(...)
  603. return passport.on_leaveplayer(...)
  604. end)
  605. minetest.register_on_craft(function(...) passport.on_craft(...) end)
  606. passport.registered = true
  607. end
  608. -- This function may be called serveral times on player-login and other times.
  609. -- We cache the result on first call.
  610. passport.player_registered = function(pname)
  611. local all_players = passport.registered_players
  612. -- Read cache if available.
  613. local registered = all_players[pname]
  614. if registered ~= nil then
  615. return registered
  616. end
  617. local player = minetest.get_player_by_name(pname)
  618. if player and player:is_player() then
  619. local inv = player:get_inventory()
  620. if inv then
  621. if inv:contains_item("main", "passport:passport") or inv:contains_item("main", "passport:passport_adv") then
  622. all_players[pname] = true -- Cache for next time.
  623. return true
  624. else
  625. all_players[pname] = false -- Cache for next time.
  626. return false
  627. end
  628. end
  629. end
  630. -- Return false, but don't cache the value -- we could not confirm it!
  631. return false
  632. end
  633. -- This checks (and caches the result!) of whether the player has a KEY OF CITIZENSHIP.
  634. -- Second param is optional, may be nil.
  635. passport.player_has_key = function(pname, player)
  636. local all_players = passport.keyed_players
  637. -- Read cache if available.
  638. local keyed = all_players[pname]
  639. if keyed ~= nil then
  640. return keyed
  641. end
  642. local pref = player or minetest.get_player_by_name(pname)
  643. if pref then
  644. local inv = pref:get_inventory()
  645. if inv then
  646. if inv:contains_item("main", "passport:passport_adv") then
  647. all_players[pname] = true -- Cache for next time.
  648. return true
  649. else
  650. all_players[pname] = false -- Cache for next time.
  651. return false
  652. end
  653. end
  654. end
  655. -- Return false, but don't cache the value -- we could not confirm it!
  656. return false
  657. end
  658. function passport.on_leaveplayer(player, timeout)
  659. local pname = player:get_player_name()
  660. -- Remove cache of player registration.
  661. passport.registered_players[pname] = nil
  662. passport.keyed_players[pname] = nil
  663. end
  664. if minetest.get_modpath("reload") then
  665. local c = "passport:core"
  666. local f = passport.modpath .. "/init.lua"
  667. if not reload.file_registered(c) then
  668. reload.register_file(c, f, false)
  669. end
  670. end