rockdrill.lua 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. rockdrill = rockdrill or {}
  2. rockdrill.modpath = minetest.get_modpath("silicon")
  3. rockdrill.image = "rockdrill_rockdrill.png"
  4. rockdrill.sound = "rockdrill"
  5. rockdrill.name = "rockdrill:rockdrill"
  6. rockdrill.description = "Rock Drill\n\nUses stored energy to blast stone.\nWon't function in protected areas.\nMust be charged to use."
  7. rockdrill.range = 4
  8. -- This is how many nodes the tool can blast.
  9. rockdrill.uses = math.floor(65535/2500)
  10. -- Find all blastable nodes in a small radius.
  11. function rockdrill.find_stone(sp, wear)
  12. local traversal = {}
  13. local queue = {}
  14. local output = {}
  15. local curpos, hash, exists, name, found, norm, cb, depth
  16. local get_node_hash = minetest.hash_node_position
  17. local get_node = minetest.get_node
  18. local is_blastable = rockdrill.is_blastable
  19. local is_protected = minetest.test_protection
  20. queue[#queue+1] = {x=sp.x, y=sp.y, z=sp.z, d=1}
  21. ::continue::
  22. curpos = queue[#queue]
  23. queue[#queue] = nil
  24. depth = curpos.d
  25. curpos.d = nil
  26. hash = get_node_hash(curpos)
  27. exists = false
  28. if traversal[hash] then
  29. exists = true
  30. if depth >= traversal[hash] then
  31. goto next
  32. end
  33. end
  34. if depth >= rockdrill.range then
  35. goto next
  36. end
  37. if wear > math.floor(65535-rockdrill.uses) then
  38. goto next
  39. end
  40. name = get_node(curpos).name
  41. found = false
  42. if is_blastable(name) then
  43. if not is_protected(curpos, "") then
  44. found = true
  45. end
  46. end
  47. if not found then
  48. goto next
  49. end
  50. traversal[hash] = depth
  51. if not exists then
  52. output[#output+1] = vector.new(curpos)
  53. wear = wear + rockdrill.uses
  54. end
  55. queue[#queue+1] = {x=curpos.x+1, y=curpos.y, z=curpos.z, d=depth+1}
  56. queue[#queue+1] = {x=curpos.x-1, y=curpos.y, z=curpos.z, d=depth+1}
  57. queue[#queue+1] = {x=curpos.x, y=curpos.y+1, z=curpos.z, d=depth+1}
  58. queue[#queue+1] = {x=curpos.x, y=curpos.y-1, z=curpos.z, d=depth+1}
  59. queue[#queue+1] = {x=curpos.x, y=curpos.y, z=curpos.z+1, d=depth+1}
  60. queue[#queue+1] = {x=curpos.x, y=curpos.y, z=curpos.z-1, d=depth+1}
  61. ::next::
  62. if #queue > 0 then
  63. goto continue
  64. end
  65. return output, wear
  66. end
  67. function rockdrill.is_blastable(name)
  68. --minetest.chat_send_player("MustTest", "# Server: " .. name .. "!")
  69. -- Air is not blastable, and therefor not obtainable.
  70. if name == "air" then
  71. return
  72. end
  73. -- Check node def.
  74. local def = minetest.reg_ns_nodes[name] or minetest.registered_nodes[name]
  75. if def and def.groups then
  76. local lg = (def.groups.immovable or 0)
  77. local pg = (def.groups.protector or 0)
  78. if lg > 0 or pg > 0 then
  79. return
  80. end
  81. if def.liquidtype ~= "none" then
  82. return
  83. end
  84. end
  85. return true
  86. end
  87. function rockdrill.handle_node_drops(pos, user)
  88. ---[[
  89. local node = minetest.get_node(pos)
  90. if node.name == "air" then
  91. return
  92. end
  93. local def = minetest.registered_nodes[node.name]
  94. if def and def.groups then
  95. local ig = (def.groups.immovable or 0)
  96. if ig > 0 then
  97. return
  98. end
  99. end
  100. local inv = user:get_inventory()
  101. if not inv then
  102. return
  103. end
  104. -- This function takes both nodetables and nodenames.
  105. -- Pass nodenames, because passing a nodetable gives wrong results.
  106. local drops = minetest.get_node_drops(node.name, "")
  107. --minetest.chat_send_player("MustTest", dump(drops))
  108. for _, item in pairs(drops) do
  109. local stack = ItemStack(item) -- Itemstring to itemstack.
  110. local remain = inv:add_item("main", stack)
  111. if not remain:is_empty() then
  112. local p = {
  113. x = pos.x + math.random()/2 - 0.25,
  114. y = pos.y + math.random()/2 - 0.25,
  115. z = pos.z + math.random()/2 - 0.25,
  116. }
  117. minetest.add_item(p, remain)
  118. end
  119. end
  120. minetest.remove_node(pos)
  121. --]]
  122. --_nodeupdate.drop_node_as_entity(pos)
  123. end
  124. function rockdrill.on_use(itemstack, user, pt)
  125. if not user or not user:is_player() then
  126. return
  127. end
  128. if pt.type ~= "node" then
  129. return
  130. end
  131. local wear = itemstack:get_wear()
  132. if wear == 0 then
  133. -- Tool isn't charged!
  134. -- Once it is charged the first time, wear should never be 0 again.
  135. return
  136. end
  137. if wear > math.floor(65535-rockdrill.uses) then
  138. -- Tool has no charge left.
  139. return
  140. end
  141. local under = pt.under
  142. local blasted, newwear = rockdrill.find_stone(under, wear)
  143. if #blasted == 0 then
  144. return
  145. end
  146. ambiance.sound_play(rockdrill.sound, under, 1.0, 40)
  147. for k, v in ipairs(blasted) do
  148. local node = minetest.get_node(v)
  149. --minetest.chat_send_player("MustTest", "# Server: blasting " .. node.name .. " at " .. minetest.pos_to_string(v) .. "!")
  150. local def = minetest.registered_nodes[node.name]
  151. if def and def.on_blast then
  152. -- Behave as if blasted by TNT.
  153. local drops = def.on_blast(v, 1.0)
  154. if drops and type(drops) == "table" then
  155. for k, j in ipairs(drops) do
  156. minetest.add_item(v, j)
  157. end
  158. end
  159. else
  160. -- No on_blast function? Destroy node normally.
  161. rockdrill.handle_node_drops(v, user)
  162. end
  163. minetest.check_for_falling(v)
  164. end
  165. wear = newwear
  166. -- Don't let wear reach max or tool will be destroyed.
  167. if wear >= 65535 then
  168. wear = 65534
  169. end
  170. itemstack:set_wear(wear)
  171. return itemstack
  172. end
  173. if not rockdrill.run_once then
  174. minetest.register_tool(":" .. rockdrill.name, {
  175. description = rockdrill.description,
  176. inventory_image = rockdrill.image,
  177. wear_represents = "eu_charge",
  178. groups = {not_repaired_by_anvil = 1, disable_repair = 1},
  179. on_use = function(...)
  180. return rockdrill.on_use(...)
  181. end,
  182. })
  183. ---[[
  184. minetest.register_craft({
  185. output = rockdrill.name,
  186. recipe = {
  187. {'moreores:tin_ingot', 'gem_cutter:blade', 'moreores:tin_ingot'},
  188. {'stainless_steel:ingot', 'techcrafts:electric_motor', 'stainless_steel:ingot'},
  189. {'', 'default:mese', 'default:copper_ingot'},
  190. }
  191. })
  192. --]]
  193. local c = "rockdrill:core"
  194. local f = rockdrill.modpath .. "/rockdrill.lua"
  195. reload.register_file(c, f, false)
  196. rockdrill.run_once = true
  197. end