chainsaw.lua 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. chainsaw = chainsaw or {}
  2. chainsaw.modpath = minetest.get_modpath("silicon")
  3. -- Localize for performance.
  4. local math_floor = math.floor
  5. chainsaw.image = "chainsaw_chainsaw.png"
  6. chainsaw.sound = "chainsaw"
  7. chainsaw.name = "chainsaw:chainsaw"
  8. chainsaw.description = "Chainsaw\n\nUses stored energy to cut timber.\nWon't function in protected areas.\nMust be charged to use."
  9. chainsaw.range = 6
  10. -- This is how many nodes the chainsaw can cut.
  11. chainsaw.uses = math_floor(65535/1500)
  12. -- Find all timber nodes in a small radius.
  13. function chainsaw.find_timber(sp, wear)
  14. local traversal = {}
  15. local queue = {}
  16. local output = {}
  17. local curpos, hash, exists, name, found, norm, cb, depth
  18. local get_node_hash = minetest.hash_node_position
  19. local get_node = minetest.get_node
  20. local is_timber = chainsaw.is_timber
  21. local is_protected = minetest.test_protection
  22. queue[#queue+1] = {x=sp.x, y=sp.y, z=sp.z, d=1}
  23. ::continue::
  24. curpos = queue[#queue]
  25. queue[#queue] = nil
  26. depth = curpos.d
  27. curpos.d = nil
  28. hash = get_node_hash(curpos)
  29. exists = false
  30. if traversal[hash] then
  31. exists = true
  32. if depth >= traversal[hash] then
  33. goto next
  34. end
  35. end
  36. if depth >= chainsaw.range then
  37. goto next
  38. end
  39. if wear > math_floor(65535-chainsaw.uses) then
  40. goto next
  41. end
  42. name = get_node(curpos).name
  43. found = false
  44. if is_timber(name) then
  45. if not is_protected(curpos, "") then
  46. found = true
  47. end
  48. end
  49. if not found then
  50. goto next
  51. end
  52. traversal[hash] = depth
  53. if not exists then
  54. output[#output+1] = vector.new(curpos)
  55. wear = wear + chainsaw.uses
  56. end
  57. queue[#queue+1] = {x=curpos.x+1, y=curpos.y, z=curpos.z, d=depth+1}
  58. queue[#queue+1] = {x=curpos.x-1, y=curpos.y, z=curpos.z, d=depth+1}
  59. queue[#queue+1] = {x=curpos.x, y=curpos.y+1, z=curpos.z, d=depth+1}
  60. if curpos.y > sp.y then
  61. queue[#queue+1] = {x=curpos.x, y=curpos.y-1, z=curpos.z, d=depth+1}
  62. end
  63. queue[#queue+1] = {x=curpos.x, y=curpos.y, z=curpos.z+1, d=depth+1}
  64. queue[#queue+1] = {x=curpos.x, y=curpos.y, z=curpos.z-1, d=depth+1}
  65. ::next::
  66. if #queue > 0 then
  67. goto continue
  68. end
  69. return output, wear
  70. end
  71. function chainsaw.is_timber(name)
  72. local def = minetest.reg_ns_nodes[name]
  73. if def and def.groups then
  74. local lg = (def.groups.leaves or 0)
  75. if lg > 0 then
  76. return true
  77. end
  78. local tg = (def.groups.tree or 0)
  79. if tg > 0 then
  80. return true
  81. end
  82. end
  83. if name == "default:cactus" then
  84. return true
  85. end
  86. end
  87. function chainsaw.on_use(itemstack, user, pt)
  88. if pt.type ~= "node" then
  89. return
  90. end
  91. local wear = itemstack:get_wear()
  92. if wear == 0 then
  93. -- Tool isn't charged!
  94. -- Once it is charged the first time, wear should never be 0 again.
  95. return
  96. end
  97. if wear > math_floor(65535-chainsaw.uses) then
  98. -- Tool has no charge left.
  99. return
  100. end
  101. local under = pt.under
  102. local timber, newwear = chainsaw.find_timber(under, wear)
  103. if #timber == 0 then
  104. return
  105. end
  106. ambiance.sound_play(chainsaw.sound, under, 1.0, 40)
  107. for k, v in ipairs(timber) do
  108. _nodeupdate.drop_node_as_entity(v)
  109. minetest.check_for_falling(v)
  110. end
  111. wear = newwear
  112. -- Don't let wear reach max or tool will be destroyed.
  113. if wear >= 65535 then
  114. wear = 65534
  115. end
  116. itemstack:set_wear(wear)
  117. return itemstack
  118. end
  119. if not chainsaw.run_once then
  120. minetest.register_tool(":" .. chainsaw.name, {
  121. description = chainsaw.description,
  122. inventory_image = chainsaw.image,
  123. wear_represents = "eu_charge",
  124. groups = {not_repaired_by_anvil = 1, disable_repair = 1},
  125. on_use = function(...)
  126. return chainsaw.on_use(...)
  127. end,
  128. })
  129. ---[[
  130. minetest.register_craft({
  131. output = chainsaw.name,
  132. recipe = {
  133. {"stainless_steel:ingot", "default:mese_crystal_fragment", "battery:battery"},
  134. {"fine_wire:copper", "techcrafts:electric_motor", "battery:battery"},
  135. {"", "", "stainless_steel:ingot"},
  136. }
  137. })
  138. --]]
  139. local c = "chainsaw:core"
  140. local f = chainsaw.modpath .. "/chainsaw.lua"
  141. reload.register_file(c, f, false)
  142. chainsaw.run_once = true
  143. end