init.lua 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018
  1. -- our API object
  2. doors = {}
  3. doors.modpath = minetest.get_modpath("doors")
  4. -- private data
  5. local _doors = {}
  6. _doors.registered_doors = {}
  7. _doors.registered_trapdoors = {}
  8. -- returns an object to a door object or nil
  9. function doors.get(pos)
  10. local node_name = minetest.get_node(pos).name
  11. if _doors.registered_doors[node_name] then
  12. -- A normal upright door
  13. return {
  14. pos = pos,
  15. open = function(self, player)
  16. if self:state() then
  17. return false
  18. end
  19. return _doors.door_toggle(self.pos, nil, player)
  20. end,
  21. close = function(self, player)
  22. if not self:state() then
  23. return false
  24. end
  25. return _doors.door_toggle(self.pos, nil, player)
  26. end,
  27. toggle = function(self, player)
  28. return _doors.door_toggle(self.pos, nil, player)
  29. end,
  30. state = function(self)
  31. local state = minetest.get_meta(self.pos):get_int("state")
  32. return state %2 == 1
  33. end
  34. }
  35. elseif _doors.registered_trapdoors[node_name] then
  36. -- A trapdoor
  37. return {
  38. pos = pos,
  39. open = function(self, player)
  40. if self:state() then
  41. return false
  42. end
  43. return _doors.trapdoor_toggle(self.pos, nil, player)
  44. end,
  45. close = function(self, player)
  46. if not self:state() then
  47. return false
  48. end
  49. return _doors.trapdoor_toggle(self.pos, nil, player)
  50. end,
  51. toggle = function(self, player)
  52. return _doors.trapdoor_toggle(self.pos, nil, player)
  53. end,
  54. state = function(self)
  55. return minetest.get_node(self.pos).name:sub(-5) == "_open"
  56. end
  57. }
  58. else
  59. return nil
  60. end
  61. end
  62. -- this hidden node is placed on top of the bottom, and prevents
  63. -- nodes from being placed in the top half of the door.
  64. minetest.register_node("doors:hidden", {
  65. description = "Hidden Door Segment",
  66. -- can't use airlike otherwise falling nodes will turn to entities
  67. -- and will be forever stuck until door is removed.
  68. drawtype = "nodebox",
  69. paramtype = "light",
  70. paramtype2 = "facedir",
  71. sunlight_propagates = true,
  72. -- has to be walkable for falling nodes to stop falling.
  73. walkable = true,
  74. pointable = false,
  75. diggable = false,
  76. buildable_to = false,
  77. floodable = false,
  78. drop = "",
  79. groups = {not_in_creative_inventory = 1},
  80. on_blast = function() end,
  81. tiles = {"doors_blank.png"},
  82. -- 1px transparent block inside door hinge near node top.
  83. nodebox = {
  84. type = "fixed",
  85. fixed = {-15/32, 13/32, -15/32, -13/32, 1/2, -13/32},
  86. },
  87. -- collision_box needed otherise selection box would be full node size
  88. collision_box = {
  89. type = "fixed",
  90. fixed = {-15/32, 13/32, -15/32, -13/32, 1/2, -13/32},
  91. },
  92. })
  93. -- table used to aid door opening/closing
  94. local transform = {
  95. {
  96. {v = "_a", param2 = 3},
  97. {v = "_a", param2 = 0},
  98. {v = "_a", param2 = 1},
  99. {v = "_a", param2 = 2},
  100. },
  101. {
  102. {v = "_b", param2 = 1},
  103. {v = "_b", param2 = 2},
  104. {v = "_b", param2 = 3},
  105. {v = "_b", param2 = 0},
  106. },
  107. {
  108. {v = "_b", param2 = 1},
  109. {v = "_b", param2 = 2},
  110. {v = "_b", param2 = 3},
  111. {v = "_b", param2 = 0},
  112. },
  113. {
  114. {v = "_a", param2 = 3},
  115. {v = "_a", param2 = 0},
  116. {v = "_a", param2 = 1},
  117. {v = "_a", param2 = 2},
  118. },
  119. }
  120. -- Force door at position to toggle, produce no sound, no ownership checks.
  121. -- Function cannot/must not fail.
  122. function _doors.door_toggle_force(pos, node)
  123. local meta = minetest.get_meta(pos)
  124. node = node or minetest.get_node(pos)
  125. local def = minetest.reg_ns_nodes[node.name]
  126. local name = def.door.name
  127. local state = meta:get_string("state")
  128. if state == "" then
  129. -- fix up lvm-placed right-hinged doors, default closed
  130. if node.name:sub(-2) == "_b" then
  131. state = 2
  132. else
  133. state = 0
  134. end
  135. else
  136. state = tonumber(state)
  137. end
  138. -- until Lua-5.2 we have no bitwise operators :(
  139. if state % 2 == 1 then
  140. state = state - 1
  141. else
  142. state = state + 1
  143. end
  144. local dir = node.param2
  145. minetest.swap_node(pos, {
  146. name = name .. transform[state + 1][dir+1].v,
  147. param2 = transform[state + 1][dir+1].param2
  148. })
  149. meta:set_int("state", state)
  150. end
  151. function _doors.have_matching_door(pos, node)
  152. local nn = minetest.get_node(pos)
  153. if nn.name == node.name and nn.param2 == node.param2 then
  154. return true
  155. end
  156. end
  157. -- The OFFICIAL door toggle function.
  158. function _doors.door_toggle(pos, node, clicker)
  159. local meta = minetest.get_meta(pos)
  160. node = node or minetest.get_node(pos)
  161. local def = minetest.reg_ns_nodes[node.name]
  162. local name = def.door.name
  163. local state = meta:get_string("state")
  164. if state == "" then
  165. -- fix up lvm-placed right-hinged doors, default closed
  166. if node.name:sub(-2) == "_b" then
  167. state = 2
  168. else
  169. state = 0
  170. end
  171. else
  172. state = tonumber(state)
  173. end
  174. if clicker and not minetest.check_player_privs(clicker, "protection_bypass") then
  175. -- is player wielding the right key?
  176. local item = clicker:get_wielded_item()
  177. local owner = meta:get_string("doors_owner")
  178. if item:get_name() == "key:key" or item:get_name() == "key:chain" then
  179. local key_meta = item:get_meta()
  180. local secret = meta:get_string("key_lock_secret")
  181. if key_meta:get_string("secret") == "" then
  182. local key_oldmeta = item:get_metadata()
  183. if key_oldmeta == "" or not minetest.parse_json(key_oldmeta) then
  184. ambiance.sound_play("doors_locked", pos, 1.0, 20)
  185. return false
  186. end
  187. key_meta:set_string("secret", minetest.parse_json(key_oldmeta).secret)
  188. item:set_metadata("")
  189. end
  190. if secret ~= key_meta:get_string("secret") then
  191. minetest.chat_send_player(clicker:get_player_name(), "# Server: Key does not fit lock!")
  192. ambiance.sound_play("doors_locked", pos, 1.0, 20)
  193. return false
  194. end
  195. elseif owner ~= "" then
  196. if clicker:get_player_name() ~= owner then
  197. ambiance.sound_play("doors_locked", pos, 1.0, 20)
  198. return false
  199. end
  200. end
  201. end
  202. local door_above = _doors.have_matching_door({x=pos.x, y=pos.y + 2, z=pos.z}, node)
  203. local door_below = _doors.have_matching_door({x=pos.x, y=pos.y - 2, z=pos.z}, node)
  204. -- until Lua-5.2 we have no bitwise operators :(
  205. if state % 2 == 1 then
  206. state = state - 1
  207. else
  208. state = state + 1
  209. end
  210. local dir = node.param2
  211. -- Play door open/close sound (check if hinges are oiled, in which case door makes no sound).
  212. local last_oiled = meta:get_int("oiled_time")
  213. if (os.time() - last_oiled) > math.random(0, 60*60*24*7) then
  214. if state % 2 == 0 then
  215. minetest.sound_play(def.door.sounds[1],
  216. {pos = pos, gain = 0.3, max_hear_distance = 20})
  217. else
  218. minetest.sound_play(def.door.sounds[2],
  219. {pos = pos, gain = 0.3, max_hear_distance = 20})
  220. end
  221. end
  222. minetest.swap_node(pos, {
  223. name = name .. transform[state + 1][dir+1].v,
  224. param2 = transform[state + 1][dir+1].param2
  225. })
  226. meta:set_int("state", state)
  227. if door_above then
  228. _doors.door_toggle_force({x=pos.x, y=pos.y + 2, z=pos.z}, node)
  229. end
  230. if door_below then
  231. _doors.door_toggle_force({x=pos.x, y=pos.y - 2, z=pos.z}, node)
  232. end
  233. return true
  234. end
  235. local function on_place_node(place_to, newnode,
  236. placer, oldnode, itemstack, pointed_thing)
  237. -- Run script hook
  238. for _, callback in ipairs(minetest.registered_on_placenodes) do
  239. -- Deepcopy pos, node and pointed_thing because callback can modify them
  240. local place_to_copy = {x = place_to.x, y = place_to.y, z = place_to.z}
  241. local newnode_copy =
  242. {name = newnode.name, param1 = newnode.param1, param2 = newnode.param2}
  243. local oldnode_copy =
  244. {name = oldnode.name, param1 = oldnode.param1, param2 = oldnode.param2}
  245. local pointed_thing_copy = {
  246. type = pointed_thing.type,
  247. above = vector.new(pointed_thing.above),
  248. under = vector.new(pointed_thing.under),
  249. ref = pointed_thing.ref,
  250. }
  251. callback(place_to_copy, newnode_copy, placer,
  252. oldnode_copy, itemstack, pointed_thing_copy)
  253. end
  254. end
  255. local function can_dig_door(pos, digger)
  256. local digger_name = digger and digger:get_player_name()
  257. if digger_name and minetest.get_player_privs(digger_name).protection_bypass then
  258. return true
  259. end
  260. return minetest.get_meta(pos):get_string("doors_owner") == digger_name
  261. end
  262. function doors.register(name, def)
  263. if not name:find(":") then
  264. name = "doors:" .. name
  265. end
  266. local inv_image = def.inventory_image
  267. if def.protected then
  268. inv_image = inv_image .. "^protector_lock.png"
  269. end
  270. minetest.register_craftitem(":" .. name, {
  271. description = def.description,
  272. inventory_image = inv_image,
  273. groups = def.groups,
  274. on_place = function(itemstack, placer, pointed_thing)
  275. local pos
  276. if not pointed_thing.type == "node" then
  277. return itemstack
  278. end
  279. -- Pass through interactions to nodes that define them (like chests).
  280. local node = minetest.get_node(pointed_thing.under)
  281. local pdef = minetest.reg_ns_nodes[node.name]
  282. if pdef and pdef.on_rightclick and not placer:get_player_control().sneak then
  283. return pdef.on_rightclick(pointed_thing.under, node, placer, itemstack, pointed_thing)
  284. end
  285. if pdef and pdef.buildable_to then
  286. pos = pointed_thing.under
  287. else
  288. pos = pointed_thing.above
  289. node = minetest.get_node(pos)
  290. pdef = minetest.reg_ns_nodes[node.name]
  291. if not pdef or not pdef.buildable_to then
  292. return itemstack
  293. end
  294. end
  295. local above = {x = pos.x, y = pos.y + 1, z = pos.z}
  296. local top_node = minetest.get_node_or_nil(above)
  297. local topdef = top_node and minetest.reg_ns_nodes[top_node.name]
  298. if not topdef or not topdef.buildable_to then
  299. return itemstack
  300. end
  301. local pn = placer:get_player_name()
  302. if minetest.is_protected(pos, pn) or minetest.is_protected(above, pn) then
  303. return itemstack
  304. end
  305. local dir = minetest.dir_to_facedir(placer:get_look_dir())
  306. local ref = {
  307. {x = -1, y = 0, z = 0},
  308. {x = 0, y = 0, z = 1},
  309. {x = 1, y = 0, z = 0},
  310. {x = 0, y = 0, z = -1},
  311. }
  312. local aside = {
  313. x = pos.x + ref[dir + 1].x,
  314. y = pos.y + ref[dir + 1].y,
  315. z = pos.z + ref[dir + 1].z,
  316. }
  317. local state = 0
  318. if minetest.get_item_group(minetest.get_node(aside).name, "door") == 1 then
  319. state = state + 2
  320. minetest.add_node(pos, {name = name .. "_b", param2 = dir})
  321. minetest.add_node(above, {name = "doors:hidden", param2 = (dir + 3) % 4})
  322. else
  323. minetest.add_node(pos, {name = name .. "_a", param2 = dir})
  324. minetest.add_node(above, {name = "doors:hidden", param2 = dir})
  325. end
  326. local meta = minetest.get_meta(pos)
  327. meta:set_int("state", state)
  328. if def.protected then
  329. meta:set_string("doors_owner", pn)
  330. local dname = rename.gpn(pn)
  331. meta:set_string("rename", dname)
  332. meta:set_string("infotext", "Locked Door (Owned by <" .. dname .. ">!)")
  333. end
  334. if not minetest.setting_getbool("creative_mode") then
  335. itemstack:take_item()
  336. end
  337. on_place_node(pos, minetest.get_node(pos),
  338. placer, node, itemstack, pointed_thing)
  339. return itemstack
  340. end
  341. })
  342. def.inventory_image = nil
  343. if def.recipe then
  344. minetest.register_craft({
  345. output = name,
  346. recipe = def.recipe,
  347. })
  348. end
  349. def.recipe = nil
  350. if not def.sounds then
  351. def.sounds = default.node_sound_wood_defaults()
  352. end
  353. if not def.sound_open then
  354. def.sound_open = "doors_door_open"
  355. end
  356. if not def.sound_close then
  357. def.sound_close = "doors_door_close"
  358. end
  359. def.groups.not_in_creative_inventory = 1
  360. def.groups.door = 1
  361. def.drop = name
  362. def.door = {
  363. name = name,
  364. sounds = { def.sound_close, def.sound_open },
  365. }
  366. def.on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
  367. _doors.door_toggle(pos, node, clicker)
  368. return itemstack
  369. end
  370. def.after_dig_node = function(pos, node, meta, digger)
  371. minetest.remove_node({x = pos.x, y = pos.y + 1, z = pos.z})
  372. minetest.check_for_falling({x = pos.x, y = pos.y + 1, z = pos.z})
  373. end
  374. def.on_rotate = function(pos, node, user, mode, new_param2)
  375. return false
  376. end
  377. if def.protected then
  378. def.can_dig = can_dig_door
  379. def.on_blast = function() end
  380. def.on_key_use = function(pos, player)
  381. local door = doors.get(pos)
  382. door:toggle(player)
  383. end
  384. def.on_skeleton_key_use = function(pos, player, newsecret)
  385. local meta = minetest.get_meta(pos)
  386. local owner = meta:get_string("doors_owner")
  387. local pname = player:get_player_name()
  388. -- verify placer is owner of lockable door
  389. if not gdac.player_is_admin(pname) then
  390. if owner ~= pname then
  391. minetest.record_protection_violation(pos, pname)
  392. minetest.chat_send_player(pname, "# Server: You do not own this locked door.")
  393. return nil
  394. end
  395. end
  396. local secret = meta:get_string("key_lock_secret")
  397. if secret == "" then
  398. secret = newsecret
  399. meta:set_string("key_lock_secret", secret)
  400. end
  401. return secret, "a locked door", owner
  402. end
  403. -- Called by rename LBM.
  404. def._on_rename_check = function(pos)
  405. local meta = minetest.get_meta(pos)
  406. local owner = meta:get_string("doors_owner")
  407. -- Nobody placed this block.
  408. if owner == "" then
  409. return
  410. end
  411. local dname = rename.gpn(owner)
  412. meta:set_string("rename", dname)
  413. meta:set_string("infotext", "Locked Door (Owned by <" .. dname .. ">!)")
  414. end
  415. -- Disable client dig prediction.
  416. def.node_dig_prediction = ""
  417. else
  418. def.on_blast = function(pos, intensity)
  419. minetest.remove_node(pos)
  420. -- hidden node doesn't get blasted away.
  421. minetest.remove_node({x = pos.x, y = pos.y + 1, z = pos.z})
  422. return {name}
  423. end
  424. end
  425. def.on_destruct = function(pos)
  426. minetest.remove_node({x = pos.x, y = pos.y + 1, z = pos.z})
  427. end
  428. def.drawtype = "mesh"
  429. def.paramtype = "light"
  430. def.paramtype2 = "facedir"
  431. def.sunlight_propagates = true
  432. def.walkable = true
  433. def.is_ground_content = false
  434. def.buildable_to = false
  435. def.selection_box = {type = "fixed", fixed = {-1/2,-1/2,-1/2,1/2,3/2,-6/16}}
  436. def.collision_box = {type = "fixed", fixed = {-1/2,-1/2,-1/2,1/2,3/2,-6/16}}
  437. def.mesh = "door_a.obj"
  438. minetest.register_node(":" .. name .. "_a", def)
  439. def.mesh = "door_b.obj"
  440. minetest.register_node(":" .. name .. "_b", def)
  441. _doors.registered_doors[name .. "_a"] = true
  442. _doors.registered_doors[name .. "_b"] = true
  443. end
  444. -- Capture mods using the old API as best as possible.
  445. function doors.register_door(name, def)
  446. if def.only_placer_can_open then
  447. def.protected = true
  448. end
  449. def.only_placer_can_open = nil
  450. local i = name:find(":")
  451. local modname = name:sub(1, i - 1)
  452. if not def.tiles then
  453. if def.protected then
  454. def.tiles = {{name = "doors_door_steel.png", backface_culling = true}}
  455. else
  456. def.tiles = {{name = "doors_door_wood.png", backface_culling = true}}
  457. end
  458. minetest.log("warning", modname .. " registered door \"" .. name .. "\" " ..
  459. "using deprecated API method \"doors.register_door()\" but " ..
  460. "did not provide the \"tiles\" parameter. A fallback tiledef " ..
  461. "will be used instead.")
  462. end
  463. doors.register(name, def)
  464. end
  465. ----trapdoor----
  466. function _doors.trapdoor_toggle(pos, node, clicker)
  467. node = node or minetest.get_node(pos)
  468. local meta = minetest.get_meta(pos)
  469. if clicker and not minetest.check_player_privs(clicker, "protection_bypass") then
  470. -- is player wielding the right key?
  471. local item = clicker:get_wielded_item()
  472. local owner = meta:get_string("doors_owner")
  473. if item:get_name() == "key:key" or item:get_name() == "key:chain" then
  474. local key_meta = item:get_meta()
  475. local secret = meta:get_string("key_lock_secret")
  476. if key_meta:get_string("secret") == "" then
  477. local key_oldmeta = item:get_metadata()
  478. if key_oldmeta == "" or not minetest.parse_json(key_oldmeta) then
  479. ambiance.sound_play("doors_locked", pos, 1.0, 20)
  480. return false
  481. end
  482. key_meta:set_string("secret", minetest.parse_json(key_oldmeta).secret)
  483. item:set_metadata("")
  484. end
  485. if secret ~= key_meta:get_string("secret") then
  486. minetest.chat_send_player(clicker:get_player_name(), "# Server: Key does not fit lock!")
  487. ambiance.sound_play("doors_locked", pos, 1.0, 20)
  488. return false
  489. end
  490. elseif owner ~= "" then
  491. if clicker:get_player_name() ~= owner then
  492. ambiance.sound_play("doors_locked", pos, 1.0, 20)
  493. return false
  494. end
  495. end
  496. end
  497. local def = minetest.reg_ns_nodes[node.name]
  498. -- Play trapdoor open/close sound (check if hinges are oiled, in which case door makes no sound).
  499. local play_sound = false
  500. local last_oiled = meta:get_int("oiled_time")
  501. if (os.time() - last_oiled) > math.random(0, 60*60*24*7) then
  502. play_sound = true
  503. end
  504. if string.sub(node.name, -5) == "_open" then
  505. if play_sound then
  506. minetest.sound_play(def.sound_close,
  507. {pos = pos, gain = 0.3, max_hear_distance = 20})
  508. end
  509. minetest.swap_node(pos, {name = string.sub(node.name, 1,
  510. string.len(node.name) - 5), param1 = node.param1, param2 = node.param2})
  511. else
  512. if play_sound then
  513. minetest.sound_play(def.sound_open,
  514. {pos = pos, gain = 0.3, max_hear_distance = 20})
  515. end
  516. minetest.swap_node(pos, {name = node.name .. "_open",
  517. param1 = node.param1, param2 = node.param2})
  518. end
  519. end
  520. function doors.register_trapdoor(name, def)
  521. local origname = name
  522. local origdef = table.copy(def)
  523. if not name:find(":") then
  524. name = "doors:" .. name
  525. end
  526. def.groups = def.groups or {}
  527. def.groups.trapdoor = 1
  528. local name_closed = name
  529. local name_opened = name.."_open"
  530. def.on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
  531. _doors.trapdoor_toggle(pos, node, clicker)
  532. return itemstack
  533. end
  534. -- Common trapdoor configuration
  535. def.drawtype = "nodebox"
  536. def.paramtype = "light"
  537. def.paramtype2 = "facedir"
  538. def.is_ground_content = false
  539. if def.protected then
  540. def.can_dig = can_dig_door
  541. def.after_place_node = function(pos, placer, itemstack, pointed_thing)
  542. local pn = placer:get_player_name()
  543. local meta = minetest.get_meta(pos)
  544. meta:set_string("doors_owner", pn)
  545. local dname = rename.gpn(pn)
  546. meta:set_string("rename", dname)
  547. meta:set_string("infotext", "Locked Trapdoor (Owned by <" .. dname .. ">!)")
  548. return minetest.setting_getbool("creative_mode")
  549. end
  550. def.on_blast = function() end
  551. def.on_key_use = function(pos, player)
  552. local door = doors.get(pos)
  553. door:toggle(player)
  554. end
  555. def.on_skeleton_key_use = function(pos, player, newsecret)
  556. local meta = minetest.get_meta(pos)
  557. local owner = meta:get_string("doors_owner")
  558. local pname = player:get_player_name()
  559. -- verify placer is owner of lockable door
  560. if not gdac.player_is_admin(pname) then
  561. if owner ~= pname then
  562. minetest.record_protection_violation(pos, pname)
  563. minetest.chat_send_player(pname, "# Server: You do not own this trapdoor.")
  564. return nil
  565. end
  566. end
  567. local secret = meta:get_string("key_lock_secret")
  568. if secret == "" then
  569. secret = newsecret
  570. meta:set_string("key_lock_secret", secret)
  571. end
  572. return secret, "a locked trapdoor", owner
  573. end
  574. -- Called by rename LBM.
  575. def._on_rename_check = function(pos)
  576. local meta = minetest.get_meta(pos)
  577. local owner = meta:get_string("doors_owner")
  578. -- Nobody placed this block.
  579. if owner == "" then
  580. return
  581. end
  582. local dname = rename.gpn(owner)
  583. meta:set_string("rename", dname)
  584. meta:set_string("infotext", "Locked Trapdoor (Owned by <" .. dname .. ">!)")
  585. end
  586. -- Disable client dig prediction.
  587. def.node_dig_prediction = ""
  588. else
  589. def.on_blast = function(pos, intensity)
  590. minetest.remove_node(pos)
  591. return {name}
  592. end
  593. end
  594. if not def.sounds then
  595. def.sounds = default.node_sound_wood_defaults()
  596. end
  597. if not def.sound_open then
  598. def.sound_open = "doors_door_open"
  599. end
  600. if not def.sound_close then
  601. def.sound_close = "doors_door_close"
  602. end
  603. local def_opened = table.copy(def)
  604. local def_closed = table.copy(def)
  605. def_closed.node_box = {
  606. type = "fixed",
  607. fixed = {-0.5, -0.5, -0.5, 0.5, -6/16, 0.5}
  608. }
  609. def_closed.selection_box = {
  610. type = "fixed",
  611. fixed = {-0.5, -0.5, -0.5, 0.5, -6/16, 0.5}
  612. }
  613. def_closed.tiles = {def.tile_front,
  614. def.tile_front .. '^[transformFY',
  615. def.tile_side, def.tile_side,
  616. def.tile_side, def.tile_side}
  617. def_opened.node_box = {
  618. type = "fixed",
  619. fixed = {-0.5, -0.5, 6/16, 0.5, 0.5, 0.5}
  620. }
  621. def_opened.selection_box = {
  622. type = "fixed",
  623. fixed = {-0.5, -0.5, 6/16, 0.5, 0.5, 0.5}
  624. }
  625. def_opened.tiles = {def.tile_side, def.tile_side,
  626. def.tile_side .. '^[transform3',
  627. def.tile_side .. '^[transform1',
  628. def.tile_front .. '^[transform46',
  629. def.tile_front .. '^[transform6'}
  630. def_opened.drop = name_closed
  631. def_opened.groups.not_in_creative_inventory = 1
  632. if def.protected then
  633. def_closed.inventory_image = def_closed.inventory_image .. "^protector_lock.png"
  634. def_opened.inventory_image = def_opened.inventory_image .. "^protector_lock.png"
  635. end
  636. minetest.register_node(name_opened, def_opened)
  637. minetest.register_node(name_closed, def_closed)
  638. if def.recipeitem then
  639. if def.protected then
  640. minetest.register_craft({
  641. output = name,
  642. recipe = {
  643. {'', 'default:padlock', ''},
  644. {def.recipeitem, def.recipeitem, 'group:stick'},
  645. {def.recipeitem, def.recipeitem, 'group:stick'},
  646. }
  647. })
  648. else
  649. minetest.register_craft({
  650. output = name,
  651. recipe = {
  652. {def.recipeitem, def.recipeitem, 'group:stick'},
  653. {def.recipeitem, def.recipeitem, 'group:stick'},
  654. }
  655. })
  656. end
  657. end
  658. _doors.registered_trapdoors[name_opened] = true
  659. _doors.registered_trapdoors[name_closed] = true
  660. doors.register_trapdoor_climbable("climbable_" .. origname, origdef)
  661. end
  662. function doors.register_trapdoor_climbable(name, def)
  663. if not name:find(":") then
  664. name = "doors:" .. name
  665. end
  666. def.groups = def.groups or {}
  667. def.groups.trapdoor = 1
  668. local name_closed = name
  669. local name_opened = name.."_open"
  670. def.description = def.description .. " With Ladder"
  671. def.on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
  672. _doors.trapdoor_toggle(pos, node, clicker)
  673. return itemstack
  674. end
  675. -- Common trapdoor configuration
  676. def.drawtype = "nodebox"
  677. def.paramtype = "light"
  678. def.paramtype2 = "facedir"
  679. def.climbable = true
  680. def.is_ground_content = false
  681. if def.protected then
  682. def.can_dig = can_dig_door
  683. def.after_place_node = function(pos, placer, itemstack, pointed_thing)
  684. local pn = placer:get_player_name()
  685. local meta = minetest.get_meta(pos)
  686. meta:set_string("doors_owner", pn)
  687. local dname = rename.gpn(pn)
  688. meta:set_string("rename", dname)
  689. meta:set_string("infotext", "Locked Trapdoor (Owned by <" .. dname .. ">!)")
  690. return minetest.setting_getbool("creative_mode")
  691. end
  692. def.on_blast = function() end
  693. def.on_key_use = function(pos, player)
  694. local door = doors.get(pos)
  695. door:toggle(player)
  696. end
  697. def.on_skeleton_key_use = function(pos, player, newsecret)
  698. local meta = minetest.get_meta(pos)
  699. local owner = meta:get_string("doors_owner")
  700. local pname = player:get_player_name()
  701. -- verify placer is owner of lockable door
  702. if not gdac.player_is_admin(pname) then
  703. if owner ~= pname then
  704. minetest.record_protection_violation(pos, pname)
  705. minetest.chat_send_player(pname, "# Server: You do not own this trapdoor.")
  706. return nil
  707. end
  708. end
  709. local secret = meta:get_string("key_lock_secret")
  710. if secret == "" then
  711. secret = newsecret
  712. meta:set_string("key_lock_secret", secret)
  713. end
  714. return secret, "a locked trapdoor", owner
  715. end
  716. -- Called by rename LBM.
  717. def._on_rename_check = function(pos)
  718. local meta = minetest.get_meta(pos)
  719. local owner = meta:get_string("doors_owner")
  720. -- Nobody placed this block.
  721. if owner == "" then
  722. return
  723. end
  724. local dname = rename.gpn(owner)
  725. meta:set_string("rename", dname)
  726. meta:set_string("infotext", "Locked Trapdoor (Owned by <" .. dname .. ">!)")
  727. end
  728. -- Disable client dig prediction.
  729. def.node_dig_prediction = ""
  730. else
  731. def.on_blast = function(pos, intensity)
  732. minetest.remove_node(pos)
  733. return {name}
  734. end
  735. end
  736. if not def.sounds then
  737. def.sounds = default.node_sound_wood_defaults()
  738. end
  739. if not def.sound_open then
  740. def.sound_open = "doors_door_open"
  741. end
  742. if not def.sound_close then
  743. def.sound_close = "doors_door_close"
  744. end
  745. local def_opened = table.copy(def)
  746. local def_closed = table.copy(def)
  747. def_closed.node_box = {
  748. type = "fixed",
  749. fixed = {-0.5, -0.5, -0.5, 0.5, -6/16, 0.5}
  750. }
  751. def_closed.selection_box = {
  752. type = "fixed",
  753. fixed = {-0.5, -0.5, -0.5, 0.5, -6/16, 0.5}
  754. }
  755. def_closed.tiles = {def.tile_front,
  756. def.tile_front .. '^[transformFY',
  757. def.tile_side, def.tile_side,
  758. def.tile_side, def.tile_side}
  759. def_opened.node_box = {
  760. type = "fixed",
  761. fixed = {-0.5, -0.5, 6/16, 0.5, 0.5, 0.5}
  762. }
  763. def_opened.selection_box = {
  764. type = "fixed",
  765. fixed = {-0.5, -0.5, 6/16, 0.5, 0.5, 0.5}
  766. }
  767. def_opened.tiles = {def.tile_side, def.tile_side,
  768. def.tile_side .. '^[transform3',
  769. def.tile_side .. '^[transform1',
  770. def.tile_front .. '^[transform46',
  771. def.tile_front .. '^[transform6'}
  772. def_opened.drop = name_closed
  773. def_opened.groups.not_in_creative_inventory = 1
  774. if def.protected then
  775. def_closed.inventory_image = def_closed.inventory_image .. "^protector_lock.png"
  776. def_opened.inventory_image = def_opened.inventory_image .. "^protector_lock.png"
  777. end
  778. def_closed.inventory_image = def_closed.inventory_image .. "^doors_ladder.png"
  779. def_opened.inventory_image = def_opened.inventory_image .. "^doors_ladder.png"
  780. minetest.register_node(name_opened, def_opened)
  781. minetest.register_node(name_closed, def_closed)
  782. if def.recipeitem then
  783. if def.protected then
  784. minetest.register_craft({
  785. output = name,
  786. recipe = {
  787. {'', 'default:padlock', ''},
  788. {def.recipeitem, def.recipeitem, 'default:ladder_wood'},
  789. {def.recipeitem, def.recipeitem, 'default:ladder_wood'},
  790. }
  791. })
  792. else
  793. minetest.register_craft({
  794. output = name,
  795. recipe = {
  796. {def.recipeitem, def.recipeitem, 'default:ladder_wood'},
  797. {def.recipeitem, def.recipeitem, 'default:ladder_wood'},
  798. }
  799. })
  800. end
  801. end
  802. _doors.registered_trapdoors[name_opened] = true
  803. _doors.registered_trapdoors[name_closed] = true
  804. end
  805. ----fence gate----
  806. function doors.register_fencegate(name, def)
  807. local fence = {
  808. description = def.description,
  809. drawtype = "mesh",
  810. tiles = {def.texture},
  811. paramtype = "light",
  812. paramtype2 = "facedir",
  813. sunlight_propagates = true,
  814. is_ground_content = false,
  815. drop = name .. "_closed",
  816. connect_sides = {"left", "right"},
  817. groups = def.groups,
  818. sounds = def.sounds,
  819. on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
  820. local node_def = minetest.reg_ns_nodes[node.name]
  821. minetest.swap_node(pos, {name = node_def.gate, param2 = node.param2})
  822. minetest.sound_play(node_def.sound, {pos = pos, gain = 0.3,
  823. max_hear_distance = 20})
  824. return itemstack
  825. end,
  826. selection_box = {
  827. type = "fixed",
  828. fixed = {-1/2, -1/2, -1/4, 1/2, 1/2, 1/4},
  829. },
  830. }
  831. if not fence.sounds then
  832. fence.sounds = default.node_sound_wood_defaults()
  833. end
  834. fence.groups.fence = 1
  835. local fence_closed = table.copy(fence)
  836. fence_closed.mesh = "doors_fencegate_closed.obj"
  837. fence_closed.gate = name .. "_open"
  838. fence_closed.sound = "doors_fencegate_open"
  839. fence_closed.collision_box = {
  840. type = "fixed",
  841. fixed = {-1/2, -1/2, -1/4, 1/2, 1/2, 1/4},
  842. }
  843. local fence_open = table.copy(fence)
  844. fence_open.mesh = "doors_fencegate_open.obj"
  845. fence_open.gate = name .. "_closed"
  846. fence_open.sound = "doors_fencegate_close"
  847. fence_open.groups.not_in_creative_inventory = 1
  848. fence_open.collision_box = {
  849. type = "fixed",
  850. fixed = {{-1/2, -1/2, -1/4, -3/8, 1/2, 1/4},
  851. {-1/2, -3/8, -1/2, -3/8, 3/8, 0}},
  852. }
  853. minetest.register_node(":" .. name .. "_closed", fence_closed)
  854. minetest.register_node(":" .. name .. "_open", fence_open)
  855. minetest.register_craft({
  856. output = name .. "_closed",
  857. recipe = {
  858. {"group:stick", def.material, "group:stick"},
  859. {"group:stick", def.material, "group:stick"}
  860. }
  861. })
  862. end
  863. dofile(doors.modpath .. "/doors.lua")
  864. dofile(doors.modpath .. "/trapdoors.lua")
  865. dofile(doors.modpath .. "/gates.lua")