tool.lua 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. -- protector placement tool (thanks to Shara for code and idea)
  2. local get_public_time = function()
  3. return os.date("!%Y/%m/%d UTC")
  4. end
  5. minetest.register_craftitem("protector:tool", {
  6. description = "Claim Expansion Tool\n\nStand near protector, face direction and use.\nHold sneak to copy member names.\nHold 'E' to double the gap distance.",
  7. inventory_image = "nodeinspector.png^protector_lock.png",
  8. stack_max = 1,
  9. on_use = function(itemstack, user, pointed_thing)
  10. local name = user:get_player_name()
  11. -- check for protector near player (2 block radius)
  12. local pos = vector.round(user:get_pos())
  13. local pp = minetest.find_nodes_in_area(
  14. vector.subtract(pos, 2), vector.add(pos, 2),
  15. {"protector:protect", "protector:protect2",
  16. "protector:protect3", "protector:protect4"})
  17. if #pp == 0 then return end -- none found
  18. if #pp > 1 then
  19. minetest.chat_send_player(name, "# Server: Too many protectors nearby, choice would be ambiguous.")
  20. return
  21. end
  22. pos = pp[1] -- take position of first protector found
  23. -- get type of protector, its radius and size class
  24. local r -- Protector radius
  25. local s -- Small protector: true, else false
  26. local node = minetest.get_node(pos)
  27. local protname
  28. if node.name == "protector:protect" or node.name == "protector:protect2" then
  29. r = protector.radius
  30. s = false
  31. protname = node.name
  32. elseif node.name == "protector:protect3" or node.name == "protector:protect4" then
  33. r = protector.radius_small
  34. s = true
  35. protname = node.name
  36. else
  37. minetest.chat_send_player(name, "# Server: PPT internal error!")
  38. return
  39. end
  40. -- get members on protector
  41. local meta = minetest.get_meta(pos)
  42. local members = meta:get_string("members") or ""
  43. local owner = meta:get_string("owner") or ""
  44. -- require the tool user to be the owner of the initial protector node
  45. if owner ~= name then
  46. minetest.chat_send_player(name, "# Server: Cannot expand claim from origin, the protector is not yours!")
  47. return
  48. end
  49. -- get direction player is facing
  50. local dir = minetest.dir_to_facedir( user:get_look_dir() )
  51. local vec = {x = 0, y = 0, z = 0}
  52. local gap = (r * 2) + 1
  53. local pit = user:get_look_vertical()
  54. -- double the gap distance if player is holding 'E'
  55. if user:get_player_control().aux1 then
  56. gap = gap * 2
  57. end
  58. -- set placement coords
  59. if pit > 1.2 then
  60. vec.y = -gap -- up
  61. elseif pit < -1.2 then
  62. vec.y = gap -- down
  63. elseif dir == 0 then
  64. vec.z = gap -- north
  65. elseif dir == 1 then
  66. vec.x = gap -- east
  67. elseif dir == 2 then
  68. vec.z = -gap -- south
  69. elseif dir == 3 then
  70. vec.x = -gap -- west
  71. end
  72. -- new position
  73. pos.x = pos.x + vec.x
  74. pos.y = pos.y + vec.y
  75. pos.z = pos.z + vec.z
  76. -- ensure position is within a valid realm
  77. if not rc.is_valid_realm_pos(pos) then
  78. minetest.chat_send_player(name, "# Server: Cannot place protector in the Void!")
  79. return
  80. end
  81. if not minetest.get_node_or_nil(pos) then
  82. minetest.chat_send_player(name, "# Server: Cannot place protector within IGNORE!")
  83. return
  84. end
  85. -- does placing a protector overlap existing area
  86. -- this is the most important check! must not mess this up!
  87. local success, reason = protector.check_overlap_main(protname, name, pos)
  88. if not success then
  89. if reason == 1 then
  90. minetest.chat_send_player(name, "# Server: Protection bounds overlap into another person's area claim.")
  91. elseif reason == 2 then
  92. minetest.chat_send_player(name, "# Server: You cannot claim this area while someone's fresh corpse is nearby!")
  93. elseif reason == 3 then
  94. minetest.chat_send_player(name, "# Server: You must remove all corpses before you can claim this area.")
  95. else
  96. minetest.chat_send_player(name, "# Server: Cannot place protection for unknown reason.")
  97. end
  98. return
  99. end
  100. -- does a protector already exist ?
  101. if #minetest.find_nodes_in_area(vector.subtract(pos, 1), vector.add(pos, 1),
  102. {"protector:protect", "protector:protect2", "protector:protect3", "protector:protect4"}) > 0 then
  103. minetest.chat_send_player(name, "# Server: Protector already in place!")
  104. return
  105. end
  106. -- do not replace containers with inventory space
  107. if minetest.get_inventory({type = "node", pos = pos}) then
  108. minetest.chat_send_player(name, "# Server: Cannot place protector, container at " .. rc.pos_to_namestr(pos) .. ".")
  109. return
  110. end
  111. -- protection check for other stuff, like bedrock, etc
  112. if minetest.is_protected(pos, name) then
  113. minetest.chat_send_player(name, "Cannot place protector, already protected at " .. rc.pos_to_namestr(pos) .. ".")
  114. return
  115. end
  116. -- check not replacing an immovable object
  117. local node = minetest.get_node(pos)
  118. if minetest.get_item_group(node.name, "immovable") ~= 0 then
  119. minetest.chat_send_player(name, "# Server: Cannot place protector in place of immovable object!")
  120. return
  121. end
  122. local nod
  123. local inv = user:get_inventory()
  124. -- try to take protector from player inventory (block first then logo)
  125. if s then
  126. if inv:contains_item("main", "protector:protect3") then
  127. inv:remove_item("main", "protector:protect3")
  128. nod = "protector:protect3"
  129. elseif inv:contains_item("main", "protector:protect4") then
  130. inv:remove_item("main", "protector:protect4")
  131. nod = "protector:protect4"
  132. end
  133. else
  134. if inv:contains_item("main", "protector:protect") then
  135. inv:remove_item("main", "protector:protect")
  136. nod = "protector:protect"
  137. elseif inv:contains_item("main", "protector:protect2") then
  138. inv:remove_item("main", "protector:protect2")
  139. nod = "protector:protect2"
  140. end
  141. end
  142. -- did we get a protector to use ?
  143. if not nod then
  144. if s then
  145. minetest.chat_send_player(name, "# Server: No basic protectors available to place!")
  146. else
  147. minetest.chat_send_player(name, "# Server: No advanced protectors available to place!")
  148. end
  149. return
  150. end
  151. -- place protector
  152. minetest.set_node(pos, {name = nod, param2 = 1})
  153. -- set protector metadata
  154. local meta = minetest.get_meta(pos)
  155. local dname = rename.gpn(name)
  156. local placedate = get_public_time()
  157. meta:set_string("placedate", placedate)
  158. meta:set_string("owner", name)
  159. meta:set_string("rename", dname)
  160. meta:set_string("infotext", "Protection (Owned by <" .. dname .. ">!)\nPlaced on " .. placedate)
  161. -- copy members across if holding sneak when using tool
  162. local members_copied = false
  163. if user:get_player_control().sneak then
  164. meta:set_string("members", members)
  165. members_copied = true
  166. else
  167. meta:set_string("members", "")
  168. end
  169. -- Notify nearby players.
  170. protector.update_nearby_players(pos)
  171. ambiance.sound_play(electric_screwdriver.sound, pos, electric_screwdriver.sound_gain, electric_screwdriver.sound_dist)
  172. if members_copied and not s then
  173. minetest.chat_send_player(name, "# Server: Protector placed at " .. rc.pos_to_namestr(pos) .. ". Members copied.")
  174. else
  175. minetest.chat_send_player(name, "# Server: Protector placed at " .. rc.pos_to_namestr(pos) .. ".")
  176. end
  177. end,
  178. })
  179. -- tool recipe
  180. minetest.register_craft({
  181. output = "protector:tool",
  182. recipe = {
  183. {"protector:protect4"},
  184. {"nodeinspector:nodeinspector"},
  185. }
  186. })