sample.txt 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. -- by boxface
  2. -- license: MIT
  3. ---- KEYCARD API ----
  4. keycard = {}
  5. local _keycard = {}
  6. _keycard.players = {}
  7. _keycard.max_keys = 8
  8. function keycard.get_context(pname)
  9. if not _keycard.players[pname] then
  10. _keycard.players[pname] = {}
  11. _keycard.players[pname].owner = pname
  12. end
  13. return _keycard.players[pname]
  14. end
  15. function keycard.clear_context(pname)
  16. _keycard.players[pname] = nil
  17. end
  18. function keycard.get_maxkeys()
  19. return _keycard.max_keys
  20. end
  21. -- deprecated?
  22. function _keycard.set_context(pname, data)
  23. _keycard.players[pname] = data
  24. end
  25. ---- END API ----
  26. local sample_keys = {
  27. {description = "key desc", secret="0001-0001"},
  28. {description = "noobs door", secret="0000-1234"}
  29. }
  30. local function get_formspec(data)
  31. if not data then
  32. data = {}
  33. data.keys = {}
  34. end
  35. if not data.keys then
  36. data.keys = {}
  37. end
  38. if not data.card_description then
  39. data.card_description = ""
  40. end
  41. if not data.key_description then
  42. data.key_description = ""
  43. end
  44. local formspec = "size[8,9]" ..
  45. "label[0,0;KeyCard]" ..
  46. "list[current_name;card;0,0.5;1,1]" ..
  47. "field[2,0.7;4,1;desc;Card name;".. data.card_description .."]" ..
  48. "image_button[6.5,0.5;1.25,0.7;wool_red.png;write;Write]"..
  49. -- key
  50. "label[0.5,6.25;Key]" ..
  51. "list[current_name;keys;0.5,6.75;1,1]" ..
  52. string.format("field[2,7.05;4,0.7;keydesc;Description;%s]",
  53. data.key_description) ..
  54. "image_button[5.6,6.75;1.25,0.7;wool_blue.png;addkey;Add]"..
  55. "tooltip[addkey;Add Key;#80C080;#FFFF80]" ..
  56. "list[current_player;main;0,8;8,1]"
  57. local y = 2.0
  58. local imax = math.min(keycard.get_maxkeys(), #data.keys)
  59. for i=1, imax do
  60. local desc = "<free slot>"
  61. local secr
  62. if data.keys[i] then
  63. desc = data.keys[i].description
  64. secr = minetest.colorize("#808080", data.keys[i].secret)
  65. else
  66. desc = ""
  67. secr = minetest.colorize("#404040", "0000-0000")
  68. end
  69. if data.rom == i then
  70. desc = minetest.colorize("#FFFF00", desc)
  71. end
  72. formspec = formspec ..
  73. string.format(
  74. "image_button[0.5,%f;1,0.5;wool_blue.png;rom%2.2d;%2.2d]",
  75. y, i, i) ..
  76. string.format("label[1.50,%f;%s]", y, desc) ..
  77. string.format("tooltip[rom%2.2d;%s\n%s;#80C080;#FFFF80]",i, desc, secr) ..
  78. string.format("image_button[6,%f;1,0.50;wool_pink.png;del%2.2d;Del]", y, i)..
  79. string.format("tooltip[del%2.2d;Remove key %2.2d;#80C080;#FFFF80]", i, i)
  80. y = y + 0.5
  81. end
  82. return formspec
  83. end
  84. local function do_construct(pos)
  85. local meta = minetest.get_meta(pos)
  86. local inv = meta:get_inventory()
  87. inv:set_size("card", 1)
  88. inv:set_size("keys", 1)
  89. meta:set_string("formspec", get_formspec())
  90. end
  91. local function do_rightclick(pos, node, player, itemstack, pointed_thing)
  92. -- local meta = minetest.get_meta(pos)
  93. -- meta:set_string("formspec", get_formspec())
  94. end
  95. local function allow_metadata_inventory_put(pos, listname, index, stack, player)
  96. local pname = player:get_player_name()
  97. local meta = minetest.get_meta(pos)
  98. local inv = meta:get_inventory()
  99. local itemname = stack:get_name()
  100. local item_meta = stack:get_meta()
  101. print("stack meta table: " .. dump(stack:get_meta():to_table()))
  102. if listname == "card" then
  103. if itemname == "boxfce:keycard_blank" or
  104. itemname == "boxfce:keycard_green" or
  105. itemname == "boxfce:keycard_red" or
  106. itemname == "boxfce:keycard_blue" then
  107. local list = inv:get_stack(listname,1)
  108. if list:get_count()>0 then
  109. return 0
  110. else
  111. return 1
  112. end
  113. else
  114. minetest.chat_send_player(pname, "Place key card only")
  115. return 0
  116. end
  117. elseif listname == "keys" then
  118. if itemname == "default:key" then
  119. return stack:get_count()
  120. else
  121. minetest.chat_send_player(
  122. player:get_player_name(),
  123. "Only keys here!")
  124. return 0
  125. end
  126. else
  127. print("[boxfce:keycard] something went wrong!")
  128. return 0
  129. end
  130. end
  131. local function do_metadata_inventory_put(pos, listname, index, stack, player)
  132. local pname = player:get_player_name()
  133. local meta = minetest.get_meta(pos)
  134. local stack_meta = stack:get_meta()
  135. --minetest.chat_send_player(pname,
  136. -- minetest.colorize("yellow", "stack_meta(".. listname .."): " ..
  137. -- dump(stack_meta:to_table())))
  138. if listname == "card" then
  139. local context = keycard.get_context(pname)
  140. context.keys = minetest.deserialize(stack_meta:get_string("keys"))
  141. context.card_inserted = true
  142. if not context.keys then
  143. context.keys = {}
  144. end
  145. context.card_description = stack_meta:get_string("description")
  146. meta:set_string("formspec", get_formspec(context))
  147. minetest.chat_send_player(pname, "Card inserted: " ..
  148. context.card_description)
  149. minetest.chat_send_player(pname, "KEY CARD: " ..
  150. dump(stack_meta:to_table()))
  151. elseif listname == "keys" then
  152. local context = keycard.get_context(pname)
  153. context.key_description = stack_meta:get_string("description")
  154. context.secret = stack_meta:get_string("secret")
  155. -- update formspec
  156. meta:set_string("formspec", get_formspec(context))
  157. end
  158. end
  159. local function do_metadata_inventory_take(pos, listname, index, stack, player)
  160. local pname = player:get_player_name()
  161. local meta = minetest.get_meta(pos)
  162. if listname == "card" then
  163. local context = keycard.get_context(pname)
  164. context.keys = {}
  165. meta:set_string("formspec", get_formspec(context))
  166. elseif listname == "keys" then
  167. end
  168. end
  169. local function keycard_on_use(itemstack, user, pointed_thing)
  170. if pointed_thing.type ~= "node" then
  171. return itemstack
  172. end
  173. local pos = pointed_thing.under
  174. local node = minetest.get_node(pos)
  175. if not node then
  176. return itemstack
  177. end
  178. local on_skeleton_key_use = minetest.registered_nodes[node.name].on_skeleton_key_use
  179. if not on_skeleton_key_use then
  180. return itemstack
  181. end
  182. -- make a new secret in case the node callback needs it
  183. local random = math.random
  184. local newsecret = string.format(
  185. "%04x%04x%04x%04x",
  186. random(2^16) - 1, random(2^16) - 1,
  187. random(2^16) - 1, random(2^16) - 1)
  188. local secret, _, _ = on_skeleton_key_use(pos, user, newsecret)
  189. if secret then
  190. minetest.chat_send_player(user:get_player_name(), "Secret: " .. secret)
  191. end
  192. end
  193. local function keycard_on_place(itemstack, placer, pointed_thing)
  194. local pname = placer:get_player_name()
  195. local pos = pointed_thing.under
  196. local node = minetest.get_node(pos)
  197. local ndef = minetest.registered_nodes[node.name]
  198. if not ndef then
  199. return itemstack
  200. end
  201. -- testing
  202. -- end testing
  203. -- get node secret
  204. local meta = minetest.get_meta(pos)
  205. local key_lock_secret = meta:get_string("key_lock_secret")
  206. if key_lock_secret == "" then
  207. minetest.chat_send_player(pname, "Item has no keys!")
  208. return itemstack
  209. end
  210. -- activate the correct key
  211. local stack_meta = itemstack:get_meta()
  212. local roms = minetest.deserialize(stack_meta:get_string("keys"))
  213. --local active_key
  214. --for i, item in pairs(roms) do
  215. -- if item.secret == key_lock_secret then
  216. --
  217. -- end
  218. --end
  219. -- =============================================================================
  220. -- get the correct key
  221. -- minetest.chat_send_player(pname, "Using key card")
  222. -- if #keys == 1 then
  223. -- -- set the only key active
  224. -- local active_key = keys[1].secret
  225. -- stack_meta:set_string("secret", active_key)
  226. -- minetest.chat_send_player(pname, "Setting active key: " .. active_key)
  227. -- end
  228. local can_open = false
  229. local active_key
  230. -- local active_desc
  231. for i=1, #roms do
  232. if roms[i].secret == key_lock_secret then
  233. print("Correct KEY found!")
  234. minetest.chat_send_player(pname, "Correct KEY found!")
  235. active_key = roms[i].secret
  236. -- active_desc = roms[i].description
  237. stack_meta:set_string("secret", active_key)
  238. placer:set_wielded_item(itemstack)
  239. can_open = true
  240. break
  241. end
  242. end
  243. if not can_open then
  244. minetest.chat_send_player(pname, "ACCESS DENIED!")
  245. return itemstack
  246. end
  247. if not node or node.name == "ignore" then
  248. return itemstack
  249. end
  250. local on_key_use = ndef.on_key_use
  251. if on_key_use then
  252. minetest.chat_send_player(pname, "Calling on_key_use")
  253. print("Calling on_key_use")
  254. -- HACK: placer to nil to skip protection (FAULTY) check.
  255. -- Needed on doors, doors are hardcoded to "default:key"
  256. -- Do not try it on chests.
  257. -- Not needed on chests.
  258. -- check if node is a faulty door
  259. local protdoors = {
  260. "doors:door_steel_a", "doors:door_steel_b",
  261. "doors:trapdoor_steel_a", "doors:trapdoor_steel_b"}
  262. minetest.chat_send_player(pname, "OBJECT IS: " .. node.name)
  263. for i=1, #protdoors do
  264. if node.name == protdoors[i] then
  265. on_key_use(pos, nil)
  266. break
  267. end
  268. end
  269. -- player is nil for some weird reason, get a new player
  270. local player = minetest.get_player_by_name(pname)
  271. -- on_key_use raise an error if "secret" is empty
  272. if stack_meta:get_string("secret") == "" then
  273. return itemstack
  274. end
  275. on_key_use(pos, player)
  276. end
  277. return itemstack
  278. end
  279. local function select_rom(pname, rom)
  280. local context = keycard.get_context(pname)
  281. context.rom = rom
  282. -- DEBUG
  283. minetest.chat_send_player(pname,
  284. string.format("ROM %2.2d SELECTED", rom))
  285. end
  286. local function delete_key(keys, ndel)
  287. local result = {}
  288. local id
  289. for i=1, ndel-1 do
  290. id = #result + 1
  291. result[id] = {}
  292. result[id].description = keys[i].description
  293. result[id].secret = keys[i].secret
  294. end
  295. for i=ndel+1, #keys do
  296. id = #result + 1
  297. result[id] = {}
  298. result[id].description = keys[i].description
  299. result[id].secret = keys[i].secret
  300. end
  301. return result
  302. end
  303. local function do_receive_fields(pos, formname, fields, sender)
  304. local pname = sender:get_player_name()
  305. local meta = minetest.get_meta(pos)
  306. -- DEBUG
  307. minetest.chat_send_player(pname, "Fields: " .. dump(fields))
  308. if fields.write then
  309. -- write data to card
  310. local inv = meta:get_inventory()
  311. local card_stack = inv:get_stack("card", 1)
  312. card_stack:set_name("boxfce:keycard_blue")
  313. local card_meta = card_stack:get_meta()
  314. card_meta:set_string("description", fields.desc)
  315. -- write keys
  316. local context = keycard.get_context(pname)
  317. card_meta:set_string("keys", minetest.serialize(context.keys))
  318. -- set the stack
  319. inv:set_stack("card", 1, card_stack)
  320. elseif fields.addkey then
  321. -- add key to keyring
  322. -- check keycard inserted
  323. local inv = meta:get_inventory()
  324. local key_stack = inv:get_stack("keys", 1)
  325. local key_meta = key_stack:get_meta()
  326. local context = keycard.get_context(pname)
  327. print("dump keys: " .. dump(context.keys))
  328. -- card inserted?
  329. local inv = meta:get_inventory()
  330. local card_stack = inv:get_stack("card", 1)
  331. local card_inserted = not card_stack:is_empty()
  332. local key_inserted = not key_stack:is_empty()
  333. if card_inserted and key_inserted then
  334. if not context.keys then
  335. context.keys = {}
  336. end
  337. local id = #context.keys + 1
  338. context.keys[id] = {}
  339. if fields.keydesc then
  340. context.keys[id].description = fields.keydesc
  341. else
  342. context.keys[id].description = key_meta:get_string("description")
  343. end
  344. context.keys[id].secret = key_meta:get_string("secret")
  345. else
  346. -- context.message = "Insert card"
  347. local msg = "Anomalous error"
  348. if not card_inserted then
  349. msg = "Can't add key, please insert a card"
  350. elseif not key_inserted then
  351. msg = "Can't add key, please insert a key"
  352. end
  353. minetest.chat_send_player(pname, msg)
  354. end
  355. else
  356. -- check for select keys and delete keys
  357. local context = keycard.get_context(pname)
  358. if not context.keys then
  359. return
  360. end
  361. -- select row
  362. for i=1, #context.keys do
  363. local fname = string.format("rom%2.2d", i)
  364. if fields[fname] then
  365. select_rom(pname, i)
  366. break
  367. end
  368. end
  369. -- delete key
  370. for i=1, #context.keys do
  371. local fname = string.format("del%2.2d", i)
  372. if fields[fname] then
  373. context.keys = delete_key(context.keys, i)
  374. break
  375. end
  376. end
  377. end
  378. -- update formspec
  379. local context = keycard.get_context(pname)
  380. meta:set_string("formspec", get_formspec(context))
  381. end
  382. minetest.register_node("boxfce:cardbox", {
  383. description = "KeyCard setup box",
  384. tiles = {"boxfce_cardbox.png"},
  385. is_ground_content = true,
  386. groups = -- comment
  387. {cracky=3},
  388. drop = "boxfce:cardbox",
  389. on_construct = do_construct,
  390. on_rightclick = do_rightclick,
  391. allow_metadata_inventory_put = allow_metadata_inventory_put,
  392. on_metadata_inventory_put = do_metadata_inventory_put,
  393. on_metadata_inventory_take = do_metadata_inventory_take,
  394. on_receive_fields = do_receive_fields
  395. })
  396. minetest.register_craftitem("boxfce:keycard_blank", {
  397. description = "Blank Key Card",
  398. inventory_image = "boxfce_card_blank.png",
  399. stack_max = 100,
  400. groups = {key=1},
  401. on_use = keycard_on_use
  402. })
  403. minetest.register_tool("boxfce:keycard_red", {
  404. description = "Key Card Red",
  405. inventory_image = "boxfce_card_red.png",
  406. stack_max = 1,
  407. groups = {key=1}
  408. })
  409. minetest.register_craftitem("boxfce:keycard_green", {
  410. description = "Key Card Green",
  411. inventory_image = "boxfce_card_green.png",
  412. stack_max = 1,
  413. groups = {key = 1},
  414. })
  415. minetest.register_tool("boxfce:keycard_blue", {
  416. description = "Key Card Blue",
  417. inventory_image = "boxfce_card_blue.png",
  418. stack_max = 1,
  419. groups = {key = 1},
  420. on_place = keycard_on_place
  421. -- on_use = keycard_on_use
  422. })